@mgsoftwarebv/mg-dashboard-mcp 2.3.3 → 2.3.4
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/dist/index.js +253 -449
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -375,404 +375,6 @@ ${rawJson.substring(0, 500)}`
|
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
-
// src/script-tools.ts
|
|
379
|
-
var SCRIPTS = [
|
|
380
|
-
{
|
|
381
|
-
name: "commit-feedback",
|
|
382
|
-
filename: "commit-feedback.ps1",
|
|
383
|
-
description: "PowerShell script that provides colored terminal feedback for the Ctrl+Shift+K commit & push keybinding. Polls for a new commit and shows branch, message, and file stats when done.",
|
|
384
|
-
content: `param()
|
|
385
|
-
|
|
386
|
-
$initial = git log --oneline -1 2>$null
|
|
387
|
-
|
|
388
|
-
Write-Host "\`n==========================================" -ForegroundColor Cyan
|
|
389
|
-
Write-Host " Starting Commit & Push..." -ForegroundColor Cyan
|
|
390
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
391
|
-
Write-Host " [1/5] Pulling latest..." -ForegroundColor DarkGray
|
|
392
|
-
Write-Host " [2/5] Staging changes..." -ForegroundColor DarkGray
|
|
393
|
-
Write-Host " [3/5] Generating AI commit message..." -ForegroundColor DarkGray
|
|
394
|
-
Write-Host " [4/5] Committing..." -ForegroundColor DarkGray
|
|
395
|
-
Write-Host " [5/5] Pushing to remote..." -ForegroundColor DarkGray
|
|
396
|
-
Write-Host ""
|
|
397
|
-
Write-Host " Waiting for commit" -ForegroundColor DarkGray -NoNewline
|
|
398
|
-
|
|
399
|
-
$timeout = 60
|
|
400
|
-
$elapsed = 0
|
|
401
|
-
while ($elapsed -lt $timeout) {
|
|
402
|
-
$current = git log --oneline -1 2>$null
|
|
403
|
-
if ($current -ne $initial) { break }
|
|
404
|
-
Start-Sleep -Seconds 1
|
|
405
|
-
$elapsed++
|
|
406
|
-
Write-Host "." -ForegroundColor DarkGray -NoNewline
|
|
407
|
-
}
|
|
408
|
-
Write-Host ""
|
|
409
|
-
|
|
410
|
-
if ($current -eq $initial) {
|
|
411
|
-
Write-Host ""
|
|
412
|
-
Write-Host " [!] No new commit detected (timed out after \${timeout}s)" -ForegroundColor Yellow
|
|
413
|
-
Write-Host ""
|
|
414
|
-
exit
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
Start-Sleep -Seconds 2
|
|
418
|
-
|
|
419
|
-
$branch = git rev-parse --abbrev-ref HEAD 2>$null
|
|
420
|
-
$commit = git log --format='%h %s' -1 2>$null
|
|
421
|
-
|
|
422
|
-
Write-Host ""
|
|
423
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
424
|
-
Write-Host " [OK] Commit & Push Complete" -ForegroundColor Green
|
|
425
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
426
|
-
Write-Host " Branch: $branch" -ForegroundColor Yellow
|
|
427
|
-
Write-Host " Commit: $commit" -ForegroundColor White
|
|
428
|
-
Write-Host ""
|
|
429
|
-
git --no-pager diff HEAD~1 --stat --color=always 2>$null
|
|
430
|
-
Write-Host ""
|
|
431
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
432
|
-
Write-Host ""
|
|
433
|
-
`
|
|
434
|
-
},
|
|
435
|
-
{
|
|
436
|
-
name: "create-pr",
|
|
437
|
-
filename: "create-pr.cmd",
|
|
438
|
-
description: "Windows batch script that auto-detects the target branch based on your release pipeline (v*-changes branches), merges the target into your branch, pushes, and creates a PR via gh CLI. Bound to Ctrl+Shift+J.",
|
|
439
|
-
content: `@echo off
|
|
440
|
-
setlocal enabledelayedexpansion
|
|
441
|
-
title MG Dashboard - Create PR
|
|
442
|
-
|
|
443
|
-
REM --- ANSI color setup ---
|
|
444
|
-
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
|
|
445
|
-
set "GREEN=%ESC%[32m"
|
|
446
|
-
set "RED=%ESC%[31m"
|
|
447
|
-
set "YELLOW=%ESC%[33m"
|
|
448
|
-
set "CYAN=%ESC%[36m"
|
|
449
|
-
set "DIM=%ESC%[90m"
|
|
450
|
-
set "BOLD=%ESC%[1m"
|
|
451
|
-
set "RESET=%ESC%[0m"
|
|
452
|
-
|
|
453
|
-
echo.
|
|
454
|
-
echo %CYAN%%BOLD%==========================================%RESET%
|
|
455
|
-
echo %CYAN%%BOLD% MG Dashboard - Create Pull Request%RESET%
|
|
456
|
-
echo %CYAN%%BOLD%==========================================%RESET%
|
|
457
|
-
echo.
|
|
458
|
-
|
|
459
|
-
REM --- Merge origin/main first ---
|
|
460
|
-
echo %CYAN%[0/4]%RESET% Merging origin/main into current branch...
|
|
461
|
-
git fetch --prune >nul 2>&1
|
|
462
|
-
git merge origin/main --no-edit >nul 2>&1
|
|
463
|
-
if errorlevel 1 (
|
|
464
|
-
git merge --abort >nul 2>&1
|
|
465
|
-
echo %RED%X Merge conflict with origin/main. Resolve manually.%RESET%
|
|
466
|
-
echo.
|
|
467
|
-
exit /b 1
|
|
468
|
-
)
|
|
469
|
-
echo %GREEN% OK%RESET%
|
|
470
|
-
echo.
|
|
471
|
-
|
|
472
|
-
REM --- Prerequisite: gh CLI ---
|
|
473
|
-
where gh >nul 2>&1
|
|
474
|
-
if errorlevel 1 (
|
|
475
|
-
echo %RED%X GitHub CLI ^(gh^) is not installed.%RESET%
|
|
476
|
-
echo %DIM% Install it from: https://cli.github.com/%RESET%
|
|
477
|
-
echo.
|
|
478
|
-
exit /b 1
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
REM --- Prerequisite: git repo ---
|
|
482
|
-
git rev-parse --is-inside-work-tree >nul 2>&1
|
|
483
|
-
if errorlevel 1 (
|
|
484
|
-
echo %RED%X Not inside a git repository.%RESET%
|
|
485
|
-
echo.
|
|
486
|
-
exit /b 1
|
|
487
|
-
)
|
|
488
|
-
|
|
489
|
-
REM --- Detect repo from git remote ---
|
|
490
|
-
set "REPO="
|
|
491
|
-
for /f "tokens=*" %%u in ('git remote get-url origin 2^>nul') do set "REMOTE_URL=%%u"
|
|
492
|
-
if defined REMOTE_URL (
|
|
493
|
-
echo !REMOTE_URL! | findstr /r "git@github.com:" >nul 2>&1
|
|
494
|
-
if not errorlevel 1 (
|
|
495
|
-
set "REPO=!REMOTE_URL:git@github.com:=!"
|
|
496
|
-
set "REPO=!REPO:.git=!"
|
|
497
|
-
)
|
|
498
|
-
echo !REMOTE_URL! | findstr /r "https://github.com/" >nul 2>&1
|
|
499
|
-
if not errorlevel 1 (
|
|
500
|
-
set "REPO=!REMOTE_URL:https://github.com/=!"
|
|
501
|
-
set "REPO=!REPO:.git=!"
|
|
502
|
-
)
|
|
503
|
-
)
|
|
504
|
-
if not defined REPO (
|
|
505
|
-
echo %RED%X Could not detect GitHub repo from git remote.%RESET%
|
|
506
|
-
echo %DIM% Make sure origin points to a GitHub repository.%RESET%
|
|
507
|
-
echo.
|
|
508
|
-
exit /b 1
|
|
509
|
-
)
|
|
510
|
-
|
|
511
|
-
REM --- Get current branch ---
|
|
512
|
-
for /f "tokens=*" %%b in ('git rev-parse --abbrev-ref HEAD') do set "CURRENT_BRANCH=%%b"
|
|
513
|
-
|
|
514
|
-
echo %DIM% Repository: !REPO!%RESET%
|
|
515
|
-
echo %DIM% Branch: %CURRENT_BRANCH%%RESET%
|
|
516
|
-
echo.
|
|
517
|
-
|
|
518
|
-
REM --- Guard: don't PR from main or a bare version branch ---
|
|
519
|
-
if "%CURRENT_BRANCH%"=="main" (
|
|
520
|
-
echo %RED%X You are on main. Switch to a feature or changes branch first.%RESET%
|
|
521
|
-
echo.
|
|
522
|
-
exit /b 1
|
|
523
|
-
)
|
|
524
|
-
echo %CURRENT_BRANCH% | findstr /r "^v[0-9]*\\.[0-9]*\\.[0-9]*$" >nul 2>&1
|
|
525
|
-
if not errorlevel 1 (
|
|
526
|
-
echo %RED%X You are on a version branch ^(%CURRENT_BRANCH%^). Switch to a feature or changes branch first.%RESET%
|
|
527
|
-
echo.
|
|
528
|
-
exit /b 1
|
|
529
|
-
)
|
|
530
|
-
|
|
531
|
-
REM --- Fetch latest remote refs ---
|
|
532
|
-
echo %CYAN%[1/4]%RESET% Fetching remote branches...
|
|
533
|
-
git fetch --prune >nul 2>&1
|
|
534
|
-
|
|
535
|
-
REM --- Determine target branch ---
|
|
536
|
-
set "TARGET="
|
|
537
|
-
|
|
538
|
-
REM Check if current branch is a -changes branch (last 8 chars)
|
|
539
|
-
if "!CURRENT_BRANCH:~-8!"=="-changes" (
|
|
540
|
-
set "TARGET=!CURRENT_BRANCH:~0,-8!"
|
|
541
|
-
echo %GREEN% Detected -changes branch. Target: %BOLD%!TARGET!%RESET%
|
|
542
|
-
goto :do_merge
|
|
543
|
-
)
|
|
544
|
-
|
|
545
|
-
REM Look for v*-changes branches on remote (highest version first)
|
|
546
|
-
set "TARGET="
|
|
547
|
-
for /f "tokens=*" %%r in ('git branch -r --sort=-version:refname --list "origin/v*-changes" 2^>nul') do (
|
|
548
|
-
if not defined TARGET (
|
|
549
|
-
set "RAW=%%r"
|
|
550
|
-
set "BRANCH=!RAW: origin/=!"
|
|
551
|
-
set "BRANCH=!BRANCH:origin/=!"
|
|
552
|
-
set "TARGET=!BRANCH!"
|
|
553
|
-
)
|
|
554
|
-
)
|
|
555
|
-
|
|
556
|
-
if defined TARGET (
|
|
557
|
-
echo %GREEN% Release pipeline detected. Target: %BOLD%!TARGET!%RESET%
|
|
558
|
-
) else (
|
|
559
|
-
REM No -changes branch; try highest version branch
|
|
560
|
-
set "TARGET="
|
|
561
|
-
for /f "tokens=*" %%r in ('git branch -r --sort=-version:refname --list "origin/v*" 2^>nul') do (
|
|
562
|
-
if not defined TARGET (
|
|
563
|
-
set "RAW=%%r"
|
|
564
|
-
set "BRANCH=!RAW: origin/=!"
|
|
565
|
-
set "BRANCH=!BRANCH:origin/=!"
|
|
566
|
-
set "TAIL=!BRANCH:~-8!"
|
|
567
|
-
if not "!TAIL!"=="-changes" set "TARGET=!BRANCH!"
|
|
568
|
-
)
|
|
569
|
-
)
|
|
570
|
-
if defined TARGET (
|
|
571
|
-
echo %GREEN% Version branch detected. Target: %BOLD%!TARGET!%RESET%
|
|
572
|
-
) else (
|
|
573
|
-
set "TARGET=main"
|
|
574
|
-
echo %YELLOW% No release pipeline or version branch found. Target: %BOLD%main%RESET%
|
|
575
|
-
)
|
|
576
|
-
)
|
|
577
|
-
|
|
578
|
-
:do_merge
|
|
579
|
-
echo.
|
|
580
|
-
|
|
581
|
-
REM --- Merge target into current branch ---
|
|
582
|
-
echo %CYAN%[2/4]%RESET% Merging %BOLD%!TARGET!%RESET% into %BOLD%%CURRENT_BRANCH%%RESET%...
|
|
583
|
-
git merge origin/!TARGET! --no-edit
|
|
584
|
-
if errorlevel 1 (
|
|
585
|
-
echo.
|
|
586
|
-
echo %RED%X Merge conflict detected.%RESET%
|
|
587
|
-
git merge --abort >nul 2>&1
|
|
588
|
-
echo %DIM% Resolve conflicts manually, then retry.%RESET%
|
|
589
|
-
echo.
|
|
590
|
-
exit /b 1
|
|
591
|
-
)
|
|
592
|
-
echo %GREEN% OK%RESET%
|
|
593
|
-
echo.
|
|
594
|
-
|
|
595
|
-
REM --- Push current branch to origin ---
|
|
596
|
-
echo %CYAN%[3/4]%RESET% Pushing %CURRENT_BRANCH% to origin...
|
|
597
|
-
git push -u origin HEAD
|
|
598
|
-
if errorlevel 1 (
|
|
599
|
-
echo.
|
|
600
|
-
echo %RED%X Failed to push branch to origin.%RESET%
|
|
601
|
-
echo.
|
|
602
|
-
exit /b 1
|
|
603
|
-
)
|
|
604
|
-
echo %GREEN% OK%RESET%
|
|
605
|
-
echo.
|
|
606
|
-
|
|
607
|
-
REM --- Guard: don't PR into the same branch ---
|
|
608
|
-
if "!TARGET!"=="!CURRENT_BRANCH!" (
|
|
609
|
-
echo %RED%X Target branch is the same as current branch ^(!TARGET!^). Cannot create PR.%RESET%
|
|
610
|
-
echo.
|
|
611
|
-
exit /b 1
|
|
612
|
-
)
|
|
613
|
-
|
|
614
|
-
echo %CYAN%[4/4]%RESET% Creating PR: %BOLD%%CURRENT_BRANCH%%RESET% %DIM%->%RESET% %BOLD%%TARGET%%RESET%
|
|
615
|
-
echo.
|
|
616
|
-
|
|
617
|
-
REM --- Create the PR ---
|
|
618
|
-
gh pr create --repo "!REPO!" --base "%TARGET%" --fill
|
|
619
|
-
if errorlevel 1 (
|
|
620
|
-
echo.
|
|
621
|
-
echo %RED%X Failed to create pull request.%RESET%
|
|
622
|
-
echo %DIM% Check the error above. A PR may already exist for this branch.%RESET%
|
|
623
|
-
echo.
|
|
624
|
-
exit /b 1
|
|
625
|
-
)
|
|
626
|
-
|
|
627
|
-
echo.
|
|
628
|
-
echo %GREEN%%BOLD% PR created successfully!%RESET%
|
|
629
|
-
echo.
|
|
630
|
-
`
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
name: "commit-and-pr",
|
|
634
|
-
filename: "commit-and-pr.ps1",
|
|
635
|
-
description: "PowerShell script that combines commit & push with PR creation. Checks for pending changes first: if changes exist, waits for the commit (triggered by Cursor keybinding), shows a summary, then runs create-pr.cmd. If no changes, skips straight to PR. Requires create-pr.cmd in the same directory. Bound to Ctrl+Shift+M.",
|
|
636
|
-
content: `param()
|
|
637
|
-
|
|
638
|
-
$hasChanges = (git status --porcelain 2>$null)
|
|
639
|
-
|
|
640
|
-
if ($hasChanges) {
|
|
641
|
-
$initial = git log --oneline -1 2>$null
|
|
642
|
-
|
|
643
|
-
Write-Host "\`n==========================================" -ForegroundColor Cyan
|
|
644
|
-
Write-Host " Starting Commit, Push & PR..." -ForegroundColor Cyan
|
|
645
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
646
|
-
Write-Host " [1/5] Pulling latest..." -ForegroundColor DarkGray
|
|
647
|
-
Write-Host " [2/5] Staging changes..." -ForegroundColor DarkGray
|
|
648
|
-
Write-Host " [3/5] Generating AI commit message..." -ForegroundColor DarkGray
|
|
649
|
-
Write-Host " [4/5] Committing..." -ForegroundColor DarkGray
|
|
650
|
-
Write-Host " [5/5] Pushing to remote..." -ForegroundColor DarkGray
|
|
651
|
-
Write-Host ""
|
|
652
|
-
Write-Host " Waiting for commit" -ForegroundColor DarkGray -NoNewline
|
|
653
|
-
|
|
654
|
-
$timeout = 60
|
|
655
|
-
$elapsed = 0
|
|
656
|
-
while ($elapsed -lt $timeout) {
|
|
657
|
-
$current = git log --oneline -1 2>$null
|
|
658
|
-
if ($current -ne $initial) { break }
|
|
659
|
-
Start-Sleep -Seconds 1
|
|
660
|
-
$elapsed++
|
|
661
|
-
Write-Host "." -ForegroundColor DarkGray -NoNewline
|
|
662
|
-
}
|
|
663
|
-
Write-Host ""
|
|
664
|
-
|
|
665
|
-
if ($current -eq $initial) {
|
|
666
|
-
Write-Host ""
|
|
667
|
-
Write-Host " [!] No new commit detected (timed out after \${timeout}s)" -ForegroundColor Yellow
|
|
668
|
-
Write-Host " Skipping PR creation." -ForegroundColor Yellow
|
|
669
|
-
Write-Host ""
|
|
670
|
-
exit
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
Start-Sleep -Seconds 2
|
|
674
|
-
|
|
675
|
-
$branch = git rev-parse --abbrev-ref HEAD 2>$null
|
|
676
|
-
$commit = git log --format='%h %s' -1 2>$null
|
|
677
|
-
|
|
678
|
-
Write-Host ""
|
|
679
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
680
|
-
Write-Host " [OK] Commit & Push Complete" -ForegroundColor Green
|
|
681
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
682
|
-
Write-Host " Branch: $branch" -ForegroundColor Yellow
|
|
683
|
-
Write-Host " Commit: $commit" -ForegroundColor White
|
|
684
|
-
Write-Host ""
|
|
685
|
-
git --no-pager diff HEAD~1 --stat --color=always 2>$null
|
|
686
|
-
Write-Host ""
|
|
687
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
688
|
-
Write-Host ""
|
|
689
|
-
} else {
|
|
690
|
-
Write-Host "\`n==========================================" -ForegroundColor Cyan
|
|
691
|
-
Write-Host " No changes to commit" -ForegroundColor DarkGray
|
|
692
|
-
Write-Host " Proceeding to PR creation..." -ForegroundColor Cyan
|
|
693
|
-
Write-Host "==========================================" -ForegroundColor Cyan
|
|
694
|
-
Write-Host ""
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
& .\\create-pr.cmd
|
|
698
|
-
`
|
|
699
|
-
}
|
|
700
|
-
];
|
|
701
|
-
var SCRIPT_TOOLS = [
|
|
702
|
-
{
|
|
703
|
-
name: "scripts-list",
|
|
704
|
-
description: "List available MG Dashboard workflow scripts that can be downloaded into your project. Returns script names, filenames, and descriptions.",
|
|
705
|
-
inputSchema: { type: "object", properties: {}, required: [] }
|
|
706
|
-
},
|
|
707
|
-
{
|
|
708
|
-
name: "script-get",
|
|
709
|
-
description: "Get the content of an MG Dashboard workflow script by name. Save the returned content to the filename indicated in the response. Place scripts in the repository root.",
|
|
710
|
-
inputSchema: {
|
|
711
|
-
type: "object",
|
|
712
|
-
properties: {
|
|
713
|
-
name: {
|
|
714
|
-
type: "string",
|
|
715
|
-
description: `Script name. Available: ${SCRIPTS.map((s) => s.name).join(", ")}`
|
|
716
|
-
}
|
|
717
|
-
},
|
|
718
|
-
required: ["name"]
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
];
|
|
722
|
-
var SCRIPT_TOOL_NAMES = new Set(SCRIPT_TOOLS.map((t) => t.name));
|
|
723
|
-
function handleScriptTool(toolName, args2) {
|
|
724
|
-
switch (toolName) {
|
|
725
|
-
case "scripts-list": {
|
|
726
|
-
const list = SCRIPTS.map((s) => ({
|
|
727
|
-
name: s.name,
|
|
728
|
-
filename: s.filename,
|
|
729
|
-
description: s.description
|
|
730
|
-
}));
|
|
731
|
-
return {
|
|
732
|
-
content: [
|
|
733
|
-
{
|
|
734
|
-
type: "text",
|
|
735
|
-
text: JSON.stringify(list, null, 2)
|
|
736
|
-
}
|
|
737
|
-
]
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
case "script-get": {
|
|
741
|
-
const scriptName = String(args2.name);
|
|
742
|
-
const script = SCRIPTS.find((s) => s.name === scriptName);
|
|
743
|
-
if (!script) {
|
|
744
|
-
const available = SCRIPTS.map((s) => s.name).join(", ");
|
|
745
|
-
return {
|
|
746
|
-
content: [
|
|
747
|
-
{
|
|
748
|
-
type: "text",
|
|
749
|
-
text: `Unknown script: "${scriptName}". Available scripts: ${available}`
|
|
750
|
-
}
|
|
751
|
-
]
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
return {
|
|
755
|
-
content: [
|
|
756
|
-
{
|
|
757
|
-
type: "text",
|
|
758
|
-
text: [
|
|
759
|
-
`Filename: ${script.filename}`,
|
|
760
|
-
`Description: ${script.description}`,
|
|
761
|
-
`Place this file in the repository root.`,
|
|
762
|
-
"",
|
|
763
|
-
"--- CONTENT START ---",
|
|
764
|
-
script.content,
|
|
765
|
-
"--- CONTENT END ---"
|
|
766
|
-
].join("\n")
|
|
767
|
-
}
|
|
768
|
-
]
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
|
-
default:
|
|
772
|
-
return { content: [{ type: "text", text: `Unknown script tool: ${toolName}` }] };
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
378
|
// src/agent-tools.ts
|
|
777
379
|
var VALID_FINDING_TYPES = /* @__PURE__ */ new Set([
|
|
778
380
|
"missing_docs",
|
|
@@ -794,13 +396,15 @@ var VALID_SCOPES = /* @__PURE__ */ new Set([
|
|
|
794
396
|
"module",
|
|
795
397
|
"component",
|
|
796
398
|
"api",
|
|
797
|
-
"package"
|
|
399
|
+
"package",
|
|
400
|
+
"security",
|
|
401
|
+
"server_audit"
|
|
798
402
|
]);
|
|
799
403
|
var VALID_REVIEW_STATUSES = /* @__PURE__ */ new Set([
|
|
800
404
|
"pending",
|
|
801
|
-
"
|
|
802
|
-
"
|
|
803
|
-
"
|
|
405
|
+
"agent_approved",
|
|
406
|
+
"agent_flagged",
|
|
407
|
+
"human_approved"
|
|
804
408
|
]);
|
|
805
409
|
var AGENT_TOOLS = [
|
|
806
410
|
{
|
|
@@ -908,10 +512,10 @@ var AGENT_TOOLS = [
|
|
|
908
512
|
},
|
|
909
513
|
path: {
|
|
910
514
|
type: "string",
|
|
911
|
-
description: 'Path within the repo (e.g. "packages/ui"
|
|
515
|
+
description: 'Path within the repo (e.g. "packages/ui")'
|
|
912
516
|
},
|
|
913
517
|
title: { type: "string", description: "Document title" },
|
|
914
|
-
content: { type: "string", description: "Documentation content (
|
|
518
|
+
content: { type: "string", description: "Documentation content (Typst markup)" },
|
|
915
519
|
review_status: {
|
|
916
520
|
type: "string",
|
|
917
521
|
enum: [...VALID_REVIEW_STATUSES],
|
|
@@ -940,7 +544,7 @@ var AGENT_TOOLS = [
|
|
|
940
544
|
},
|
|
941
545
|
status: {
|
|
942
546
|
type: "string",
|
|
943
|
-
enum: ["open", "
|
|
547
|
+
enum: ["open", "ticket_created", "resolved", "dismissed"],
|
|
944
548
|
description: "Filter by status (default: all)"
|
|
945
549
|
},
|
|
946
550
|
limit: {
|
|
@@ -971,6 +575,56 @@ var AGENT_TOOLS = [
|
|
|
971
575
|
},
|
|
972
576
|
required: ["repo_slug"]
|
|
973
577
|
}
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
name: "agent-validate-suggestions",
|
|
581
|
+
description: "Validate existing open suggestions against the actual codebase. For each suggestion, report whether it is valid, invalid (should be dismissed), or needs adjustment. Invalid suggestions are auto-dismissed with a reason.",
|
|
582
|
+
inputSchema: {
|
|
583
|
+
type: "object",
|
|
584
|
+
properties: {
|
|
585
|
+
repo_slug: {
|
|
586
|
+
type: "string",
|
|
587
|
+
description: "Repository slug being validated"
|
|
588
|
+
},
|
|
589
|
+
results: {
|
|
590
|
+
type: "array",
|
|
591
|
+
description: "Validation results per suggestion",
|
|
592
|
+
items: {
|
|
593
|
+
type: "object",
|
|
594
|
+
properties: {
|
|
595
|
+
suggestion_id: {
|
|
596
|
+
type: "string",
|
|
597
|
+
description: "UUID of the doc_suggestion being validated"
|
|
598
|
+
},
|
|
599
|
+
verdict: {
|
|
600
|
+
type: "string",
|
|
601
|
+
enum: ["valid", "invalid", "adjusted"],
|
|
602
|
+
description: "Validation verdict: valid (keep as-is), invalid (dismiss), adjusted (update fields)"
|
|
603
|
+
},
|
|
604
|
+
reason: {
|
|
605
|
+
type: "string",
|
|
606
|
+
description: "Explanation of why this suggestion is valid/invalid/adjusted (max 2000 chars)"
|
|
607
|
+
},
|
|
608
|
+
adjusted_description: {
|
|
609
|
+
type: "string",
|
|
610
|
+
description: "Updated description (only for verdict=adjusted, max 2000 chars)"
|
|
611
|
+
},
|
|
612
|
+
adjusted_severity: {
|
|
613
|
+
type: "string",
|
|
614
|
+
enum: ["info", "warning", "critical"],
|
|
615
|
+
description: "Updated severity (only for verdict=adjusted)"
|
|
616
|
+
},
|
|
617
|
+
adjusted_suggested_fix: {
|
|
618
|
+
type: "string",
|
|
619
|
+
description: "Updated suggested fix (only for verdict=adjusted, max 5000 chars)"
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
required: ["suggestion_id", "verdict", "reason"]
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
required: ["repo_slug", "results"]
|
|
627
|
+
}
|
|
974
628
|
}
|
|
975
629
|
];
|
|
976
630
|
var AGENT_TOOL_NAMES = new Set(AGENT_TOOLS.map((t) => t.name));
|
|
@@ -979,7 +633,8 @@ var AGENT_TOOL_MODULE_MAP = {
|
|
|
979
633
|
"agent-report-finding": "agent_reporting",
|
|
980
634
|
"agent-save-documentation": "agent_reporting",
|
|
981
635
|
"agent-list-findings": "agent_reporting",
|
|
982
|
-
"agent-get-documentation": "agent_reporting"
|
|
636
|
+
"agent-get-documentation": "agent_reporting",
|
|
637
|
+
"agent-validate-suggestions": "agent_reporting"
|
|
983
638
|
};
|
|
984
639
|
function clamp(val, min, max) {
|
|
985
640
|
return Math.max(min, Math.min(max, val));
|
|
@@ -987,25 +642,24 @@ function clamp(val, min, max) {
|
|
|
987
642
|
function sanitizeString(val, maxLen) {
|
|
988
643
|
return String(val ?? "").slice(0, maxLen);
|
|
989
644
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
const
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
return inserted.id;
|
|
645
|
+
function textSimilarity(a, b) {
|
|
646
|
+
if (a === b) return 1;
|
|
647
|
+
const norm = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
|
|
648
|
+
const na = norm(a);
|
|
649
|
+
const nb = norm(b);
|
|
650
|
+
if (na === nb) return 1;
|
|
651
|
+
if (na.length < 3 || nb.length < 3) return na === nb ? 1 : 0;
|
|
652
|
+
const trigrams = (s) => {
|
|
653
|
+
const set = /* @__PURE__ */ new Set();
|
|
654
|
+
for (let i = 0; i <= s.length - 3; i++) set.add(s.slice(i, i + 3));
|
|
655
|
+
return set;
|
|
656
|
+
};
|
|
657
|
+
const setA = trigrams(na);
|
|
658
|
+
const setB = trigrams(nb);
|
|
659
|
+
let intersection = 0;
|
|
660
|
+
for (const t of setA) if (setB.has(t)) intersection++;
|
|
661
|
+
const union = setA.size + setB.size - intersection;
|
|
662
|
+
return union === 0 ? 0 : intersection / union;
|
|
1009
663
|
}
|
|
1010
664
|
async function handleAgentTool(name, args2, deps) {
|
|
1011
665
|
const { supabase: supabase2 } = deps;
|
|
@@ -1061,30 +715,90 @@ async function handleAgentTool(name, args2, deps) {
|
|
|
1061
715
|
throw new Error('category must be "scan_findings" or "perf_audit"');
|
|
1062
716
|
}
|
|
1063
717
|
if (findings.length === 0) throw new Error("findings array must not be empty");
|
|
1064
|
-
const
|
|
718
|
+
const SIMILARITY_THRESHOLD = 0.55;
|
|
719
|
+
const MAX_OPEN_PER_TYPE = 30;
|
|
720
|
+
const { data: existingFindings } = await supabase2.from("doc_suggestion").select("id, type, description, file_path, severity, category, status").eq("repo_slug", repoSlug).in("status", ["open", "dismissed"]).limit(500);
|
|
721
|
+
const existing = existingFindings ?? [];
|
|
722
|
+
const typeCountMap = /* @__PURE__ */ new Map();
|
|
723
|
+
for (const e of existing) {
|
|
724
|
+
if (e.status !== "open") continue;
|
|
725
|
+
const key = `${e.category}:${e.type}`;
|
|
726
|
+
typeCountMap.set(key, (typeCountMap.get(key) ?? 0) + 1);
|
|
727
|
+
}
|
|
1065
728
|
let inserted = 0;
|
|
729
|
+
let deduplicated = 0;
|
|
730
|
+
let grouped = 0;
|
|
1066
731
|
let errors = 0;
|
|
732
|
+
const overflowBucket = /* @__PURE__ */ new Map();
|
|
1067
733
|
for (const f of findings) {
|
|
1068
734
|
const findingType = VALID_FINDING_TYPES.has(f.type) ? f.type : "improvement";
|
|
1069
735
|
const severity = VALID_SEVERITIES.has(f.severity) ? f.severity : "info";
|
|
1070
736
|
const description = sanitizeString(f.description, 2e3);
|
|
737
|
+
const filePath = f.file_path ? sanitizeString(f.file_path, 500) : null;
|
|
1071
738
|
if (!description) continue;
|
|
739
|
+
const isDuplicate = existing.some((e) => {
|
|
740
|
+
if (e.type !== findingType) return false;
|
|
741
|
+
if (filePath && e.file_path === filePath) {
|
|
742
|
+
return textSimilarity(e.description ?? "", description) > 0.4;
|
|
743
|
+
}
|
|
744
|
+
return textSimilarity(e.description ?? "", description) > SIMILARITY_THRESHOLD;
|
|
745
|
+
});
|
|
746
|
+
if (isDuplicate) {
|
|
747
|
+
deduplicated++;
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
const typeKey = `${category}:${findingType}`;
|
|
751
|
+
const currentCount = typeCountMap.get(typeKey) ?? 0;
|
|
752
|
+
if (currentCount >= MAX_OPEN_PER_TYPE) {
|
|
753
|
+
const bucket = overflowBucket.get(typeKey) ?? [];
|
|
754
|
+
bucket.push(`${filePath ? `${filePath}: ` : ""}${description.slice(0, 120)}`);
|
|
755
|
+
overflowBucket.set(typeKey, bucket);
|
|
756
|
+
grouped++;
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
1072
759
|
const { error } = await supabase2.from("doc_suggestion").insert({
|
|
1073
|
-
|
|
760
|
+
repo_slug: repoSlug,
|
|
761
|
+
refront_project_id: refrontProjectId,
|
|
762
|
+
category,
|
|
1074
763
|
type: findingType,
|
|
1075
764
|
severity,
|
|
1076
765
|
description,
|
|
1077
|
-
file_path:
|
|
766
|
+
file_path: filePath,
|
|
1078
767
|
suggested_fix: f.suggested_fix ? sanitizeString(f.suggested_fix, 5e3) : null,
|
|
1079
768
|
status: "open"
|
|
1080
769
|
});
|
|
1081
|
-
if (error)
|
|
1082
|
-
|
|
770
|
+
if (error) {
|
|
771
|
+
errors++;
|
|
772
|
+
} else {
|
|
773
|
+
inserted++;
|
|
774
|
+
typeCountMap.set(typeKey, currentCount + 1);
|
|
775
|
+
existing.push({ id: "", type: findingType, description, file_path: filePath, severity, category, status: "open" });
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
for (const [typeKey, items] of overflowBucket) {
|
|
779
|
+
const [cat, type] = typeKey.split(":");
|
|
780
|
+
const summary = `Gegroepeerd (${items.length} items):
|
|
781
|
+
${items.map((i) => `\u2022 ${i}`).join("\n")}`;
|
|
782
|
+
await supabase2.from("doc_suggestion").insert({
|
|
783
|
+
repo_slug: repoSlug,
|
|
784
|
+
refront_project_id: refrontProjectId,
|
|
785
|
+
category: cat,
|
|
786
|
+
type,
|
|
787
|
+
severity: "info",
|
|
788
|
+
description: summary.slice(0, 5e3),
|
|
789
|
+
file_path: null,
|
|
790
|
+
suggested_fix: null,
|
|
791
|
+
status: "open"
|
|
792
|
+
});
|
|
1083
793
|
}
|
|
794
|
+
const parts = [`${inserted} inserted`];
|
|
795
|
+
if (deduplicated > 0) parts.push(`${deduplicated} deduplicated`);
|
|
796
|
+
if (grouped > 0) parts.push(`${grouped} grouped into ${overflowBucket.size} summary row(s)`);
|
|
797
|
+
if (errors > 0) parts.push(`${errors} errors`);
|
|
1084
798
|
return {
|
|
1085
799
|
content: [{
|
|
1086
800
|
type: "text",
|
|
1087
|
-
text: `Findings reported
|
|
801
|
+
text: `Findings reported under ${category}: ${parts.join(", ")}`
|
|
1088
802
|
}]
|
|
1089
803
|
};
|
|
1090
804
|
}
|
|
@@ -1108,10 +822,12 @@ async function handleAgentTool(name, args2, deps) {
|
|
|
1108
822
|
title,
|
|
1109
823
|
content,
|
|
1110
824
|
review_status: reviewStatus,
|
|
825
|
+
pdf_storage_path: null,
|
|
826
|
+
pdf_compiled_at: null,
|
|
1111
827
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1112
828
|
}).eq("id", existing.id);
|
|
1113
829
|
if (error2) throw new Error(`Failed to update documentation: ${error2.message}`);
|
|
1114
|
-
return { content: [{ type: "text", text: `Documentation updated: ${title} (${scope}/${path})
|
|
830
|
+
return { content: [{ type: "text", text: `Documentation updated: ${title} (${scope}/${path}). PDF compilation pending.` }] };
|
|
1115
831
|
}
|
|
1116
832
|
const generatedBy = deps.workspaceId ? `agent-${deps.workspaceId.slice(0, 8)}` : "agent-mcp";
|
|
1117
833
|
const { error } = await supabase2.from("project_documentation").insert({
|
|
@@ -1122,22 +838,19 @@ async function handleAgentTool(name, args2, deps) {
|
|
|
1122
838
|
title,
|
|
1123
839
|
content,
|
|
1124
840
|
generated_by: generatedBy,
|
|
1125
|
-
review_status: reviewStatus
|
|
841
|
+
review_status: reviewStatus,
|
|
842
|
+
pdf_storage_path: null,
|
|
843
|
+
pdf_compiled_at: null
|
|
1126
844
|
});
|
|
1127
845
|
if (error) throw new Error(`Failed to save documentation: ${error.message}`);
|
|
1128
|
-
return { content: [{ type: "text", text: `Documentation saved: ${title} (${scope}/${path})
|
|
846
|
+
return { content: [{ type: "text", text: `Documentation saved: ${title} (${scope}/${path}). PDF compilation pending.` }] };
|
|
1129
847
|
}
|
|
1130
848
|
// -----------------------------------------------------------------
|
|
1131
849
|
case "agent-list-findings": {
|
|
1132
850
|
const repoSlug = sanitizeString(args2.repo_slug, 200);
|
|
1133
851
|
if (!repoSlug) throw new Error("repo_slug is required");
|
|
1134
852
|
const limit = clamp(Number(args2.limit) || 50, 1, 200);
|
|
1135
|
-
let
|
|
1136
|
-
const docIds = await docQuery;
|
|
1137
|
-
if (!docIds.data || docIds.data.length === 0) {
|
|
1138
|
-
return { content: [{ type: "text", text: `No documentation records found for repo "${repoSlug}"` }] };
|
|
1139
|
-
}
|
|
1140
|
-
let query = supabase2.from("doc_suggestion").select("id, type, severity, description, file_path, status, created_at").in("documentation_id", docIds.data.map((d) => d.id)).order("created_at", { ascending: false }).limit(limit);
|
|
853
|
+
let query = supabase2.from("doc_suggestion").select("id, type, severity, description, file_path, status, category, created_at").eq("repo_slug", repoSlug).order("created_at", { ascending: false }).limit(limit);
|
|
1141
854
|
if (args2.type && VALID_FINDING_TYPES.has(args2.type)) {
|
|
1142
855
|
query = query.eq("type", args2.type);
|
|
1143
856
|
}
|
|
@@ -1199,6 +912,70 @@ ${output}` }]
|
|
|
1199
912
|
};
|
|
1200
913
|
}
|
|
1201
914
|
// -----------------------------------------------------------------
|
|
915
|
+
case "agent-validate-suggestions": {
|
|
916
|
+
const repoSlug = sanitizeString(args2.repo_slug, 200);
|
|
917
|
+
const results = Array.isArray(args2.results) ? args2.results : [];
|
|
918
|
+
if (!repoSlug) throw new Error("repo_slug is required");
|
|
919
|
+
if (results.length === 0) throw new Error("results array must not be empty");
|
|
920
|
+
const validatedBy = deps.workspaceId ? `validator-${deps.workspaceId.slice(0, 8)}` : "validator-mcp";
|
|
921
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
922
|
+
let dismissed = 0;
|
|
923
|
+
let adjusted = 0;
|
|
924
|
+
let validated = 0;
|
|
925
|
+
let errors = 0;
|
|
926
|
+
for (const r of results) {
|
|
927
|
+
const id = sanitizeString(r.suggestion_id, 100);
|
|
928
|
+
const verdict = r.verdict;
|
|
929
|
+
const reason = sanitizeString(r.reason, 2e3);
|
|
930
|
+
if (!id || !["valid", "invalid", "adjusted"].includes(verdict)) {
|
|
931
|
+
errors++;
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
if (verdict === "invalid") {
|
|
935
|
+
const { error } = await supabase2.from("doc_suggestion").update({
|
|
936
|
+
status: "dismissed",
|
|
937
|
+
dismissed_reason: reason || "Dismissed by validation agent",
|
|
938
|
+
validated_at: now,
|
|
939
|
+
validated_by: validatedBy
|
|
940
|
+
}).eq("id", id).eq("repo_slug", repoSlug);
|
|
941
|
+
if (error) errors++;
|
|
942
|
+
else dismissed++;
|
|
943
|
+
} else if (verdict === "adjusted") {
|
|
944
|
+
const updates = {
|
|
945
|
+
validated_at: now,
|
|
946
|
+
validated_by: validatedBy
|
|
947
|
+
};
|
|
948
|
+
if (r.adjusted_description) {
|
|
949
|
+
updates.description = sanitizeString(r.adjusted_description, 2e3);
|
|
950
|
+
}
|
|
951
|
+
if (r.adjusted_severity && VALID_SEVERITIES.has(r.adjusted_severity)) {
|
|
952
|
+
updates.severity = r.adjusted_severity;
|
|
953
|
+
}
|
|
954
|
+
if (r.adjusted_suggested_fix) {
|
|
955
|
+
updates.suggested_fix = sanitizeString(r.adjusted_suggested_fix, 5e3);
|
|
956
|
+
}
|
|
957
|
+
const { error } = await supabase2.from("doc_suggestion").update(updates).eq("id", id).eq("repo_slug", repoSlug);
|
|
958
|
+
if (error) errors++;
|
|
959
|
+
else adjusted++;
|
|
960
|
+
} else {
|
|
961
|
+
const { error } = await supabase2.from("doc_suggestion").update({ validated_at: now, validated_by: validatedBy }).eq("id", id).eq("repo_slug", repoSlug);
|
|
962
|
+
if (error) errors++;
|
|
963
|
+
else validated++;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
const parts = [];
|
|
967
|
+
if (validated > 0) parts.push(`${validated} valid`);
|
|
968
|
+
if (dismissed > 0) parts.push(`${dismissed} dismissed`);
|
|
969
|
+
if (adjusted > 0) parts.push(`${adjusted} adjusted`);
|
|
970
|
+
if (errors > 0) parts.push(`${errors} errors`);
|
|
971
|
+
return {
|
|
972
|
+
content: [{
|
|
973
|
+
type: "text",
|
|
974
|
+
text: `Validation complete for "${repoSlug}": ${parts.join(", ")}`
|
|
975
|
+
}]
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
// -----------------------------------------------------------------
|
|
1202
979
|
default:
|
|
1203
980
|
return { content: [{ type: "text", text: `Unknown agent tool: ${name}` }] };
|
|
1204
981
|
}
|
|
@@ -1336,6 +1113,7 @@ var TOOL_MODULE_MAP = {
|
|
|
1336
1113
|
"env-store": "ci_cd",
|
|
1337
1114
|
"domain-list": "domains",
|
|
1338
1115
|
"domain-get": "domains",
|
|
1116
|
+
"domain-update-ns": "domains",
|
|
1339
1117
|
"dns-list": "domains",
|
|
1340
1118
|
"dns-create": "domains",
|
|
1341
1119
|
"dns-update": "domains",
|
|
@@ -1570,7 +1348,7 @@ async function attemptVercelSync(appName, environment, knownStageId) {
|
|
|
1570
1348
|
const envVars = keys.map((key) => ({
|
|
1571
1349
|
key,
|
|
1572
1350
|
value: pairs[key],
|
|
1573
|
-
type: "
|
|
1351
|
+
type: "encrypted",
|
|
1574
1352
|
...targeting
|
|
1575
1353
|
}));
|
|
1576
1354
|
const { created, error } = await syncEnvVarsToVercel(token, app.vercelProjectId, envVars);
|
|
@@ -2366,7 +2144,7 @@ var TOOLS = [
|
|
|
2366
2144
|
type: "object",
|
|
2367
2145
|
properties: {
|
|
2368
2146
|
appName: { type: "string", description: "Application name (e.g. backoffice, api, web)" },
|
|
2369
|
-
environment: { type: "string",
|
|
2147
|
+
environment: { type: "string", enum: ["production", "staging", "development", "local"], description: "Environment name" },
|
|
2370
2148
|
releaseProfile: { type: "string", description: "Release profile name (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Required when multiple profiles exist. Use env-list to discover available profiles." }
|
|
2371
2149
|
},
|
|
2372
2150
|
required: ["appName", "environment"]
|
|
@@ -2379,7 +2157,7 @@ var TOOLS = [
|
|
|
2379
2157
|
type: "object",
|
|
2380
2158
|
properties: {
|
|
2381
2159
|
appName: { type: "string", description: "Application name (e.g. backoffice, api, web)" },
|
|
2382
|
-
environment: { type: "string",
|
|
2160
|
+
environment: { type: "string", enum: ["production", "staging", "development", "local"], description: "Environment name" },
|
|
2383
2161
|
content: { type: "string", description: "The .env file content to store" },
|
|
2384
2162
|
description: { type: "string", description: "Optional description" },
|
|
2385
2163
|
releaseProfile: { type: "string", description: "Release profile name (usually matches the project folder name or git repo name, e.g. prefabaanbouw). Required when multiple profiles exist. Use env-list to discover available profiles." }
|
|
@@ -2415,6 +2193,18 @@ var TOOLS = [
|
|
|
2415
2193
|
required: ["domain"]
|
|
2416
2194
|
}
|
|
2417
2195
|
},
|
|
2196
|
+
{
|
|
2197
|
+
name: "domain-update-ns",
|
|
2198
|
+
description: 'Update nameservers for a domain. Use alias "default-mijnhost" to reset to mijn.host defaults. Pushes the change to the domain registry.',
|
|
2199
|
+
inputSchema: {
|
|
2200
|
+
type: "object",
|
|
2201
|
+
properties: {
|
|
2202
|
+
domain: { type: "string", description: "Domain name (e.g. example.com)" },
|
|
2203
|
+
nameserver: { type: "string", description: 'Nameserver profile alias (e.g. "default-mijnhost")' }
|
|
2204
|
+
},
|
|
2205
|
+
required: ["domain", "nameserver"]
|
|
2206
|
+
}
|
|
2207
|
+
},
|
|
2418
2208
|
{
|
|
2419
2209
|
name: "dns-list",
|
|
2420
2210
|
description: "List all DNS records for a domain. Returns type (A, AAAA, CNAME, MX, TXT, etc.), name, value, and TTL for each record.",
|
|
@@ -2473,8 +2263,6 @@ var TOOLS = [
|
|
|
2473
2263
|
},
|
|
2474
2264
|
// ----- Trigger.dev -----
|
|
2475
2265
|
...TRIGGER_TOOLS,
|
|
2476
|
-
// ----- Scripts -----
|
|
2477
|
-
...SCRIPT_TOOLS,
|
|
2478
2266
|
// ----- Agent Reporting -----
|
|
2479
2267
|
...AGENT_TOOLS
|
|
2480
2268
|
];
|
|
@@ -2823,6 +2611,24 @@ ${lines.join("\n")}` }] };
|
|
|
2823
2611
|
}
|
|
2824
2612
|
return { content: [{ type: "text", text: sections.join("\n") }] };
|
|
2825
2613
|
}
|
|
2614
|
+
case "domain-update-ns": {
|
|
2615
|
+
const domain = String(a.domain);
|
|
2616
|
+
const nameserver = String(a.nameserver);
|
|
2617
|
+
if (!domain || !nameserver) throw new Error("domain and nameserver are required");
|
|
2618
|
+
await mijnhostFetch(`/domains/${encodeURIComponent(domain)}`, {
|
|
2619
|
+
method: "PUT",
|
|
2620
|
+
body: JSON.stringify({ nameserver })
|
|
2621
|
+
});
|
|
2622
|
+
const verify = await mijnhostFetch(`/domains/${encodeURIComponent(domain)}`);
|
|
2623
|
+
const ns = verify.data.nameservers;
|
|
2624
|
+
return {
|
|
2625
|
+
content: [{
|
|
2626
|
+
type: "text",
|
|
2627
|
+
text: `Nameservers for ${domain} updated to profile "${nameserver}".
|
|
2628
|
+
Current nameservers: ${ns.join(", ")}`
|
|
2629
|
+
}]
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2826
2632
|
case "dns-list": {
|
|
2827
2633
|
const domain = String(a.domain);
|
|
2828
2634
|
if (!domain) throw new Error("domain is required");
|
|
@@ -2924,9 +2730,6 @@ ${lines.join("\n")}` }] };
|
|
|
2924
2730
|
if (TRIGGER_TOOL_NAMES.has(name)) {
|
|
2925
2731
|
return handleTriggerTool(name, a, { sshExec, getServerConnection });
|
|
2926
2732
|
}
|
|
2927
|
-
if (SCRIPT_TOOL_NAMES.has(name)) {
|
|
2928
|
-
return handleScriptTool(name, a);
|
|
2929
|
-
}
|
|
2930
2733
|
if (AGENT_TOOL_NAMES.has(name)) {
|
|
2931
2734
|
return handleAgentTool(name, a, { supabase, workspaceId: agentWorkspaceId });
|
|
2932
2735
|
}
|
|
@@ -2963,7 +2766,8 @@ async function main() {
|
|
|
2963
2766
|
"/api/report-finding": "agent-report-finding",
|
|
2964
2767
|
"/api/save-documentation": "agent-save-documentation",
|
|
2965
2768
|
"/api/list-findings": "agent-list-findings",
|
|
2966
|
-
"/api/get-documentation": "agent-get-documentation"
|
|
2769
|
+
"/api/get-documentation": "agent-get-documentation",
|
|
2770
|
+
"/api/validate-suggestions": "agent-validate-suggestions"
|
|
2967
2771
|
};
|
|
2968
2772
|
const httpServer = createServer(async (req, res) => {
|
|
2969
2773
|
const url = new URL(req.url ?? "/", `http://localhost:${httpPort}`);
|