nexarch 0.8.27 → 0.9.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/commands/check-in.js +2 -1
- package/dist/commands/command-claim.js +2 -1
- package/dist/commands/init-agent.js +13 -7
- package/dist/commands/init-project.js +159 -11
- package/dist/commands/policy-audit-submit.js +9 -8
- package/dist/commands/policy-audit-template.js +2 -2
- package/dist/commands/policy-controls.js +3 -3
- package/dist/index.js +6 -0
- package/package.json +1 -1
|
@@ -34,7 +34,7 @@ function loadIdentity() {
|
|
|
34
34
|
}
|
|
35
35
|
export async function checkIn(args) {
|
|
36
36
|
const asJson = parseFlag(args, "--json");
|
|
37
|
-
const agentKeyArg = parseOptionValue(args, "--agent-key");
|
|
37
|
+
const agentKeyArg = parseOptionValue(args, "--agent-ref") ?? parseOptionValue(args, "--agent-key");
|
|
38
38
|
const creds = requireCredentials();
|
|
39
39
|
const identity = loadIdentity();
|
|
40
40
|
const agentKey = agentKeyArg ?? identity.agentKey;
|
|
@@ -48,6 +48,7 @@ export async function checkIn(args) {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
const raw = await callMcpTool("nexarch_claim_command", {
|
|
51
|
+
agentRef: agentKey,
|
|
51
52
|
agentKey,
|
|
52
53
|
companyId: creds.companyId,
|
|
53
54
|
}, { companyId: creds.companyId });
|
|
@@ -35,7 +35,7 @@ function loadIdentity() {
|
|
|
35
35
|
export async function commandClaim(args) {
|
|
36
36
|
const asJson = parseFlag(args, "--json");
|
|
37
37
|
const id = parseOptionValue(args, "--id");
|
|
38
|
-
const agentKeyArg = parseOptionValue(args, "--agent-key");
|
|
38
|
+
const agentKeyArg = parseOptionValue(args, "--agent-ref") ?? parseOptionValue(args, "--agent-key");
|
|
39
39
|
if (!id) {
|
|
40
40
|
console.error("error: --id <commandId> is required");
|
|
41
41
|
process.exit(1);
|
|
@@ -49,6 +49,7 @@ export async function commandClaim(args) {
|
|
|
49
49
|
}
|
|
50
50
|
const raw = await callMcpTool("nexarch_claim_command_by_id", {
|
|
51
51
|
commandId: id,
|
|
52
|
+
agentRef: agentKey,
|
|
52
53
|
agentKey,
|
|
53
54
|
companyId: creds.companyId,
|
|
54
55
|
}, { companyId: creds.companyId });
|
|
@@ -76,10 +76,16 @@ function renderChecksTable(checks) {
|
|
|
76
76
|
const lines = [hr, formatRow(headers), hr, ...rows.map(formatRow), hr];
|
|
77
77
|
return lines.join("\n");
|
|
78
78
|
}
|
|
79
|
+
function normalizeRefSegment(value) {
|
|
80
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
81
|
+
}
|
|
82
|
+
function buildEntityRef(entityTypeCode, ...segments) {
|
|
83
|
+
return [normalizeRefSegment(entityTypeCode), ...segments.map(normalizeRefSegment).filter(Boolean)].join(":");
|
|
84
|
+
}
|
|
79
85
|
function getDefaultAgentId() {
|
|
80
86
|
const osUser = process.env.USERNAME || process.env.USER || userInfo().username || "unknown";
|
|
81
87
|
const host = hostname() || "unknown-host";
|
|
82
|
-
return `
|
|
88
|
+
return `nexarch_cli_${normalizeRefSegment(osUser)}_${normalizeRefSegment(host)}`;
|
|
83
89
|
}
|
|
84
90
|
function getRuntimeMode() {
|
|
85
91
|
if (process.env.CI)
|
|
@@ -519,6 +525,7 @@ export async function initAgent(args) {
|
|
|
519
525
|
const capabilitiesArg = parseCsv(parseOptionValue(args, "--capabilities"));
|
|
520
526
|
const notesArg = parseOptionValue(args, "--notes");
|
|
521
527
|
const agentId = explicitAgentId ?? getDefaultAgentId();
|
|
528
|
+
const agentExternalKey = buildEntityRef("agent", agentId);
|
|
522
529
|
const runtime = {
|
|
523
530
|
osPlatform: platform(),
|
|
524
531
|
osType: osType(),
|
|
@@ -635,7 +642,6 @@ export async function initAgent(args) {
|
|
|
635
642
|
if (preflightPassed && policies.policyBundleHash && relForTechBinding) {
|
|
636
643
|
const nowIso = new Date().toISOString();
|
|
637
644
|
const agentRunId = `init-agent-${Date.now()}`;
|
|
638
|
-
const agentExternalKey = `agent:${agentId}`;
|
|
639
645
|
const upsertRaw = await callMcpTool("nexarch_upsert_entities", {
|
|
640
646
|
entities: [
|
|
641
647
|
{
|
|
@@ -713,9 +719,9 @@ export async function initAgent(args) {
|
|
|
713
719
|
}
|
|
714
720
|
if (registration.ok) {
|
|
715
721
|
techComponents.attempted = true;
|
|
716
|
-
const hostExternalKey =
|
|
717
|
-
const osExternalKey =
|
|
718
|
-
const nodeExternalKey =
|
|
722
|
+
const hostExternalKey = buildEntityRef("technology_component", "host", runtime.hostname, runtime.arch);
|
|
723
|
+
const osExternalKey = buildEntityRef("technology_component", "os", runtime.osPlatform, runtime.osRelease, runtime.arch);
|
|
724
|
+
const nodeExternalKey = buildEntityRef("technology_component", "runtime", "nodejs", runtime.nodeVersion);
|
|
719
725
|
const techUpsertRaw = await callMcpTool("nexarch_upsert_entities", {
|
|
720
726
|
entities: [
|
|
721
727
|
{
|
|
@@ -886,7 +892,7 @@ export async function initAgent(args) {
|
|
|
886
892
|
relationships: [
|
|
887
893
|
{
|
|
888
894
|
relationshipTypeCode: "accountable_for",
|
|
889
|
-
fromEntityExternalKey:
|
|
895
|
+
fromEntityExternalKey: buildEntityRef("organisation", creds.companyId),
|
|
890
896
|
toEntityExternalKey: agentExternalKey,
|
|
891
897
|
confidence: 1,
|
|
892
898
|
attributes: { source: "nexarch-cli-init-agent", kind: "org_agent", createdAt: nowIso },
|
|
@@ -1065,7 +1071,7 @@ export async function initAgent(args) {
|
|
|
1065
1071
|
// Save identity so check-in can find the agent key
|
|
1066
1072
|
const identityDir = join(homedir(), ".nexarch");
|
|
1067
1073
|
mkdirSync(identityDir, { recursive: true });
|
|
1068
|
-
writeFileSync(join(identityDir, "identity.json"), JSON.stringify({ agentKey:
|
|
1074
|
+
writeFileSync(join(identityDir, "identity.json"), JSON.stringify({ agentKey: agentExternalKey, companyId: creds.companyId }, null, 2), { mode: 0o600 });
|
|
1069
1075
|
}
|
|
1070
1076
|
catch {
|
|
1071
1077
|
// non-fatal
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import process from "process";
|
|
2
|
+
import * as readline from "node:readline/promises";
|
|
2
3
|
import { execFileSync } from "node:child_process";
|
|
3
4
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
4
5
|
import { basename, join, relative, resolve as resolvePath } from "node:path";
|
|
@@ -23,7 +24,7 @@ function parseToolText(result) {
|
|
|
23
24
|
return JSON.parse(text);
|
|
24
25
|
}
|
|
25
26
|
function slugify(name) {
|
|
26
|
-
return name.toLowerCase().replace(/[^a-z0-9]+/g, "
|
|
27
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
27
28
|
}
|
|
28
29
|
function safeExec(command, args, cwd) {
|
|
29
30
|
try {
|
|
@@ -89,14 +90,14 @@ function inferProvider(ref) {
|
|
|
89
90
|
}
|
|
90
91
|
function providerCanonicalRepoRef(provider) {
|
|
91
92
|
switch (provider) {
|
|
92
|
-
case "github": return "global:
|
|
93
|
-
case "gitlab": return "global:
|
|
94
|
-
case "bitbucket": return "global:
|
|
95
|
-
case "azure-repos": return "global:
|
|
96
|
-
case "codecommit": return "global:
|
|
97
|
-
case "gitea": return "global:
|
|
98
|
-
case "forgejo": return "global:
|
|
99
|
-
case "sourcehut": return "global:
|
|
93
|
+
case "github": return "global:technology_component:github";
|
|
94
|
+
case "gitlab": return "global:technology_component:gitlab";
|
|
95
|
+
case "bitbucket": return "global:technology_component:bitbucket";
|
|
96
|
+
case "azure-repos": return "global:technology_component:azure_repos";
|
|
97
|
+
case "codecommit": return "global:technology_component:codecommit";
|
|
98
|
+
case "gitea": return "global:technology_component:gitea";
|
|
99
|
+
case "forgejo": return "global:technology_component:forgejo";
|
|
100
|
+
case "sourcehut": return "global:technology_component:sourcehut";
|
|
100
101
|
default: return null;
|
|
101
102
|
}
|
|
102
103
|
}
|
|
@@ -864,6 +865,88 @@ function pickRelationshipType(toEntityTypeCode, _fromEntityTypeCode = "applicati
|
|
|
864
865
|
return "depends_on";
|
|
865
866
|
}
|
|
866
867
|
}
|
|
868
|
+
function normalizeToken(value) {
|
|
869
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
870
|
+
}
|
|
871
|
+
function extractHost(input) {
|
|
872
|
+
if (!input)
|
|
873
|
+
return null;
|
|
874
|
+
try {
|
|
875
|
+
return new URL(input).hostname.replace(/^www\./, "").toLowerCase();
|
|
876
|
+
}
|
|
877
|
+
catch {
|
|
878
|
+
return null;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function scoreApplicationCandidate(app, projectName, repoUrl) {
|
|
882
|
+
const entityRef = app.entityRef ?? app.externalKey ?? null;
|
|
883
|
+
if (!entityRef)
|
|
884
|
+
return null;
|
|
885
|
+
let score = 0;
|
|
886
|
+
const reasons = [];
|
|
887
|
+
const appNameNorm = normalizeToken(app.name);
|
|
888
|
+
const projectNorm = normalizeToken(projectName);
|
|
889
|
+
const refNorm = normalizeToken(entityRef);
|
|
890
|
+
if (appNameNorm === projectNorm) {
|
|
891
|
+
score += 0.45;
|
|
892
|
+
reasons.push("name_exact");
|
|
893
|
+
}
|
|
894
|
+
else if (appNameNorm.includes(projectNorm) || projectNorm.includes(appNameNorm)) {
|
|
895
|
+
score += 0.25;
|
|
896
|
+
reasons.push("name_partial");
|
|
897
|
+
}
|
|
898
|
+
if (refNorm.includes(projectNorm)) {
|
|
899
|
+
score += 0.25;
|
|
900
|
+
reasons.push("ref_matches_project");
|
|
901
|
+
}
|
|
902
|
+
const repoHost = extractHost(repoUrl);
|
|
903
|
+
const appWebsite = typeof app.attributes?.website_url === "string" ? app.attributes.website_url : null;
|
|
904
|
+
const appWebsiteHost = extractHost(appWebsite);
|
|
905
|
+
if (repoHost && appWebsiteHost && repoHost === appWebsiteHost) {
|
|
906
|
+
score += 0.5;
|
|
907
|
+
reasons.push("website_host_exact");
|
|
908
|
+
}
|
|
909
|
+
if (score <= 0)
|
|
910
|
+
return null;
|
|
911
|
+
return { entityRef, name: app.name, score: Math.min(1, score), reasons };
|
|
912
|
+
}
|
|
913
|
+
async function promptApplicationChoice(matches, allApps, suggested) {
|
|
914
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
915
|
+
try {
|
|
916
|
+
console.log("\nExisting application entities found.");
|
|
917
|
+
if (suggested) {
|
|
918
|
+
console.log(`Suggested match: ${suggested.name} (${suggested.entityRef}) score=${suggested.score.toFixed(2)} [${suggested.reasons.join(", ")}]`);
|
|
919
|
+
}
|
|
920
|
+
console.log("\nChoose target application:");
|
|
921
|
+
const options = [];
|
|
922
|
+
let index = 1;
|
|
923
|
+
for (const m of matches.slice(0, 5)) {
|
|
924
|
+
options.push({
|
|
925
|
+
key: String(index++),
|
|
926
|
+
label: `${m.name} (${m.entityRef}) score=${m.score.toFixed(2)}`,
|
|
927
|
+
value: m.entityRef,
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
options.push({ key: String(index++), label: "Show all applications", value: "__show_all__" });
|
|
931
|
+
options.push({ key: String(index), label: "Create a new application", value: "__create__" });
|
|
932
|
+
for (const o of options)
|
|
933
|
+
console.log(` ${o.key}) ${o.label}`);
|
|
934
|
+
const answer = (await rl.question("Select option: ")).trim();
|
|
935
|
+
const chosen = options.find((o) => o.key === answer)?.value;
|
|
936
|
+
if (chosen === "__show_all__") {
|
|
937
|
+
console.log("\nAll applications:");
|
|
938
|
+
allApps.forEach((a, i) => console.log(` ${i + 1}) ${a.name} (${a.entityRef ?? a.externalKey ?? "n/a"})`));
|
|
939
|
+
const pick = Number((await rl.question("Pick application number or 0 to create new: ")).trim());
|
|
940
|
+
if (!Number.isFinite(pick) || pick <= 0 || pick > allApps.length)
|
|
941
|
+
return "__create__";
|
|
942
|
+
return allApps[pick - 1].entityRef ?? allApps[pick - 1].externalKey ?? "__create__";
|
|
943
|
+
}
|
|
944
|
+
return chosen && chosen !== "__show_all__" ? chosen : "__create__";
|
|
945
|
+
}
|
|
946
|
+
finally {
|
|
947
|
+
rl.close();
|
|
948
|
+
}
|
|
949
|
+
}
|
|
867
950
|
// ─── Main command ─────────────────────────────────────────────────────────────
|
|
868
951
|
export async function initProject(args) {
|
|
869
952
|
const asJson = parseFlag(args, "--json");
|
|
@@ -875,6 +958,10 @@ export async function initProject(args) {
|
|
|
875
958
|
const repoRefOverride = parseOptionValue(args, "--repo-ref");
|
|
876
959
|
const repoUrlOverride = parseOptionValue(args, "--repo-url");
|
|
877
960
|
const repoPathOverride = parseOptionValue(args, "--repo-path");
|
|
961
|
+
const applicationRefOverride = parseOptionValue(args, "--application-ref");
|
|
962
|
+
const forceCreateApplication = parseFlag(args, "--create-application");
|
|
963
|
+
const autoMapApplication = parseFlag(args, "--auto-map-application");
|
|
964
|
+
const nonInteractive = parseFlag(args, "--non-interactive");
|
|
878
965
|
const creds = requireCredentials();
|
|
879
966
|
const mcpOpts = { companyId: creds.companyId };
|
|
880
967
|
if (!asJson)
|
|
@@ -883,7 +970,7 @@ export async function initProject(args) {
|
|
|
883
970
|
const detectedRepo = detectSourceRepository(dir);
|
|
884
971
|
const displayName = nameOverride ?? projectName;
|
|
885
972
|
const projectSlug = slugify(displayName);
|
|
886
|
-
|
|
973
|
+
let projectExternalKey = `${entityTypeOverride}:${projectSlug}`;
|
|
887
974
|
// Compute sub-package external keys now that projectSlug is known.
|
|
888
975
|
// Unscoped names (no "/") get prefixed with the project slug to avoid ambiguous keys
|
|
889
976
|
// like "application:crawler" — they become "application:whatsontap-crawler" instead,
|
|
@@ -987,6 +1074,57 @@ export async function initProject(args) {
|
|
|
987
1074
|
const repoUrl = repoUrlOverride ?? detectedRepo?.url ?? null;
|
|
988
1075
|
const sourceVcsType = detectedRepo?.vcsType ?? "unknown";
|
|
989
1076
|
const sourceProvider = detectedRepo?.provider ?? "unknown";
|
|
1077
|
+
if (entityTypeOverride === "application" && !forceCreateApplication) {
|
|
1078
|
+
if (applicationRefOverride) {
|
|
1079
|
+
projectExternalKey = applicationRefOverride;
|
|
1080
|
+
if (!asJson)
|
|
1081
|
+
console.log(`\nUsing --application-ref target: ${projectExternalKey}`);
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
const appsRaw = await callMcpTool("nexarch_list_entities", { entityTypeCode: "application", status: "active", limit: 500, companyId: creds.companyId }, mcpOpts);
|
|
1085
|
+
const appsData = parseToolText(appsRaw);
|
|
1086
|
+
const apps = (appsData.entities ?? []).filter((e) => (e.entityRef ?? e.externalKey));
|
|
1087
|
+
if (apps.length > 0) {
|
|
1088
|
+
const matches = apps
|
|
1089
|
+
.map((a) => scoreApplicationCandidate(a, displayName, repoUrl))
|
|
1090
|
+
.filter((m) => Boolean(m))
|
|
1091
|
+
.sort((a, b) => b.score - a.score);
|
|
1092
|
+
const suggested = matches.length > 0 ? matches[0] : null;
|
|
1093
|
+
const highConfidence = suggested && suggested.score >= 0.85;
|
|
1094
|
+
const interactiveAllowed = !asJson && !nonInteractive && process.stdin.isTTY;
|
|
1095
|
+
if (autoMapApplication && highConfidence) {
|
|
1096
|
+
projectExternalKey = suggested.entityRef;
|
|
1097
|
+
if (!asJson)
|
|
1098
|
+
console.log(`\nAuto-mapped to existing application: ${suggested.name} (${projectExternalKey})`);
|
|
1099
|
+
}
|
|
1100
|
+
else if (!interactiveAllowed) {
|
|
1101
|
+
if (highConfidence) {
|
|
1102
|
+
projectExternalKey = suggested.entityRef;
|
|
1103
|
+
}
|
|
1104
|
+
else if (autoMapApplication) {
|
|
1105
|
+
const message = "Ambiguous application mapping in non-interactive mode. Pass --application-ref or --create-application.";
|
|
1106
|
+
if (asJson) {
|
|
1107
|
+
process.stdout.write(`${JSON.stringify({ ok: false, error: "APPLICATION_MAPPING_AMBIGUOUS", message, candidates: matches.slice(0, 5) }, null, 2)}\n`);
|
|
1108
|
+
process.exitCode = 1;
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
throw new Error(message);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
const chosen = await promptApplicationChoice(matches, apps, highConfidence ? suggested : null);
|
|
1116
|
+
if (chosen !== "__create__") {
|
|
1117
|
+
projectExternalKey = chosen;
|
|
1118
|
+
if (!asJson)
|
|
1119
|
+
console.log(`Mapped to existing application: ${projectExternalKey}`);
|
|
1120
|
+
}
|
|
1121
|
+
else if (!asJson) {
|
|
1122
|
+
console.log("Creating a new application entity for this project.");
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
990
1128
|
const agentContext = {
|
|
991
1129
|
agentId: "nexarch-cli:init-project",
|
|
992
1130
|
agentRunId: `init-project-${Date.now()}`,
|
|
@@ -1131,7 +1269,17 @@ export async function initProject(args) {
|
|
|
1131
1269
|
}
|
|
1132
1270
|
}
|
|
1133
1271
|
// Company org is accountable_for the top-level project entity
|
|
1134
|
-
|
|
1272
|
+
let orgExternalKey = `organisation:${normalizeToken(creds.companyId)}`;
|
|
1273
|
+
try {
|
|
1274
|
+
const orgRaw = await callMcpTool("nexarch_list_entities", { entityTypeCode: "organisation", status: "active", limit: 1, companyId: creds.companyId }, mcpOpts);
|
|
1275
|
+
const orgData = parseToolText(orgRaw);
|
|
1276
|
+
const org = (orgData.entities ?? [])[0];
|
|
1277
|
+
if (org?.entityRef || org?.externalKey)
|
|
1278
|
+
orgExternalKey = (org.entityRef ?? org.externalKey);
|
|
1279
|
+
}
|
|
1280
|
+
catch {
|
|
1281
|
+
// keep fallback
|
|
1282
|
+
}
|
|
1135
1283
|
addRel("accountable_for", orgExternalKey, projectExternalKey, 1);
|
|
1136
1284
|
// Also accountable_for any sub-package applications
|
|
1137
1285
|
for (const sp of subPackages) {
|
|
@@ -115,11 +115,11 @@ export async function policyAuditSubmit(args) {
|
|
|
115
115
|
if (parseFlag(args, "--help") || parseFlag(args, "-h")) {
|
|
116
116
|
console.log(`
|
|
117
117
|
Usage:
|
|
118
|
-
nexarch policy-audit-submit --command-id <id> --application-
|
|
118
|
+
nexarch policy-audit-submit --command-id <id> --application-ref <key> [options]
|
|
119
119
|
|
|
120
120
|
Options:
|
|
121
121
|
--command-id <id> Required command id
|
|
122
|
-
--application-
|
|
122
|
+
--application-ref <key> Required application reference key (e.g. application:bad-driving)
|
|
123
123
|
--agent-key <key> Optional agent key (defaults from identity)
|
|
124
124
|
--finding <controlId|ruleId|result|rationale|missing1;missing2> Repeatable
|
|
125
125
|
--findings-json <json> JSON array of findings
|
|
@@ -134,22 +134,23 @@ Notes:
|
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
136
|
const commandId = parseOptionValue(args, "--command-id") ?? parseOptionValue(args, "--id");
|
|
137
|
-
const
|
|
137
|
+
const applicationEntityRef = parseOptionValue(args, "--application-ref") ?? parseOptionValue(args, "--application-key") ?? parseOptionValue(args, "--entity-ref") ?? parseOptionValue(args, "--entity");
|
|
138
138
|
const agentKey = parseOptionValue(args, "--agent-key") ?? loadIdentityAgentKey();
|
|
139
139
|
if (!commandId) {
|
|
140
140
|
console.error("error: --command-id <uuid> is required");
|
|
141
141
|
process.exit(1);
|
|
142
142
|
}
|
|
143
|
-
if (!
|
|
144
|
-
console.error("error: --application-
|
|
143
|
+
if (!applicationEntityRef) {
|
|
144
|
+
console.error("error: --application-ref <entityRef> is required (e.g. application:bad-driving)");
|
|
145
145
|
process.exit(1);
|
|
146
146
|
}
|
|
147
147
|
const findings = parseFindings(args);
|
|
148
148
|
const creds = requireCredentials();
|
|
149
149
|
const raw = await callMcpTool("nexarch_submit_policy_audit", {
|
|
150
150
|
commandId,
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
applicationEntityRef,
|
|
152
|
+
applicationEntityKey: applicationEntityRef,
|
|
153
|
+
...(agentKey ? { agentRef: agentKey, agentKey } : {}),
|
|
153
154
|
findings,
|
|
154
155
|
companyId: creds.companyId,
|
|
155
156
|
}, { companyId: creds.companyId });
|
|
@@ -162,7 +163,7 @@ Notes:
|
|
|
162
163
|
console.error(`Policy audit submit failed${result.error ? `: ${result.error}` : ""}`);
|
|
163
164
|
process.exit(1);
|
|
164
165
|
}
|
|
165
|
-
console.log(`Policy audit submitted for ${
|
|
166
|
+
console.log(`Policy audit submitted for ${applicationEntityRef}.`);
|
|
166
167
|
if (result.runId)
|
|
167
168
|
console.log(`Run ID: ${result.runId}`);
|
|
168
169
|
if (result.summary) {
|
|
@@ -32,7 +32,7 @@ function parseToolText(result) {
|
|
|
32
32
|
}
|
|
33
33
|
export async function policyAuditTemplate(args) {
|
|
34
34
|
const asJson = parseFlag(args, "--json");
|
|
35
|
-
const entity = parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
|
|
35
|
+
const entity = parseOptionValue(args, "--entity-ref") ?? parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
|
|
36
36
|
const outputPath = parseOptionValue(args, "--out") ?? parseOptionValue(args, "--output");
|
|
37
37
|
const defaultResult = (parseOptionValue(args, "--default-result") ?? "fail").toLowerCase();
|
|
38
38
|
const selectedControlIds = new Set(parseMultiOptionValues(args, "--control-id"));
|
|
@@ -62,7 +62,7 @@ Output shape is ready for:
|
|
|
62
62
|
process.exit(1);
|
|
63
63
|
}
|
|
64
64
|
const creds = requireCredentials();
|
|
65
|
-
const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
|
|
65
|
+
const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityRef: entity, entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
|
|
66
66
|
const result = parseToolText(raw);
|
|
67
67
|
if (!result.found) {
|
|
68
68
|
console.error(`error: entity not found: ${entity}`);
|
|
@@ -19,13 +19,13 @@ function parseToolText(result) {
|
|
|
19
19
|
}
|
|
20
20
|
export async function policyControls(args) {
|
|
21
21
|
const asJson = parseFlag(args, "--json");
|
|
22
|
-
const entity = parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
|
|
22
|
+
const entity = parseOptionValue(args, "--entity-ref") ?? parseOptionValue(args, "--entity") ?? parseOptionValue(args, "--application-key");
|
|
23
23
|
if (!entity) {
|
|
24
24
|
console.error("error: --entity <externalKey> is required (e.g. application:bad-driving)");
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
const creds = requireCredentials();
|
|
28
|
-
const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
|
|
28
|
+
const raw = await callMcpTool("nexarch_get_entity_policy_controls", { entityRef: entity, entityExternalKey: entity, companyId: creds.companyId }, { companyId: creds.companyId });
|
|
29
29
|
const result = parseToolText(raw);
|
|
30
30
|
if (asJson) {
|
|
31
31
|
process.stdout.write(JSON.stringify(result) + "\n");
|
|
@@ -35,7 +35,7 @@ export async function policyControls(args) {
|
|
|
35
35
|
console.log(`Entity not found: ${entity}`);
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
|
-
console.log(`Policy controls for ${result.entityExternalKey ?? entity}`);
|
|
38
|
+
console.log(`Policy controls for ${result.entityRef ?? result.entityExternalKey ?? entity}`);
|
|
39
39
|
console.log(`Controls: ${result.controlCount ?? 0}`);
|
|
40
40
|
for (const control of result.controls ?? []) {
|
|
41
41
|
const rules = control.rules ?? [];
|
package/dist/index.js
CHANGED
|
@@ -85,9 +85,15 @@ Usage:
|
|
|
85
85
|
config files against the reference library, write entities and
|
|
86
86
|
relationships to the architecture graph, and log unresolved
|
|
87
87
|
names as reference candidates.
|
|
88
|
+
When entity-type=application and existing applications are present,
|
|
89
|
+
prompts to map to an existing app or create a new one.
|
|
88
90
|
Options: --dir <path> (default: cwd)
|
|
89
91
|
--name <name> override project name
|
|
90
92
|
--entity-type <code> (default: application)
|
|
93
|
+
--application-ref <entityRef> force mapping target
|
|
94
|
+
--create-application force new application entity
|
|
95
|
+
--auto-map-application auto-map only when high confidence
|
|
96
|
+
--non-interactive fail on ambiguous mapping
|
|
91
97
|
--dry-run preview without writing
|
|
92
98
|
--json
|
|
93
99
|
nexarch update-entity
|