@datasynx/agentic-ai-cartography 0.1.9 → 0.2.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.
- package/dist/bookmarks-O7KNR7D3.js +8 -0
- package/dist/bookmarks-O7KNR7D3.js.map +1 -0
- package/dist/chunk-EVJP2FWQ.js +118 -0
- package/dist/chunk-EVJP2FWQ.js.map +1 -0
- package/dist/chunk-GUZXO6PM.js +647 -0
- package/dist/chunk-GUZXO6PM.js.map +1 -0
- package/dist/chunk-JAFRT2R6.js +97 -0
- package/dist/chunk-JAFRT2R6.js.map +1 -0
- package/dist/cli.js +898 -724
- package/dist/cli.js.map +1 -1
- package/dist/exporter-BDVDYA3K.js +24 -0
- package/dist/exporter-BDVDYA3K.js.map +1 -0
- package/dist/index.d.ts +16 -3
- package/dist/index.js +538 -11
- package/dist/index.js.map +1 -1
- package/dist/types-NKF6BRMZ.js +26 -0
- package/dist/types-NKF6BRMZ.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -385,6 +385,24 @@ var CartographyDB = class {
|
|
|
385
385
|
confidence: r["confidence"]
|
|
386
386
|
}));
|
|
387
387
|
}
|
|
388
|
+
markTaskAsSOPCandidate(taskId) {
|
|
389
|
+
this.db.prepare("UPDATE tasks SET is_sop_candidate = 1 WHERE id = ?").run(taskId);
|
|
390
|
+
}
|
|
391
|
+
getAllSOPs() {
|
|
392
|
+
const rows = this.db.prepare("SELECT * FROM sops ORDER BY generated_at DESC").all();
|
|
393
|
+
return rows.map((r) => ({
|
|
394
|
+
id: r["id"],
|
|
395
|
+
workflowId: r["workflow_id"],
|
|
396
|
+
title: r["title"],
|
|
397
|
+
description: r["description"],
|
|
398
|
+
steps: JSON.parse(r["steps"]),
|
|
399
|
+
involvedSystems: JSON.parse(r["involved_systems"]),
|
|
400
|
+
estimatedDuration: r["estimated_duration"],
|
|
401
|
+
frequency: r["frequency"],
|
|
402
|
+
confidence: r["confidence"],
|
|
403
|
+
generatedAt: r["generated_at"]
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
388
406
|
// ── Approvals ───────────────────────────
|
|
389
407
|
setApproval(pattern, action) {
|
|
390
408
|
this.db.prepare(`
|
|
@@ -735,6 +753,292 @@ async function createCartographyTools(db, sessionId, opts = {}) {
|
|
|
735
753
|
}]
|
|
736
754
|
};
|
|
737
755
|
}),
|
|
756
|
+
tool("scan_k8s_resources", "Kubernetes-Cluster via kubectl scannen \u2014 100% readonly (get, describe)", {
|
|
757
|
+
namespace: z2.string().optional().describe("Namespace filtern \u2014 leer = alle Namespaces")
|
|
758
|
+
}, async (args) => {
|
|
759
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
760
|
+
const ns = args["namespace"];
|
|
761
|
+
const nsFlag = ns ? `-n ${ns}` : "--all-namespaces";
|
|
762
|
+
const run = (cmd) => {
|
|
763
|
+
try {
|
|
764
|
+
return execSync2(cmd, { stdio: "pipe", timeout: 15e3, shell: "/bin/sh" }).toString().trim();
|
|
765
|
+
} catch (e) {
|
|
766
|
+
return `(error: ${e instanceof Error ? e.message.split("\n")[0] : String(e)})`;
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
const sections = [
|
|
770
|
+
["CONTEXT", 'kubectl config current-context 2>/dev/null || echo "(kein Context gesetzt)"'],
|
|
771
|
+
["NODES", "kubectl get nodes -o wide"],
|
|
772
|
+
["NAMESPACES", "kubectl get namespaces"],
|
|
773
|
+
["SERVICES", `kubectl get services ${nsFlag}`],
|
|
774
|
+
["DEPLOYMENTS", `kubectl get deployments ${nsFlag}`],
|
|
775
|
+
["STATEFULSETS", `kubectl get statefulsets ${nsFlag}`],
|
|
776
|
+
["INGRESSES", `kubectl get ingress ${nsFlag} 2>/dev/null || echo "(keine)"`],
|
|
777
|
+
["PODS_RUNNING", `kubectl get pods ${nsFlag} --field-selector=status.phase=Running 2>/dev/null | head -60`],
|
|
778
|
+
["CONFIGMAPS_SYSTEM", "kubectl get configmaps -n kube-system 2>/dev/null | head -30"]
|
|
779
|
+
];
|
|
780
|
+
const out = sections.map(([l, c]) => `=== ${l} ===
|
|
781
|
+
${run(c)}`).join("\n\n");
|
|
782
|
+
return { content: [{ type: "text", text: out }] };
|
|
783
|
+
}),
|
|
784
|
+
tool("scan_aws_resources", "AWS-Infrastruktur via AWS CLI scannen \u2014 100% readonly (describe, list)", {
|
|
785
|
+
region: z2.string().optional().describe("AWS Region \u2014 default: AWS_DEFAULT_REGION oder Profil"),
|
|
786
|
+
profile: z2.string().optional().describe("AWS CLI Profil")
|
|
787
|
+
}, async (args) => {
|
|
788
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
789
|
+
const region = args["region"];
|
|
790
|
+
const profile = args["profile"];
|
|
791
|
+
const env = { ...process.env };
|
|
792
|
+
if (region) env["AWS_DEFAULT_REGION"] = region;
|
|
793
|
+
const pf = profile ? `--profile ${profile}` : "";
|
|
794
|
+
const run = (cmd) => {
|
|
795
|
+
try {
|
|
796
|
+
return execSync2(cmd, { stdio: "pipe", timeout: 2e4, shell: "/bin/sh", env }).toString().trim();
|
|
797
|
+
} catch (e) {
|
|
798
|
+
return `(error: ${e instanceof Error ? e.message.split("\n")[0] : String(e)})`;
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
const sections = [
|
|
802
|
+
["IDENTITY", `aws sts get-caller-identity ${pf} --output json`],
|
|
803
|
+
["EC2", `aws ec2 describe-instances ${pf} --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,State.Name,PublicIpAddress,PrivateIpAddress,Tags[?Key==\`Name\`].Value|[0]]' --output table`],
|
|
804
|
+
["RDS", `aws rds describe-db-instances ${pf} --query 'DBInstances[*].[DBInstanceIdentifier,Engine,DBInstanceStatus,Endpoint.Address,Endpoint.Port]' --output table`],
|
|
805
|
+
["ELB_V2", `aws elbv2 describe-load-balancers ${pf} --query 'LoadBalancers[*].[LoadBalancerName,DNSName,Type,State.Code]' --output table`],
|
|
806
|
+
["EKS", `aws eks list-clusters ${pf} --output json`],
|
|
807
|
+
["ELASTICACHE", `aws elasticache describe-cache-clusters ${pf} --query 'CacheClusters[*].[CacheClusterId,Engine,CacheClusterStatus]' --output table 2>/dev/null || echo "(nicht verf\xFCgbar)"`],
|
|
808
|
+
["S3", `aws s3 ls ${pf} 2>/dev/null || echo "(nicht verf\xFCgbar)"`],
|
|
809
|
+
["VPC", `aws ec2 describe-vpcs ${pf} --query 'Vpcs[*].[VpcId,CidrBlock,IsDefault,Tags[?Key==\`Name\`].Value|[0]]' --output table`]
|
|
810
|
+
];
|
|
811
|
+
const out = sections.map(([l, c]) => `=== ${l} ===
|
|
812
|
+
${run(c)}`).join("\n\n");
|
|
813
|
+
return { content: [{ type: "text", text: out }] };
|
|
814
|
+
}),
|
|
815
|
+
tool("scan_gcp_resources", "Google Cloud Platform via gcloud CLI scannen \u2014 100% readonly (list, describe)", {
|
|
816
|
+
project: z2.string().optional().describe("GCP Project ID \u2014 default: aktuelles gcloud-Projekt")
|
|
817
|
+
}, async (args) => {
|
|
818
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
819
|
+
const project = args["project"];
|
|
820
|
+
const pf = project ? `--project ${project}` : "";
|
|
821
|
+
const run = (cmd) => {
|
|
822
|
+
try {
|
|
823
|
+
return execSync2(cmd, { stdio: "pipe", timeout: 2e4, shell: "/bin/sh" }).toString().trim();
|
|
824
|
+
} catch (e) {
|
|
825
|
+
return `(error: ${e instanceof Error ? e.message.split("\n")[0] : String(e)})`;
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
const sections = [
|
|
829
|
+
["IDENTITY", `gcloud config list account --format='value(core.account)' 2>/dev/null; gcloud config get-value project 2>/dev/null`],
|
|
830
|
+
["COMPUTE_INSTANCES", `gcloud compute instances list ${pf} 2>/dev/null || echo "(error)"`],
|
|
831
|
+
["SQL_INSTANCES", `gcloud sql instances list ${pf} 2>/dev/null || echo "(error)"`],
|
|
832
|
+
["GKE_CLUSTERS", `gcloud container clusters list ${pf} 2>/dev/null || echo "(error)"`],
|
|
833
|
+
["CLOUD_RUN", `gcloud run services list ${pf} --platform managed 2>/dev/null || echo "(error)"`],
|
|
834
|
+
["CLOUD_FUNCTIONS", `gcloud functions list ${pf} 2>/dev/null || echo "(error)"`],
|
|
835
|
+
["REDIS", `gcloud redis instances list ${pf} --regions=- 2>/dev/null || echo "(error)"`],
|
|
836
|
+
["PUBSUB", `gcloud pubsub topics list ${pf} 2>/dev/null || echo "(error)"`],
|
|
837
|
+
["SPANNER", `gcloud spanner instances list ${pf} 2>/dev/null || echo "(error)"`]
|
|
838
|
+
];
|
|
839
|
+
const out = sections.map(([l, c]) => `=== ${l} ===
|
|
840
|
+
${run(c)}`).join("\n\n");
|
|
841
|
+
return { content: [{ type: "text", text: out }] };
|
|
842
|
+
}),
|
|
843
|
+
tool("scan_azure_resources", "Azure-Infrastruktur via az CLI scannen \u2014 100% readonly (list, show)", {
|
|
844
|
+
subscription: z2.string().optional().describe("Azure Subscription ID"),
|
|
845
|
+
resourceGroup: z2.string().optional().describe("Resource Group filtern")
|
|
846
|
+
}, async (args) => {
|
|
847
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
848
|
+
const sub = args["subscription"];
|
|
849
|
+
const rg = args["resourceGroup"];
|
|
850
|
+
const sf = sub ? `--subscription ${sub}` : "";
|
|
851
|
+
const rf = rg ? `--resource-group ${rg}` : "";
|
|
852
|
+
const run = (cmd) => {
|
|
853
|
+
try {
|
|
854
|
+
return execSync2(cmd, { stdio: "pipe", timeout: 2e4, shell: "/bin/sh" }).toString().trim();
|
|
855
|
+
} catch (e) {
|
|
856
|
+
return `(error: ${e instanceof Error ? e.message.split("\n")[0] : String(e)})`;
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
const sections = [
|
|
860
|
+
["IDENTITY", `az account show --output json ${sf} 2>/dev/null || echo "(nicht eingeloggt \u2014 az login)"`],
|
|
861
|
+
["VMS", `az vm list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
862
|
+
["AKS", `az aks list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
863
|
+
["SQL_SERVERS", `az sql server list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
864
|
+
["POSTGRES", `az postgres server list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
865
|
+
["REDIS", `az redis list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
866
|
+
["WEBAPPS", `az webapp list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
867
|
+
["CONTAINER_APPS", `az containerapp list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`],
|
|
868
|
+
["FUNCTIONS", `az functionapp list ${sf} ${rf} --output table 2>/dev/null || echo "(error)"`]
|
|
869
|
+
];
|
|
870
|
+
const out = sections.map(([l, c]) => `=== ${l} ===
|
|
871
|
+
${run(c)}`).join("\n\n");
|
|
872
|
+
return { content: [{ type: "text", text: out }] };
|
|
873
|
+
}),
|
|
874
|
+
tool("scan_installed_apps", "Alle installierten Apps und Tools auf dem PC scannen \u2014 IDEs, Office, Dev-Tools, Business-Apps", {
|
|
875
|
+
searchHint: z2.string().optional().describe('Optionaler Suchbegriff um gezielt nach bestimmten Tools zu suchen (z.B. "hubspot windsurf cursor")')
|
|
876
|
+
}, async (args) => {
|
|
877
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
878
|
+
const hint = args["searchHint"];
|
|
879
|
+
const run = (cmd) => {
|
|
880
|
+
try {
|
|
881
|
+
return execSync2(cmd, { stdio: "pipe", timeout: 15e3, shell: "/bin/sh" }).toString().trim();
|
|
882
|
+
} catch {
|
|
883
|
+
return "";
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
const platform = process.platform;
|
|
887
|
+
const results = {};
|
|
888
|
+
if (platform === "darwin") {
|
|
889
|
+
results["APPLICATIONS"] = run("ls /Applications/ 2>/dev/null | head -200") || "(leer)";
|
|
890
|
+
results["USER_APPLICATIONS"] = run("ls ~/Applications/ 2>/dev/null | head -100") || "(leer)";
|
|
891
|
+
results["BREW_CASKS"] = run("brew list --cask 2>/dev/null | head -100") || "(brew nicht installiert)";
|
|
892
|
+
results["BREW_FORMULAE"] = run("brew list --formula 2>/dev/null | head -150") || "(brew nicht installiert)";
|
|
893
|
+
results["SPOTLIGHT_APPS"] = run(`mdfind "kMDItemKind == 'Application'" 2>/dev/null | grep -v "^/System" | grep -v "^/Library/Apple" | head -100`) || "(Spotlight nicht verf\xFCgbar)";
|
|
894
|
+
} else if (platform === "linux") {
|
|
895
|
+
results["DPKG"] = run("dpkg --list 2>/dev/null | awk '{print $2}' | head -200") || "(dpkg nicht verf\xFCgbar)";
|
|
896
|
+
results["SNAP"] = run("snap list 2>/dev/null | head -50") || "(snap nicht verf\xFCgbar)";
|
|
897
|
+
results["FLATPAK"] = run("flatpak list 2>/dev/null | head -50") || "(flatpak nicht verf\xFCgbar)";
|
|
898
|
+
results["DESKTOP_FILES"] = run("ls /usr/share/applications/*.desktop ~/.local/share/applications/*.desktop 2>/dev/null | xargs -I{} basename {} .desktop 2>/dev/null | head -100") || "(keine .desktop files)";
|
|
899
|
+
results["RPM"] = run("rpm -qa 2>/dev/null | head -200") || "(rpm nicht verf\xFCgbar)";
|
|
900
|
+
} else if (platform === "win32") {
|
|
901
|
+
results["WINGET"] = run("winget list 2>/dev/null | head -100") || "(winget nicht verf\xFCgbar)";
|
|
902
|
+
results["PROGRAMS_x64"] = run('reg query "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" /s /v DisplayName 2>/dev/null | findstr DisplayName | head -100') || "(nicht verf\xFCgbar)";
|
|
903
|
+
}
|
|
904
|
+
const knownTools = [
|
|
905
|
+
// IDEs & Editors
|
|
906
|
+
"code",
|
|
907
|
+
"code-insiders",
|
|
908
|
+
"cursor",
|
|
909
|
+
"windsurf",
|
|
910
|
+
"zed",
|
|
911
|
+
"vim",
|
|
912
|
+
"nvim",
|
|
913
|
+
"emacs",
|
|
914
|
+
"nano",
|
|
915
|
+
"sublime_text",
|
|
916
|
+
"atom",
|
|
917
|
+
"idea",
|
|
918
|
+
"webstorm",
|
|
919
|
+
"pycharm",
|
|
920
|
+
"goland",
|
|
921
|
+
"datagrip",
|
|
922
|
+
"clion",
|
|
923
|
+
"rider",
|
|
924
|
+
"phpstorm",
|
|
925
|
+
"rubymine",
|
|
926
|
+
"appcode",
|
|
927
|
+
// Dev Tools
|
|
928
|
+
"git",
|
|
929
|
+
"gh",
|
|
930
|
+
"docker",
|
|
931
|
+
"docker-compose",
|
|
932
|
+
"podman",
|
|
933
|
+
"kubectl",
|
|
934
|
+
"helm",
|
|
935
|
+
"terraform",
|
|
936
|
+
"ansible",
|
|
937
|
+
"node",
|
|
938
|
+
"npm",
|
|
939
|
+
"npx",
|
|
940
|
+
"yarn",
|
|
941
|
+
"pnpm",
|
|
942
|
+
"bun",
|
|
943
|
+
"deno",
|
|
944
|
+
"python",
|
|
945
|
+
"python3",
|
|
946
|
+
"pip",
|
|
947
|
+
"pip3",
|
|
948
|
+
"pipenv",
|
|
949
|
+
"poetry",
|
|
950
|
+
"conda",
|
|
951
|
+
"ruby",
|
|
952
|
+
"gem",
|
|
953
|
+
"bundler",
|
|
954
|
+
"rails",
|
|
955
|
+
"java",
|
|
956
|
+
"mvn",
|
|
957
|
+
"gradle",
|
|
958
|
+
"kotlin",
|
|
959
|
+
"go",
|
|
960
|
+
"cargo",
|
|
961
|
+
"rustc",
|
|
962
|
+
"php",
|
|
963
|
+
"composer",
|
|
964
|
+
"dotnet",
|
|
965
|
+
"dotnet-sdk",
|
|
966
|
+
// Databases
|
|
967
|
+
"psql",
|
|
968
|
+
"mysql",
|
|
969
|
+
"mysqladmin",
|
|
970
|
+
"mongo",
|
|
971
|
+
"mongosh",
|
|
972
|
+
"redis-cli",
|
|
973
|
+
"sqlite3",
|
|
974
|
+
"clickhouse-client",
|
|
975
|
+
// Cloud CLIs
|
|
976
|
+
"aws",
|
|
977
|
+
"gcloud",
|
|
978
|
+
"az",
|
|
979
|
+
"heroku",
|
|
980
|
+
"fly",
|
|
981
|
+
"vercel",
|
|
982
|
+
"netlify",
|
|
983
|
+
"wrangler",
|
|
984
|
+
// Infra
|
|
985
|
+
"vagrant",
|
|
986
|
+
"packer",
|
|
987
|
+
"consul",
|
|
988
|
+
"vault",
|
|
989
|
+
"nomad",
|
|
990
|
+
// Communication / SaaS
|
|
991
|
+
"slack",
|
|
992
|
+
"discord",
|
|
993
|
+
"zoom",
|
|
994
|
+
"teams",
|
|
995
|
+
"skype",
|
|
996
|
+
"telegram",
|
|
997
|
+
"signal",
|
|
998
|
+
// Browsers
|
|
999
|
+
"google-chrome",
|
|
1000
|
+
"chromium",
|
|
1001
|
+
"firefox",
|
|
1002
|
+
"safari",
|
|
1003
|
+
"brave",
|
|
1004
|
+
"opera",
|
|
1005
|
+
"edge",
|
|
1006
|
+
// Monitoring / Analytics
|
|
1007
|
+
"datadog-agent",
|
|
1008
|
+
"newrelic-agent",
|
|
1009
|
+
"prometheus",
|
|
1010
|
+
"grafana-cli",
|
|
1011
|
+
// Other tools
|
|
1012
|
+
"ngrok",
|
|
1013
|
+
"stripe",
|
|
1014
|
+
"supabase",
|
|
1015
|
+
"neon"
|
|
1016
|
+
];
|
|
1017
|
+
const found = [];
|
|
1018
|
+
const notFound = [];
|
|
1019
|
+
for (const t of knownTools) {
|
|
1020
|
+
const r = run(`which ${t} 2>/dev/null`);
|
|
1021
|
+
if (r) found.push(`${t}: ${r}`);
|
|
1022
|
+
else notFound.push(t);
|
|
1023
|
+
}
|
|
1024
|
+
results["WHICH_FOUND"] = found.join("\n") || "(nichts gefunden)";
|
|
1025
|
+
results["WHICH_NOT_FOUND"] = notFound.join(", ");
|
|
1026
|
+
if (hint) {
|
|
1027
|
+
const terms = hint.split(/[\s,]+/).filter(Boolean);
|
|
1028
|
+
const hintResults = [];
|
|
1029
|
+
for (const term of terms) {
|
|
1030
|
+
const safe = term.replace(/[^a-zA-Z0-9._-]/g, "");
|
|
1031
|
+
if (!safe) continue;
|
|
1032
|
+
const r = run(`which ${safe} 2>/dev/null || find /Applications ~/Applications /usr/bin /usr/local/bin /opt/homebrew/bin ~/.local/bin 2>/dev/null -iname "*${safe}*" -maxdepth 3 2>/dev/null | head -5`);
|
|
1033
|
+
if (r) hintResults.push(`${term}: ${r}`);
|
|
1034
|
+
else hintResults.push(`${term}: (nicht gefunden)`);
|
|
1035
|
+
}
|
|
1036
|
+
results["HINT_SEARCH"] = hintResults.join("\n");
|
|
1037
|
+
}
|
|
1038
|
+
const out = Object.entries(results).map(([k, v]) => `=== ${k} ===
|
|
1039
|
+
${v}`).join("\n\n");
|
|
1040
|
+
return { content: [{ type: "text", text: out }] };
|
|
1041
|
+
}),
|
|
738
1042
|
tool("save_sop", "Standard Operating Procedure speichern", {
|
|
739
1043
|
workflowId: z2.string(),
|
|
740
1044
|
title: z2.string(),
|
|
@@ -790,11 +1094,15 @@ var safetyHook = async (input) => {
|
|
|
790
1094
|
};
|
|
791
1095
|
|
|
792
1096
|
// src/agent.ts
|
|
793
|
-
async function runDiscovery(config, db, sessionId, onEvent, onAskUser) {
|
|
1097
|
+
async function runDiscovery(config, db, sessionId, onEvent, onAskUser, hint) {
|
|
794
1098
|
const { query } = await import("@anthropic-ai/claude-code");
|
|
795
1099
|
const tools = await createCartographyTools(db, sessionId, { onAskUser });
|
|
796
|
-
const
|
|
797
|
-
|
|
1100
|
+
const hintSection = hint ? `
|
|
1101
|
+
\u26A1 USER-HINT (PRIORIT\xC4T): Der User m\xF6chte gezielt nach folgenden Tools suchen: "${hint}"
|
|
1102
|
+
\u2192 scan_installed_apps(searchHint: "${hint}") SOFORT ausf\xFChren und diese Tools als saas_tool oder config_file speichern!
|
|
1103
|
+
` : "";
|
|
1104
|
+
const systemPrompt = `Du bist ein Infrastruktur-Discovery-Agent. Kartographiere die gesamte Systemlandschaft \u2014 lokale Services, SaaS-Tools UND alle installierten Apps/Tools des Users.
|
|
1105
|
+
${hintSection}
|
|
798
1106
|
\u2501\u2501 PFLICHT-REIHENFOLGE \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
799
1107
|
SCHRITT 1 \u2014 Browser-Lesezeichen (IMMER ZUERST):
|
|
800
1108
|
scan_bookmarks() aufrufen \u2192 jede zur\xFCckgegebene Domain klassifizieren:
|
|
@@ -802,19 +1110,36 @@ SCHRITT 1 \u2014 Browser-Lesezeichen (IMMER ZUERST):
|
|
|
802
1110
|
\u2022 Interne Hosts (IPs, custom.company.com:PORT) \u2192 save_node als web_service
|
|
803
1111
|
\u2022 Pers\xF6nliches (Social Media, News, Streaming, Shopping) \u2192 IGNORIEREN, NICHT speichern
|
|
804
1112
|
|
|
805
|
-
SCHRITT 2 \u2014
|
|
1113
|
+
SCHRITT 2 \u2014 Installierte Apps & Tools (SEHR WICHTIG):
|
|
1114
|
+
scan_installed_apps() aufrufen \u2192 ALLE gefundenen Apps/Tools klassifizieren:
|
|
1115
|
+
\u2022 IDEs (VS Code, Cursor, Windsurf, JetBrains, etc.) \u2192 save_node als saas_tool mit category="ide"
|
|
1116
|
+
\u2022 Office & Produktivit\xE4t (Word, Excel, Notion, Obsidian, etc.) \u2192 save_node als saas_tool mit category="productivity"
|
|
1117
|
+
\u2022 Dev-Tools (Docker, kubectl, git, Node, Python, etc.) \u2192 save_node als saas_tool mit category="dev-tool"
|
|
1118
|
+
\u2022 Business-Apps (Slack, Zoom, HubSpot, Salesforce, etc.) \u2192 save_node als saas_tool mit category="business"
|
|
1119
|
+
\u2022 Browser (Chrome, Firefox, Safari, etc.) \u2192 save_node als saas_tool mit category="browser"
|
|
1120
|
+
\u2022 Design-Tools (Figma, Sketch, Adobe, etc.) \u2192 save_node als saas_tool mit category="design"
|
|
1121
|
+
ALLE relevanten Tools speichern \u2014 auch wenn offline/lokal!
|
|
1122
|
+
|
|
1123
|
+
SCHRITT 3 \u2014 Lokale Infrastruktur:
|
|
806
1124
|
ss -tlnp && ps aux \u2192 alle lauschenden Ports/Prozesse identifizieren
|
|
807
1125
|
Jeden Service vertiefen: DB\u2192Schemas, API\u2192Endpoints, Queue\u2192Topics
|
|
808
1126
|
|
|
809
|
-
SCHRITT
|
|
1127
|
+
SCHRITT 4 \u2014 Cloud & Kubernetes (falls CLI vorhanden):
|
|
1128
|
+
scan_k8s_resources() \u2192 Nodes, Services, Pods, Deployments, Ingresses
|
|
1129
|
+
scan_aws_resources() \u2192 EC2, RDS, ELB, EKS, ElastiCache, S3 (falls AWS CLI + Credentials)
|
|
1130
|
+
scan_gcp_resources() \u2192 Compute, SQL, GKE, Cloud Run, Functions (falls gcloud + Auth)
|
|
1131
|
+
scan_azure_resources() \u2192 VMs, AKS, SQL, Redis, WebApps (falls az CLI + Login)
|
|
1132
|
+
Fehler / "nicht verf\xFCgbar" \u2192 ignorieren, weiter mit n\xE4chstem Tool
|
|
1133
|
+
|
|
1134
|
+
SCHRITT 5 \u2014 Config-Files:
|
|
810
1135
|
.env, docker-compose.yml, application.yml, kubernetes/*.yml
|
|
811
1136
|
Nur Host:Port extrahieren \u2014 KEINE Credentials
|
|
812
1137
|
|
|
813
|
-
SCHRITT
|
|
1138
|
+
SCHRITT 6 \u2014 R\xFCckfragen bei Unklarheit:
|
|
814
1139
|
ask_user() nutzen wenn: Dienst unklar ist, Kontext fehlt, oder User Input sinnvoll w\xE4re
|
|
815
1140
|
Beispiele: "Welche Umgebung ist das (dev/staging/prod)?", "Ist <host> ein internes Tool?"
|
|
816
1141
|
|
|
817
|
-
SCHRITT
|
|
1142
|
+
SCHRITT 7 \u2014 Fertig wenn alle Spuren ersch\xF6pft.
|
|
818
1143
|
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
819
1144
|
|
|
820
1145
|
PORT-MAPPING: 5432=postgres, 3306=mysql, 27017=mongodb, 6379=redis,
|
|
@@ -824,15 +1149,20 @@ PORT-MAPPING: 5432=postgres, 3306=mysql, 27017=mongodb, 6379=redis,
|
|
|
824
1149
|
REGELN:
|
|
825
1150
|
\u2022 Nur read-only (ss, ps, cat, head, curl -s, docker inspect, kubectl get)
|
|
826
1151
|
\u2022 Node IDs: "type:host:port" oder "type:name" \u2014 keine Pfade, keine Credentials
|
|
827
|
-
\u2022 saas_tool IDs: "saas_tool:github.com", "saas_tool:
|
|
828
|
-
\u2022
|
|
829
|
-
\u2022
|
|
1152
|
+
\u2022 saas_tool IDs: "saas_tool:github.com", "saas_tool:vscode", "saas_tool:cursor"
|
|
1153
|
+
\u2022 Installed-App IDs: "saas_tool:<appname>" z.B. "saas_tool:slack", "saas_tool:docker-desktop"
|
|
1154
|
+
\u2022 Confidence: 0.9 direkt gesehen, 0.7 aus Config/Bookmarks/Apps, 0.5 Vermutung
|
|
1155
|
+
\u2022 metadata erlaubt: { description, category, port, version, path } \u2014 keine Passw\xF6rter
|
|
830
1156
|
\u2022 get_catalog vor save_node \u2192 Duplikate vermeiden
|
|
831
1157
|
\u2022 Edges speichern wenn Verbindungen klar erkennbar sind
|
|
832
1158
|
|
|
833
1159
|
Entrypoints: ${config.entryPoints.join(", ")}`;
|
|
834
|
-
const initialPrompt = `Starte Discovery
|
|
1160
|
+
const initialPrompt = hint ? `Starte Discovery mit USER-HINT: "${hint}".
|
|
1161
|
+
F\xFChre SOFORT scan_installed_apps(searchHint: "${hint}") aus um nach diesen Tools zu suchen.
|
|
1162
|
+
Dann scan_bookmarks, dann lokale Services.
|
|
1163
|
+
Nutze ask_user wenn du Kontext vom User brauchst.` : `Starte Discovery jetzt.
|
|
835
1164
|
F\xFChre SOFORT als erstes scan_bookmarks aus \u2014 noch bevor du ss oder ps verwendest.
|
|
1165
|
+
Danach scan_installed_apps() f\xFCr alle installierten Apps und Tools.
|
|
836
1166
|
Dann systematisch lokale Services, dann Config-Files.
|
|
837
1167
|
Nutze ask_user wenn du Kontext vom User brauchst.`;
|
|
838
1168
|
let turnCount = 0;
|
|
@@ -849,6 +1179,11 @@ Nutze ask_user wenn du Kontext vom User brauchst.`;
|
|
|
849
1179
|
"mcp__cartograph__save_edge",
|
|
850
1180
|
"mcp__cartograph__get_catalog",
|
|
851
1181
|
"mcp__cartograph__scan_bookmarks",
|
|
1182
|
+
"mcp__cartograph__scan_installed_apps",
|
|
1183
|
+
"mcp__cartograph__scan_k8s_resources",
|
|
1184
|
+
"mcp__cartograph__scan_aws_resources",
|
|
1185
|
+
"mcp__cartograph__scan_gcp_resources",
|
|
1186
|
+
"mcp__cartograph__scan_azure_resources",
|
|
852
1187
|
"mcp__cartograph__ask_user"
|
|
853
1188
|
],
|
|
854
1189
|
hooks: {
|
|
@@ -1400,6 +1735,197 @@ function exportSOPMarkdown(sop) {
|
|
|
1400
1735
|
}
|
|
1401
1736
|
return lines.join("\n");
|
|
1402
1737
|
}
|
|
1738
|
+
function exportSOPDashboard(sops) {
|
|
1739
|
+
const sopsJson = JSON.stringify(sops.map((s) => ({
|
|
1740
|
+
id: s.id,
|
|
1741
|
+
title: s.title,
|
|
1742
|
+
description: s.description,
|
|
1743
|
+
steps: s.steps,
|
|
1744
|
+
systems: s.involvedSystems,
|
|
1745
|
+
duration: s.estimatedDuration,
|
|
1746
|
+
frequency: s.frequency,
|
|
1747
|
+
confidence: s.confidence,
|
|
1748
|
+
generatedAt: s.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1749
|
+
})));
|
|
1750
|
+
const systemCount = {};
|
|
1751
|
+
for (const sop of sops) {
|
|
1752
|
+
for (const sys of sop.involvedSystems) {
|
|
1753
|
+
systemCount[sys] = (systemCount[sys] ?? 0) + 1;
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
const systemsJson = JSON.stringify(
|
|
1757
|
+
Object.entries(systemCount).sort((a, b) => b[1] - a[1])
|
|
1758
|
+
);
|
|
1759
|
+
return `<!DOCTYPE html>
|
|
1760
|
+
<html lang="de">
|
|
1761
|
+
<head>
|
|
1762
|
+
<meta charset="UTF-8">
|
|
1763
|
+
<title>Cartography \u2014 SOP Dashboard</title>
|
|
1764
|
+
<style>
|
|
1765
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
1766
|
+
body {
|
|
1767
|
+
background: #0d1117; color: #e6edf3;
|
|
1768
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace;
|
|
1769
|
+
padding: 0; line-height: 1.6;
|
|
1770
|
+
}
|
|
1771
|
+
.header {
|
|
1772
|
+
background: linear-gradient(135deg, #161b22 0%, #1a1f2e 100%);
|
|
1773
|
+
border-bottom: 1px solid #30363d; padding: 32px 40px;
|
|
1774
|
+
}
|
|
1775
|
+
.header h1 { font-size: 24px; color: #58a6ff; margin-bottom: 8px; }
|
|
1776
|
+
.header .subtitle { color: #8b949e; font-size: 14px; }
|
|
1777
|
+
.stats-row {
|
|
1778
|
+
display: flex; gap: 24px; margin-top: 16px; flex-wrap: wrap;
|
|
1779
|
+
}
|
|
1780
|
+
.stat-card {
|
|
1781
|
+
background: #21262d; border: 1px solid #30363d; border-radius: 8px;
|
|
1782
|
+
padding: 12px 20px; min-width: 140px;
|
|
1783
|
+
}
|
|
1784
|
+
.stat-card .value { font-size: 28px; font-weight: 700; color: #58a6ff; }
|
|
1785
|
+
.stat-card .label { font-size: 11px; color: #8b949e; text-transform: uppercase; letter-spacing: 0.5px; }
|
|
1786
|
+
.container { max-width: 1200px; margin: 0 auto; padding: 24px 40px; }
|
|
1787
|
+
.section-title { font-size: 18px; color: #c9d1d9; margin: 32px 0 16px; border-bottom: 1px solid #21262d; padding-bottom: 8px; }
|
|
1788
|
+
/* Systems bar chart */
|
|
1789
|
+
.systems-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 24px; }
|
|
1790
|
+
.sys-tag {
|
|
1791
|
+
background: #21262d; border: 1px solid #30363d; border-radius: 6px;
|
|
1792
|
+
padding: 6px 12px; font-size: 12px; cursor: default;
|
|
1793
|
+
}
|
|
1794
|
+
.sys-tag .count { color: #58a6ff; font-weight: 600; margin-left: 4px; }
|
|
1795
|
+
/* SOP cards */
|
|
1796
|
+
.sop-card {
|
|
1797
|
+
background: #161b22; border: 1px solid #30363d; border-radius: 8px;
|
|
1798
|
+
margin-bottom: 16px; overflow: hidden; transition: border-color 0.2s;
|
|
1799
|
+
}
|
|
1800
|
+
.sop-card:hover { border-color: #58a6ff; }
|
|
1801
|
+
.sop-header {
|
|
1802
|
+
padding: 16px 20px; cursor: pointer; display: flex;
|
|
1803
|
+
justify-content: space-between; align-items: center;
|
|
1804
|
+
}
|
|
1805
|
+
.sop-header h3 { font-size: 16px; color: #e6edf3; }
|
|
1806
|
+
.sop-meta { display: flex; gap: 16px; align-items: center; font-size: 12px; color: #8b949e; }
|
|
1807
|
+
.sop-meta .freq { color: #3fb950; font-weight: 600; }
|
|
1808
|
+
.sop-meta .dur { color: #d29922; }
|
|
1809
|
+
.sop-meta .conf {
|
|
1810
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1811
|
+
}
|
|
1812
|
+
.conf-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
|
|
1813
|
+
.sop-body { display: none; padding: 0 20px 20px; border-top: 1px solid #21262d; }
|
|
1814
|
+
.sop-body.open { display: block; padding-top: 16px; }
|
|
1815
|
+
.sop-desc { color: #8b949e; font-size: 13px; margin-bottom: 12px; }
|
|
1816
|
+
.sop-systems { margin-bottom: 12px; }
|
|
1817
|
+
.sop-systems span { background: #0d419d33; color: #58a6ff; border-radius: 4px; padding: 2px 8px; font-size: 11px; margin-right: 4px; }
|
|
1818
|
+
.steps-list { list-style: none; counter-reset: step; }
|
|
1819
|
+
.steps-list li {
|
|
1820
|
+
counter-increment: step; position: relative;
|
|
1821
|
+
padding: 10px 12px 10px 44px; border-left: 2px solid #30363d;
|
|
1822
|
+
margin-left: 14px; font-size: 13px;
|
|
1823
|
+
}
|
|
1824
|
+
.steps-list li:last-child { border-left-color: transparent; }
|
|
1825
|
+
.steps-list li::before {
|
|
1826
|
+
content: counter(step);
|
|
1827
|
+
position: absolute; left: -14px; top: 8px;
|
|
1828
|
+
width: 26px; height: 26px; border-radius: 50%;
|
|
1829
|
+
background: #21262d; border: 2px solid #30363d;
|
|
1830
|
+
display: flex; align-items: center; justify-content: center;
|
|
1831
|
+
font-size: 12px; font-weight: 600; color: #58a6ff;
|
|
1832
|
+
}
|
|
1833
|
+
.step-tool { color: #d2a8ff; font-weight: 600; }
|
|
1834
|
+
.step-target { color: #7ee787; font-size: 12px; }
|
|
1835
|
+
.step-notes { color: #8b949e; font-style: italic; font-size: 12px; margin-top: 2px; }
|
|
1836
|
+
.step-instr { color: #c9d1d9; }
|
|
1837
|
+
.toggle-icon { color: #8b949e; font-size: 18px; transition: transform 0.2s; }
|
|
1838
|
+
.toggle-icon.open { transform: rotate(90deg); }
|
|
1839
|
+
.empty { color: #484f58; font-size: 14px; padding: 40px; text-align: center; }
|
|
1840
|
+
.gen-time { color: #484f58; font-size: 11px; margin-top: 8px; }
|
|
1841
|
+
</style>
|
|
1842
|
+
</head>
|
|
1843
|
+
<body>
|
|
1844
|
+
<div class="header">
|
|
1845
|
+
<h1>SOP Dashboard</h1>
|
|
1846
|
+
<div class="subtitle">Datasynx Cartography \u2014 Standard Operating Procedures</div>
|
|
1847
|
+
<div class="stats-row">
|
|
1848
|
+
<div class="stat-card"><div class="value" id="sop-count">0</div><div class="label">SOPs</div></div>
|
|
1849
|
+
<div class="stat-card"><div class="value" id="step-count">0</div><div class="label">Total Steps</div></div>
|
|
1850
|
+
<div class="stat-card"><div class="value" id="sys-count">0</div><div class="label">Systems</div></div>
|
|
1851
|
+
<div class="stat-card"><div class="value" id="avg-conf">\u2014</div><div class="label">Avg Confidence</div></div>
|
|
1852
|
+
</div>
|
|
1853
|
+
</div>
|
|
1854
|
+
<div class="container">
|
|
1855
|
+
<h2 class="section-title">Beteiligte Systeme</h2>
|
|
1856
|
+
<div class="systems-grid" id="systems"></div>
|
|
1857
|
+
|
|
1858
|
+
<h2 class="section-title">SOPs</h2>
|
|
1859
|
+
<div id="sop-list"></div>
|
|
1860
|
+
</div>
|
|
1861
|
+
<script>
|
|
1862
|
+
const sops = ${sopsJson};
|
|
1863
|
+
const systems = ${systemsJson};
|
|
1864
|
+
|
|
1865
|
+
document.getElementById('sop-count').textContent = sops.length;
|
|
1866
|
+
document.getElementById('step-count').textContent = sops.reduce((a, s) => a + s.steps.length, 0);
|
|
1867
|
+
document.getElementById('sys-count').textContent = systems.length;
|
|
1868
|
+
const avgConf = sops.length > 0
|
|
1869
|
+
? (sops.reduce((a, s) => a + s.confidence, 0) / sops.length * 100).toFixed(0) + '%'
|
|
1870
|
+
: '\u2014';
|
|
1871
|
+
document.getElementById('avg-conf').textContent = avgConf;
|
|
1872
|
+
|
|
1873
|
+
const sysDiv = document.getElementById('systems');
|
|
1874
|
+
systems.forEach(([name, count]) => {
|
|
1875
|
+
const el = document.createElement('div');
|
|
1876
|
+
el.className = 'sys-tag';
|
|
1877
|
+
el.innerHTML = name + '<span class="count">x' + count + '</span>';
|
|
1878
|
+
sysDiv.appendChild(el);
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
const listDiv = document.getElementById('sop-list');
|
|
1882
|
+
if (sops.length === 0) {
|
|
1883
|
+
listDiv.innerHTML = '<div class="empty">Keine SOPs vorhanden. Shadow-Daemon starten und Workflows beobachten.</div>';
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
sops.forEach((sop, i) => {
|
|
1887
|
+
const confColor = sop.confidence >= 0.8 ? '#3fb950' : sop.confidence >= 0.5 ? '#d29922' : '#f85149';
|
|
1888
|
+
const card = document.createElement('div');
|
|
1889
|
+
card.className = 'sop-card';
|
|
1890
|
+
card.innerHTML = \`
|
|
1891
|
+
<div class="sop-header" onclick="toggle(\${i})">
|
|
1892
|
+
<h3>\${sop.title}</h3>
|
|
1893
|
+
<div class="sop-meta">
|
|
1894
|
+
<span class="freq">\${sop.frequency}</span>
|
|
1895
|
+
<span class="dur">\${sop.duration}</span>
|
|
1896
|
+
<span class="conf"><span class="conf-dot" style="background:\${confColor}"></span>\${Math.round(sop.confidence*100)}%</span>
|
|
1897
|
+
<span class="toggle-icon" id="icon-\${i}">\u25B8</span>
|
|
1898
|
+
</div>
|
|
1899
|
+
</div>
|
|
1900
|
+
<div class="sop-body" id="body-\${i}">
|
|
1901
|
+
<div class="sop-desc">\${sop.description}</div>
|
|
1902
|
+
<div class="sop-systems">\${sop.systems.map(s => '<span>'+s+'</span>').join('')}</div>
|
|
1903
|
+
<ol class="steps-list">
|
|
1904
|
+
\${sop.steps.map(st => \`
|
|
1905
|
+
<li>
|
|
1906
|
+
<span class="step-tool">\${st.tool}</span>
|
|
1907
|
+
\${st.target ? '<span class="step-target"> \u2192 '+st.target+'</span>' : ''}
|
|
1908
|
+
<div class="step-instr">\${st.instruction}</div>
|
|
1909
|
+
\${st.notes ? '<div class="step-notes">'+st.notes+'</div>' : ''}
|
|
1910
|
+
</li>
|
|
1911
|
+
\`).join('')}
|
|
1912
|
+
</ol>
|
|
1913
|
+
<div class="gen-time">Generiert: \${sop.generatedAt ? sop.generatedAt.substring(0,19).replace('T',' ') : '\u2014'}</div>
|
|
1914
|
+
</div>
|
|
1915
|
+
\`;
|
|
1916
|
+
listDiv.appendChild(card);
|
|
1917
|
+
});
|
|
1918
|
+
|
|
1919
|
+
function toggle(i) {
|
|
1920
|
+
const body = document.getElementById('body-'+i);
|
|
1921
|
+
const icon = document.getElementById('icon-'+i);
|
|
1922
|
+
body.classList.toggle('open');
|
|
1923
|
+
icon.classList.toggle('open');
|
|
1924
|
+
}
|
|
1925
|
+
</script>
|
|
1926
|
+
</body>
|
|
1927
|
+
</html>`;
|
|
1928
|
+
}
|
|
1403
1929
|
function exportAll(db, sessionId, outputDir, formats = ["mermaid", "json", "yaml", "html", "sops"]) {
|
|
1404
1930
|
mkdirSync2(outputDir, { recursive: true });
|
|
1405
1931
|
mkdirSync2(join2(outputDir, "sops"), { recursive: true });
|
|
@@ -1496,6 +2022,7 @@ export {
|
|
|
1496
2022
|
exportBackstageYAML,
|
|
1497
2023
|
exportHTML,
|
|
1498
2024
|
exportJSON,
|
|
2025
|
+
exportSOPDashboard,
|
|
1499
2026
|
exportSOPMarkdown,
|
|
1500
2027
|
generateDependencyMermaid,
|
|
1501
2028
|
generateSOPs,
|