nexarch 0.4.9 → 0.5.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.
|
@@ -5,7 +5,7 @@ import process from "process";
|
|
|
5
5
|
import { requireCredentials } from "../lib/credentials.js";
|
|
6
6
|
import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
|
|
7
7
|
import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
|
|
8
|
-
const CLI_VERSION = "0.
|
|
8
|
+
const CLI_VERSION = "0.5.1";
|
|
9
9
|
const AGENT_ENTITY_TYPE = "agent";
|
|
10
10
|
const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
|
|
11
11
|
function parseFlag(args, flag) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import process from "process";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { basename, join, relative, resolve as resolvePath } from "node:path";
|
|
4
5
|
import { homedir } from "node:os";
|
|
5
6
|
import { requireCredentials } from "../lib/credentials.js";
|
|
6
7
|
import { callMcpTool } from "../lib/mcp.js";
|
|
8
|
+
import { CURATED_AGENT_ICON_NAMES } from "../lib/application-icons.js";
|
|
7
9
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
8
10
|
function parseFlag(args, flag) {
|
|
9
11
|
return args.includes(flag);
|
|
@@ -24,6 +26,175 @@ function parseToolText(result) {
|
|
|
24
26
|
function slugify(name) {
|
|
25
27
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
26
28
|
}
|
|
29
|
+
function safeExec(command, args, cwd) {
|
|
30
|
+
try {
|
|
31
|
+
const out = execFileSync(command, args, { cwd, stdio: ["ignore", "pipe", "ignore"], encoding: "utf8" });
|
|
32
|
+
const trimmed = out.trim();
|
|
33
|
+
return trimmed || null;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function normalizeRepoUrl(raw) {
|
|
40
|
+
const trimmed = raw.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
return null;
|
|
43
|
+
// user@host:path(.git) → https://host/path
|
|
44
|
+
const scpLike = trimmed.match(/^(?:[a-z0-9._-]+)@([^:]+):(.+)$/i);
|
|
45
|
+
if (scpLike) {
|
|
46
|
+
const host = scpLike[1].toLowerCase();
|
|
47
|
+
const path = scpLike[2].replace(/\.git$/i, "").replace(/^\/+/, "");
|
|
48
|
+
return `https://${host}/${path}`;
|
|
49
|
+
}
|
|
50
|
+
// ssh://user@host/path(.git) → https://host/path
|
|
51
|
+
const sshLike = trimmed.match(/^ssh:\/\/(?:[a-z0-9._-]+@)?([^/]+)\/(.+)$/i);
|
|
52
|
+
if (sshLike) {
|
|
53
|
+
const host = sshLike[1].toLowerCase();
|
|
54
|
+
const path = sshLike[2].replace(/\.git$/i, "").replace(/^\/+/, "");
|
|
55
|
+
return `https://${host}/${path}`;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const u = new URL(trimmed);
|
|
59
|
+
if (u.protocol === "http:" || u.protocol === "https:") {
|
|
60
|
+
u.hash = "";
|
|
61
|
+
u.search = "";
|
|
62
|
+
u.pathname = u.pathname.replace(/\.git$/i, "");
|
|
63
|
+
return u.toString().replace(/\/$/, "");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// ignore
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
function inferProvider(ref) {
|
|
72
|
+
const value = ref.toLowerCase();
|
|
73
|
+
if (value.includes("github.com"))
|
|
74
|
+
return "github";
|
|
75
|
+
if (value.includes("gitlab.com"))
|
|
76
|
+
return "gitlab";
|
|
77
|
+
if (value.includes("bitbucket.org"))
|
|
78
|
+
return "bitbucket";
|
|
79
|
+
if (value.includes("dev.azure.com") || value.includes("visualstudio.com"))
|
|
80
|
+
return "azure-repos";
|
|
81
|
+
if (value.includes("codecommit"))
|
|
82
|
+
return "codecommit";
|
|
83
|
+
if (value.includes("git.sr.ht") || value.includes("sourcehut"))
|
|
84
|
+
return "sourcehut";
|
|
85
|
+
if (value.includes("forgejo"))
|
|
86
|
+
return "forgejo";
|
|
87
|
+
if (value.includes("gitea"))
|
|
88
|
+
return "gitea";
|
|
89
|
+
return "unknown";
|
|
90
|
+
}
|
|
91
|
+
function providerCanonicalRepoRef(provider) {
|
|
92
|
+
switch (provider) {
|
|
93
|
+
case "github": return "global:repo:github";
|
|
94
|
+
case "gitlab": return "global:repo:gitlab";
|
|
95
|
+
case "bitbucket": return "global:repo:bitbucket";
|
|
96
|
+
case "azure-repos": return "global:repo:azure-repos";
|
|
97
|
+
case "codecommit": return "global:repo:codecommit";
|
|
98
|
+
case "gitea": return "global:repo:gitea";
|
|
99
|
+
case "forgejo": return "global:repo:forgejo";
|
|
100
|
+
case "sourcehut": return "global:repo:sourcehut";
|
|
101
|
+
default: return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function readPackageRepositoryField(dir) {
|
|
105
|
+
const pkgPath = join(dir, "package.json");
|
|
106
|
+
if (!existsSync(pkgPath))
|
|
107
|
+
return null;
|
|
108
|
+
try {
|
|
109
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
110
|
+
if (typeof pkg.repository === "string")
|
|
111
|
+
return pkg.repository;
|
|
112
|
+
if (pkg.repository && typeof pkg.repository === "object" && "url" in pkg.repository && typeof pkg.repository.url === "string") {
|
|
113
|
+
return pkg.repository.url;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// ignore
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
function readHgDefaultPath(dir) {
|
|
122
|
+
const hgrcPath = join(dir, ".hg", "hgrc");
|
|
123
|
+
if (!existsSync(hgrcPath))
|
|
124
|
+
return null;
|
|
125
|
+
try {
|
|
126
|
+
const content = readFileSync(hgrcPath, "utf8");
|
|
127
|
+
const section = content.match(/\[paths\]([\s\S]*?)(\n\[[^\]]+\]|$)/i)?.[1] ?? "";
|
|
128
|
+
const line = section
|
|
129
|
+
.split("\n")
|
|
130
|
+
.map((l) => l.trim())
|
|
131
|
+
.find((l) => /^default\s*=\s*/i.test(l));
|
|
132
|
+
if (!line)
|
|
133
|
+
return null;
|
|
134
|
+
return line.replace(/^default\s*=\s*/i, "").trim() || null;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function readSvnRepositoryUrl(dir) {
|
|
141
|
+
// Best effort using svn CLI if available.
|
|
142
|
+
const fromCli = safeExec("svn", ["info", "--show-item", "repos-root-url"], dir);
|
|
143
|
+
if (fromCli)
|
|
144
|
+
return fromCli;
|
|
145
|
+
// Very rough fallback for legacy .svn/entries format.
|
|
146
|
+
const entriesPath = join(dir, ".svn", "entries");
|
|
147
|
+
if (!existsSync(entriesPath))
|
|
148
|
+
return null;
|
|
149
|
+
try {
|
|
150
|
+
const content = readFileSync(entriesPath, "utf8");
|
|
151
|
+
const firstUrl = content.match(/https?:\/\/[^\s]+/i)?.[0] ?? null;
|
|
152
|
+
return firstUrl;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function detectSourceRepository(dir) {
|
|
159
|
+
let rawRef = null;
|
|
160
|
+
let vcsType = "unknown";
|
|
161
|
+
// Prefer git when present.
|
|
162
|
+
if (existsSync(join(dir, ".git"))) {
|
|
163
|
+
rawRef = safeExec("git", ["remote", "get-url", "origin"], dir)
|
|
164
|
+
?? safeExec("git", ["config", "--get", "remote.origin.url"], dir);
|
|
165
|
+
if (rawRef)
|
|
166
|
+
vcsType = "git";
|
|
167
|
+
}
|
|
168
|
+
// Mercurial fallback.
|
|
169
|
+
if (!rawRef && existsSync(join(dir, ".hg"))) {
|
|
170
|
+
rawRef = safeExec("hg", ["paths", "default"], dir) ?? readHgDefaultPath(dir);
|
|
171
|
+
if (rawRef)
|
|
172
|
+
vcsType = "hg";
|
|
173
|
+
}
|
|
174
|
+
// Subversion fallback.
|
|
175
|
+
if (!rawRef && existsSync(join(dir, ".svn"))) {
|
|
176
|
+
rawRef = readSvnRepositoryUrl(dir);
|
|
177
|
+
if (rawRef)
|
|
178
|
+
vcsType = "svn";
|
|
179
|
+
}
|
|
180
|
+
// package.json repository fallback (metadata only).
|
|
181
|
+
if (!rawRef) {
|
|
182
|
+
rawRef = readPackageRepositoryField(dir);
|
|
183
|
+
if (rawRef)
|
|
184
|
+
vcsType = "unknown";
|
|
185
|
+
}
|
|
186
|
+
if (!rawRef)
|
|
187
|
+
return null;
|
|
188
|
+
const url = normalizeRepoUrl(rawRef);
|
|
189
|
+
const provider = inferProvider(url ?? rawRef);
|
|
190
|
+
return {
|
|
191
|
+
rawRef,
|
|
192
|
+
url,
|
|
193
|
+
vcsType,
|
|
194
|
+
provider,
|
|
195
|
+
canonicalRepoRef: providerCanonicalRepoRef(provider),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
27
198
|
// ─── Project scanning ─────────────────────────────────────────────────────────
|
|
28
199
|
// Noise patterns for env var keys that are internal config, not external service references
|
|
29
200
|
const ENV_KEY_NOISE = /^(NODE_ENV|PORT|HOST|DEBUG|LOG_LEVEL|TZ|LANG|PATH|HOME|USER|SHELL|TERM)$|(_LOG_LEVEL|_MAX_|_MIN_|_DEFAULT_|_TIMEOUT|_DELAY|_JOBS|_INTERVAL|_LIMIT|_RETRIES|_CONCURREN|_WORKERS)$|(_URL|_SECRET|_TOKEN|_KEY|_PASSWORD|_CREDENTIAL|_DSN|_URI)$/;
|
|
@@ -571,6 +742,7 @@ export async function initProject(args) {
|
|
|
571
742
|
if (!asJson)
|
|
572
743
|
console.log(`Scanning ${dir}…`);
|
|
573
744
|
const { projectName, packageJsonCount, detectedNames, rootDepNames, subPackages, detectedEcosystems } = scanProject(dir);
|
|
745
|
+
const detectedRepo = detectSourceRepository(dir);
|
|
574
746
|
const displayName = nameOverride ?? projectName;
|
|
575
747
|
const projectSlug = slugify(displayName);
|
|
576
748
|
const projectExternalKey = `${entityTypeOverride}:${projectSlug}`;
|
|
@@ -587,6 +759,9 @@ export async function initProject(args) {
|
|
|
587
759
|
console.log(` Project : ${displayName} (${entityTypeOverride})`);
|
|
588
760
|
console.log(` Packages: ${packageJsonCount} package.json file(s)`);
|
|
589
761
|
console.log(` Detected: ${detectedNames.length} raw names`);
|
|
762
|
+
if (detectedRepo) {
|
|
763
|
+
console.log(` Repo : ${detectedRepo.url ?? detectedRepo.rawRef} (${detectedRepo.provider}/${detectedRepo.vcsType})`);
|
|
764
|
+
}
|
|
590
765
|
}
|
|
591
766
|
if (detectedNames.length === 0) {
|
|
592
767
|
if (!asJson)
|
|
@@ -613,7 +788,20 @@ export async function initProject(args) {
|
|
|
613
788
|
if (dryRun) {
|
|
614
789
|
const output = {
|
|
615
790
|
dryRun: true,
|
|
616
|
-
project: {
|
|
791
|
+
project: {
|
|
792
|
+
name: displayName,
|
|
793
|
+
externalKey: projectExternalKey,
|
|
794
|
+
entityType: entityTypeOverride,
|
|
795
|
+
sourceRepository: detectedRepo
|
|
796
|
+
? {
|
|
797
|
+
ref: detectedRepo.rawRef,
|
|
798
|
+
url: detectedRepo.url,
|
|
799
|
+
vcsType: detectedRepo.vcsType,
|
|
800
|
+
provider: detectedRepo.provider,
|
|
801
|
+
componentRef: detectedRepo.canonicalRepoRef,
|
|
802
|
+
}
|
|
803
|
+
: null,
|
|
804
|
+
},
|
|
617
805
|
resolved: resolvedItems.map((r) => ({
|
|
618
806
|
input: r.input,
|
|
619
807
|
canonicalName: r.canonicalName,
|
|
@@ -630,9 +818,11 @@ export async function initProject(args) {
|
|
|
630
818
|
const policies = parseToolText(policiesRaw);
|
|
631
819
|
const policyBundleHash = policies.policyBundleHash ?? null;
|
|
632
820
|
const nowIso = new Date().toISOString();
|
|
633
|
-
const repoRef = repoRefOverride ?? dir;
|
|
821
|
+
const repoRef = repoRefOverride ?? detectedRepo?.rawRef ?? dir;
|
|
634
822
|
const repoPath = repoPathOverride ?? dir;
|
|
635
|
-
const repoUrl = repoUrlOverride ?? null;
|
|
823
|
+
const repoUrl = repoUrlOverride ?? detectedRepo?.url ?? null;
|
|
824
|
+
const sourceVcsType = detectedRepo?.vcsType ?? "unknown";
|
|
825
|
+
const sourceProvider = detectedRepo?.provider ?? "unknown";
|
|
636
826
|
const agentContext = {
|
|
637
827
|
agentId: "nexarch-cli:init-project",
|
|
638
828
|
agentRunId: `init-project-${Date.now()}`,
|
|
@@ -661,8 +851,12 @@ export async function initProject(args) {
|
|
|
661
851
|
source_dir: dir,
|
|
662
852
|
scanned_at: nowIso,
|
|
663
853
|
package_json_count: packageJsonCount,
|
|
664
|
-
...(repoUrl ? { repository_url: repoUrl } : {}),
|
|
854
|
+
...(repoUrl ? { repository_url: repoUrl, source_repository_url: repoUrl } : {}),
|
|
665
855
|
repository_ref: repoRef,
|
|
856
|
+
source_repository_ref: repoRef,
|
|
857
|
+
source_vcs_type: sourceVcsType,
|
|
858
|
+
source_provider: sourceProvider,
|
|
859
|
+
...(detectedRepo?.canonicalRepoRef ? { source_repository_component_ref: detectedRepo.canonicalRepoRef } : {}),
|
|
666
860
|
},
|
|
667
861
|
});
|
|
668
862
|
// Resolved reference entities (deduplicated by canonical external ref)
|
|
@@ -680,6 +874,28 @@ export async function initProject(args) {
|
|
|
680
874
|
confidence: 0.95,
|
|
681
875
|
});
|
|
682
876
|
}
|
|
877
|
+
// Ensure source repository component is represented when we can infer one.
|
|
878
|
+
if (detectedRepo?.canonicalRepoRef && !seenRefs.has(detectedRepo.canonicalRepoRef)) {
|
|
879
|
+
seenRefs.add(detectedRepo.canonicalRepoRef);
|
|
880
|
+
entities.push({
|
|
881
|
+
externalKey: detectedRepo.canonicalRepoRef,
|
|
882
|
+
entityTypeCode: "technology_component",
|
|
883
|
+
entitySubtypeCode: "tech_infrastructure",
|
|
884
|
+
name: detectedRepo.provider === "unknown" ? "Source Repository" : `Source Repository (${detectedRepo.provider})`,
|
|
885
|
+
confidence: 0.9,
|
|
886
|
+
...(repoUrl
|
|
887
|
+
? {
|
|
888
|
+
attributes: {
|
|
889
|
+
repository_url: repoUrl,
|
|
890
|
+
source_repository_url: repoUrl,
|
|
891
|
+
source_repository_ref: repoRef,
|
|
892
|
+
source_vcs_type: sourceVcsType,
|
|
893
|
+
source_provider: sourceProvider,
|
|
894
|
+
},
|
|
895
|
+
}
|
|
896
|
+
: {}),
|
|
897
|
+
});
|
|
898
|
+
}
|
|
683
899
|
// Auto-create stub entities for each sub-package
|
|
684
900
|
const seenSubKeys = new Set();
|
|
685
901
|
for (const sp of subPackages) {
|
|
@@ -750,6 +966,10 @@ export async function initProject(args) {
|
|
|
750
966
|
addRel("accountable_for", orgExternalKey, sp.externalKey, 1);
|
|
751
967
|
}
|
|
752
968
|
}
|
|
969
|
+
// Project depends_on its source repository component when resolved/inferred.
|
|
970
|
+
if (detectedRepo?.canonicalRepoRef) {
|
|
971
|
+
addRel("depends_on", projectExternalKey, detectedRepo.canonicalRepoRef, 0.95);
|
|
972
|
+
}
|
|
753
973
|
if (!asJson)
|
|
754
974
|
console.log(`\nWriting to graph…`);
|
|
755
975
|
// Upsert entities
|
|
@@ -768,6 +988,7 @@ export async function initProject(args) {
|
|
|
768
988
|
const ecosystemLabel = detectedEcosystems.length > 0
|
|
769
989
|
? detectedEcosystems.join(", ")
|
|
770
990
|
: "unknown";
|
|
991
|
+
const curatedIconList = CURATED_AGENT_ICON_NAMES.join(", ");
|
|
771
992
|
const manifestHint = detectedEcosystems.includes("nodejs")
|
|
772
993
|
? "package.json"
|
|
773
994
|
: detectedEcosystems.includes("python")
|
|
@@ -800,6 +1021,11 @@ ${subPackages.map((sp) => ` • ${sp.name} (${sp.relativePath})`).join("\n")
|
|
|
800
1021
|
Type definitions or utility package with no runtime
|
|
801
1022
|
→ --entity-type technology_component --subtype tech_library
|
|
802
1023
|
|
|
1024
|
+
ICON ASSIGNMENT (applications only):
|
|
1025
|
+
• Pick one icon from this curated set for each application/sub-app.
|
|
1026
|
+
• If confidence is low, skip --icon rather than guessing.
|
|
1027
|
+
• Allowed icons: ${curatedIconList}
|
|
1028
|
+
|
|
803
1029
|
For each sub-package, run update-entity to register it:
|
|
804
1030
|
|
|
805
1031
|
npx nexarch update-entity \\
|
|
@@ -807,7 +1033,8 @@ ${subPackages.map((sp) => ` • ${sp.name} (${sp.relativePath})`).join("\n")
|
|
|
807
1033
|
--entity-type "<chosen entity type>" \\
|
|
808
1034
|
--subtype "<chosen subtype>" \\
|
|
809
1035
|
--name "<human readable name>" \\
|
|
810
|
-
--description "<what this package does and its role in the project>"
|
|
1036
|
+
--description "<what this package does and its role in the project>" \\
|
|
1037
|
+
--icon "<curated icon>" # applications only
|
|
811
1038
|
|
|
812
1039
|
Then register it as a resolvable alias so future scans don't re-surface it as a candidate:
|
|
813
1040
|
|
|
@@ -922,13 +1149,18 @@ STEP 2 — Enrich the project entity. Run this command with the description you'
|
|
|
922
1149
|
|
|
923
1150
|
npx nexarch update-entity \\
|
|
924
1151
|
--key "${projectExternalKey}" \\
|
|
925
|
-
--entity-type "${entityTypeOverride}"${entityTypeOverride === "application" ? " \\\n --subtype \"app_custom_built\"" : ""} \\
|
|
1152
|
+
--entity-type "${entityTypeOverride}"${entityTypeOverride === "application" ? " \\\n --subtype \"app_custom_built\"\n --icon \"<curated icon>\"" : ""} \\
|
|
926
1153
|
--name "<proper product name from README>" \\
|
|
927
1154
|
--description "<2–4 sentence summary of what it does and why>"
|
|
928
1155
|
${subPkgSection}${gapCheckSection}`;
|
|
929
1156
|
}
|
|
930
1157
|
const enrichmentTask = {
|
|
931
1158
|
instructions: buildEnrichmentInstructions(),
|
|
1159
|
+
iconHints: {
|
|
1160
|
+
provider: "lucide",
|
|
1161
|
+
curated: CURATED_AGENT_ICON_NAMES,
|
|
1162
|
+
note: "Use curated list for agent-selected enrichment icons; omit icon when low confidence.",
|
|
1163
|
+
},
|
|
932
1164
|
projectEntity: {
|
|
933
1165
|
externalKey: projectExternalKey,
|
|
934
1166
|
entityType: entityTypeOverride,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import process from "process";
|
|
2
2
|
import { requireCredentials } from "../lib/credentials.js";
|
|
3
3
|
import { callMcpTool } from "../lib/mcp.js";
|
|
4
|
+
import { CURATED_AGENT_ICON_SET } from "../lib/application-icons.js";
|
|
4
5
|
function parseFlag(args, flag) {
|
|
5
6
|
return args.includes(flag);
|
|
6
7
|
}
|
|
@@ -24,6 +25,7 @@ export async function updateEntity(args) {
|
|
|
24
25
|
const description = parseOptionValue(args, "--description");
|
|
25
26
|
const entityTypeCode = parseOptionValue(args, "--entity-type") ?? "application";
|
|
26
27
|
const entitySubtypeCode = parseOptionValue(args, "--subtype");
|
|
28
|
+
const iconName = parseOptionValue(args, "--icon");
|
|
27
29
|
if (!externalKey) {
|
|
28
30
|
console.error("error: --key <externalKey> is required");
|
|
29
31
|
process.exit(1);
|
|
@@ -50,6 +52,10 @@ export async function updateEntity(args) {
|
|
|
50
52
|
const policyContext = policyBundleHash
|
|
51
53
|
? { policyBundleHash, alignmentSummary: { score: 1, violations: [], waivers: [] } }
|
|
52
54
|
: undefined;
|
|
55
|
+
if (iconName && !CURATED_AGENT_ICON_SET.has(iconName)) {
|
|
56
|
+
console.error(`error: --icon must be one of the curated agent icons (got '${iconName}')`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
53
59
|
const entity = {
|
|
54
60
|
externalKey,
|
|
55
61
|
entityTypeCode,
|
|
@@ -61,6 +67,14 @@ export async function updateEntity(args) {
|
|
|
61
67
|
entity.description = description;
|
|
62
68
|
if (entitySubtypeCode)
|
|
63
69
|
entity.entitySubtypeCode = entitySubtypeCode;
|
|
70
|
+
if (iconName) {
|
|
71
|
+
entity.attributes = {
|
|
72
|
+
application_icon: {
|
|
73
|
+
provider: "lucide",
|
|
74
|
+
name: iconName,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
64
78
|
const raw = await callMcpTool("nexarch_upsert_entities", { entities: [entity], agentContext, policyContext }, mcpOpts);
|
|
65
79
|
const result = parseToolText(raw);
|
|
66
80
|
if (asJson) {
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const CURATED_AGENT_ICON_NAMES = [
|
|
2
|
+
"rocket",
|
|
3
|
+
"globe",
|
|
4
|
+
"monitor",
|
|
5
|
+
"smartphone",
|
|
6
|
+
"server",
|
|
7
|
+
"database",
|
|
8
|
+
"cloud",
|
|
9
|
+
"network",
|
|
10
|
+
"shield",
|
|
11
|
+
"lock",
|
|
12
|
+
"cpu",
|
|
13
|
+
"code",
|
|
14
|
+
"terminal",
|
|
15
|
+
"bug",
|
|
16
|
+
"flask-conical",
|
|
17
|
+
"bot",
|
|
18
|
+
"brain",
|
|
19
|
+
"sparkles",
|
|
20
|
+
"activity",
|
|
21
|
+
"gauge",
|
|
22
|
+
"clock-3",
|
|
23
|
+
"calendar",
|
|
24
|
+
"book-open",
|
|
25
|
+
"file-code",
|
|
26
|
+
"folder",
|
|
27
|
+
"search",
|
|
28
|
+
"filter",
|
|
29
|
+
"list-checks",
|
|
30
|
+
"kanban-square",
|
|
31
|
+
"layers",
|
|
32
|
+
"workflow",
|
|
33
|
+
"git-branch",
|
|
34
|
+
"package",
|
|
35
|
+
"wrench",
|
|
36
|
+
"settings",
|
|
37
|
+
"building-2",
|
|
38
|
+
"factory",
|
|
39
|
+
"store",
|
|
40
|
+
"map",
|
|
41
|
+
"users",
|
|
42
|
+
"briefcase",
|
|
43
|
+
"bar-chart-3",
|
|
44
|
+
"trending-up",
|
|
45
|
+
"target",
|
|
46
|
+
"leaf",
|
|
47
|
+
"heart-pulse",
|
|
48
|
+
];
|
|
49
|
+
export const CURATED_AGENT_ICON_SET = new Set(CURATED_AGENT_ICON_NAMES);
|
package/dist/lib/mcp.js
CHANGED
|
@@ -68,7 +68,7 @@ export async function mcpInitialize(options = {}) {
|
|
|
68
68
|
return callMcpRpc("initialize", {
|
|
69
69
|
protocolVersion: "2024-11-05",
|
|
70
70
|
capabilities: {},
|
|
71
|
-
clientInfo: { name: "nexarch-cli", version: "0.
|
|
71
|
+
clientInfo: { name: "nexarch-cli", version: "0.5.1" },
|
|
72
72
|
}, options);
|
|
73
73
|
}
|
|
74
74
|
export async function mcpListTools(options = {}) {
|