nexarch 0.9.34 → 0.11.0
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.
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
3
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
4
|
+
function parseFlag(args, flag) {
|
|
5
|
+
return args.includes(flag);
|
|
6
|
+
}
|
|
7
|
+
function parseOptionValue(args, option) {
|
|
8
|
+
const idx = args.indexOf(option);
|
|
9
|
+
if (idx === -1)
|
|
10
|
+
return null;
|
|
11
|
+
const v = args[idx + 1];
|
|
12
|
+
if (!v || v.startsWith("--"))
|
|
13
|
+
return null;
|
|
14
|
+
return v;
|
|
15
|
+
}
|
|
16
|
+
function parseToolText(result) {
|
|
17
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
18
|
+
return JSON.parse(text);
|
|
19
|
+
}
|
|
20
|
+
export async function appliedPolicies(args) {
|
|
21
|
+
const asJson = parseFlag(args, "--json");
|
|
22
|
+
const showMarkdown = parseFlag(args, "--markdown");
|
|
23
|
+
if (parseFlag(args, "--help") || parseFlag(args, "-h")) {
|
|
24
|
+
console.log(`
|
|
25
|
+
Usage:
|
|
26
|
+
nexarch applied-policies [--pack <packCode>] [--markdown] [--json]
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
--pack <code> Filter to a specific policy pack code
|
|
30
|
+
--markdown Include full document markdown in human output
|
|
31
|
+
--json Print JSON response (always includes markdown)
|
|
32
|
+
`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const packCode = parseOptionValue(args, "--pack") ?? parseOptionValue(args, "--pack-code");
|
|
36
|
+
const creds = requireCredentials();
|
|
37
|
+
const raw = await callMcpTool("nexarch_get_applied_policies", { ...(packCode ? { packCode } : {}) }, { companyId: creds.companyId });
|
|
38
|
+
const result = parseToolText(raw);
|
|
39
|
+
if (asJson) {
|
|
40
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
console.log(`Applied policies${packCode ? ` (pack: ${packCode})` : ""}`);
|
|
44
|
+
if (result.policyBundleHash)
|
|
45
|
+
console.log(`Bundle hash: ${result.policyBundleHash}`);
|
|
46
|
+
console.log(`Documents: ${result.policyCount ?? 0}`);
|
|
47
|
+
for (const pack of result.policies ?? []) {
|
|
48
|
+
console.log(`\n[${pack.packCode}] ${pack.packName} — v${pack.installedVersion}`);
|
|
49
|
+
for (const doc of pack.documents ?? []) {
|
|
50
|
+
console.log(` - ${doc.title} (${doc.code})`);
|
|
51
|
+
if (showMarkdown && doc.contentMarkdown) {
|
|
52
|
+
const indented = doc.contentMarkdown.split("\n").map((l) => ` ${l}`).join("\n");
|
|
53
|
+
console.log(indented);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
3
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
4
|
+
function parseFlag(args, flag) {
|
|
5
|
+
return args.includes(flag);
|
|
6
|
+
}
|
|
7
|
+
function parseToolText(result) {
|
|
8
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
9
|
+
return JSON.parse(text);
|
|
10
|
+
}
|
|
11
|
+
export async function governanceSummary(args) {
|
|
12
|
+
const asJson = parseFlag(args, "--json");
|
|
13
|
+
if (parseFlag(args, "--help") || parseFlag(args, "-h")) {
|
|
14
|
+
console.log(`
|
|
15
|
+
Usage:
|
|
16
|
+
nexarch governance-summary [--json]
|
|
17
|
+
|
|
18
|
+
Returns review queue counts, graph stats, and a per-application policy
|
|
19
|
+
audit rollup (latest run status, pass/partial/fail counts).
|
|
20
|
+
`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const creds = requireCredentials();
|
|
24
|
+
const raw = await callMcpTool("nexarch_get_governance_summary", { companyId: creds.companyId }, { companyId: creds.companyId });
|
|
25
|
+
const result = parseToolText(raw);
|
|
26
|
+
if (asJson) {
|
|
27
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log("Governance summary");
|
|
31
|
+
const review = result.reviewQueue ?? {};
|
|
32
|
+
console.log(` Review queue: ${review.pending_entities ?? 0} entities, ${review.pending_relationships ?? 0} relationships`);
|
|
33
|
+
console.log(` Graph: ${result.graphEntityCount ?? 0} entities, ${result.graphRelationshipCount ?? 0} relationships (${result.architectureFactCount ?? 0} facts)`);
|
|
34
|
+
console.log(` Canonical coverage: ${result.canonicalCoverageOverallPct ?? 0}% overall ` +
|
|
35
|
+
`(entities ${result.canonicalCoverageEntityPct ?? 0}%, relationships ${result.canonicalCoverageRelationshipPct ?? 0}%)`);
|
|
36
|
+
console.log(` Canonical registry size: ${result.canonicalRegistryCount ?? 0}`);
|
|
37
|
+
const audit = result.policyAudit;
|
|
38
|
+
if (audit) {
|
|
39
|
+
console.log("\nPolicy audit rollup");
|
|
40
|
+
console.log(` Applications: ${audit.totalApplications} (audited ${audit.appsAudited}, missing audit ${audit.appsWithoutAudit})`);
|
|
41
|
+
console.log(` With failures: ${audit.appsWithFailures}, with partials only: ${audit.appsWithPartials}, clean: ${audit.appsClean}`);
|
|
42
|
+
if (audit.applications.length > 0) {
|
|
43
|
+
console.log("\n Per application:");
|
|
44
|
+
for (const app of audit.applications) {
|
|
45
|
+
if (!app.latestRunId) {
|
|
46
|
+
console.log(` - ${app.applicationName} (${app.applicationEntityRef}): no audit run`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
console.log(` - ${app.applicationName} (${app.applicationEntityRef}): ${app.latestRunStatus} — ` +
|
|
50
|
+
`${app.passCount ?? 0} pass, ${app.partialCount ?? 0} partial, ${app.failCount ?? 0} fail` +
|
|
51
|
+
(app.totalRules ? ` of ${app.totalRules}` : "") +
|
|
52
|
+
(app.completedAt ? ` (completed ${app.completedAt})` : ""));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1490,7 +1490,8 @@ export async function initProject(args) {
|
|
|
1490
1490
|
// Upsert entities (chunked for progressive feedback)
|
|
1491
1491
|
const entityChunks = chunkArray(entities, Math.max(1, upsertBatchSize));
|
|
1492
1492
|
const entitiesResult = {
|
|
1493
|
-
summary: { requested: 0, succeeded: 0, failed: 0 },
|
|
1493
|
+
summary: { requested: 0, succeeded: 0, failed: 0, preserved: 0 },
|
|
1494
|
+
preserved: [],
|
|
1494
1495
|
errors: [],
|
|
1495
1496
|
};
|
|
1496
1497
|
logProgress("upsert.entities.start", `count=${entities.length}, batches=${entityChunks.length}, batchSize=${Math.max(1, upsertBatchSize)}`);
|
|
@@ -1511,7 +1512,10 @@ export async function initProject(args) {
|
|
|
1511
1512
|
}
|
|
1512
1513
|
entitiesResult.summary.requested = Number(entitiesResult.summary.requested ?? 0) + Number(chunkResult.summary?.requested ?? chunk.length);
|
|
1513
1514
|
entitiesResult.summary.succeeded = Number(entitiesResult.summary.succeeded ?? 0) + Number(chunkResult.summary?.succeeded ?? 0);
|
|
1515
|
+
entitiesResult.summary.preserved = Number(entitiesResult.summary.preserved ?? 0) + Number(chunkResult.summary?.preserved ?? 0);
|
|
1514
1516
|
entitiesResult.summary.failed = Number(entitiesResult.summary.failed ?? 0) + Number(chunkResult.summary?.failed ?? 0);
|
|
1517
|
+
if (chunkResult.preserved?.length)
|
|
1518
|
+
entitiesResult.preserved.push(...chunkResult.preserved);
|
|
1515
1519
|
if (chunkResult.errors?.length)
|
|
1516
1520
|
entitiesResult.errors.push(...chunkResult.errors);
|
|
1517
1521
|
logProgress("upsert.entities.batch.done", `${i + 1}/${entityChunks.length} succeeded=${chunkResult.summary?.succeeded ?? 0}, failed=${chunkResult.summary?.failed ?? 0}`);
|
|
@@ -1620,11 +1624,26 @@ export async function initProject(args) {
|
|
|
1620
1624
|
addRelationship: `nexarch add-relationship --from "decision_record:${projectSlug}_<adr_slug>" --to "${projectExternalKey}" --type decides`,
|
|
1621
1625
|
},
|
|
1622
1626
|
});
|
|
1627
|
+
const preservedEntities = entitiesResult.preserved ?? [];
|
|
1628
|
+
const nothingWritten = (entitiesResult.summary?.succeeded ?? 0) === 0;
|
|
1629
|
+
const status = refreshMode && nothingWritten && preservedEntities.length > 0
|
|
1630
|
+
? "review_enrichment"
|
|
1631
|
+
: "enrichment_required";
|
|
1623
1632
|
return {
|
|
1624
|
-
status
|
|
1625
|
-
note:
|
|
1626
|
-
? "
|
|
1627
|
-
:
|
|
1633
|
+
status,
|
|
1634
|
+
note: status === "review_enrichment"
|
|
1635
|
+
? "No new skeletons were written — all entities were already enriched and preserved. Review the preservedEntities list and confirm scan values match. Update with nexarch update-entity only if something has genuinely changed."
|
|
1636
|
+
: refreshMode
|
|
1637
|
+
? "Execute ALL pendingSteps. In refresh mode, compare graphState vs scanState to identify gaps — do not blindly remove relationships the scanner missed; the scanner cannot detect platforms, integrations, data assets, or application_functions."
|
|
1638
|
+
: "Execute ALL pendingSteps before reporting the project as registered. Do not pause or ask for confirmation between steps.",
|
|
1639
|
+
...(refreshMode && preservedEntities.length > 0
|
|
1640
|
+
? {
|
|
1641
|
+
preservedEntities: {
|
|
1642
|
+
note: "These entities already have enriched content and were NOT overwritten by the scan. Review the scan values — if anything has genuinely changed, update with nexarch update-entity.",
|
|
1643
|
+
entities: preservedEntities,
|
|
1644
|
+
},
|
|
1645
|
+
}
|
|
1646
|
+
: {}),
|
|
1628
1647
|
projectEntity: {
|
|
1629
1648
|
externalKey: projectExternalKey,
|
|
1630
1649
|
entityType: entityTypeOverride,
|
|
@@ -1709,11 +1728,19 @@ export async function initProject(args) {
|
|
|
1709
1728
|
// This is addressed to the *calling agent* (Claude Code, Codex, etc.) and tells it
|
|
1710
1729
|
// to act inline in this same session — not to queue enrichment for later.
|
|
1711
1730
|
function buildEnrichmentDirective() {
|
|
1731
|
+
const preservedEntities = entitiesResult.preserved ?? [];
|
|
1712
1732
|
const lines = [];
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1733
|
+
if (refreshMode) {
|
|
1734
|
+
lines.push("─── REFRESH REVIEW REQUIRED ──────────────────────────────────────────────");
|
|
1735
|
+
lines.push("update-project refreshed the scan. Review enriched entities and complete any");
|
|
1736
|
+
lines.push("new skeletons below — do not ask the user for permission, just execute.");
|
|
1737
|
+
}
|
|
1738
|
+
else {
|
|
1739
|
+
lines.push("─── ENRICHMENT REQUIRED ─────────────────────────────────────────────────");
|
|
1740
|
+
lines.push("init-project wrote a skeleton. Complete enrichment below — do not ask the");
|
|
1741
|
+
lines.push("user for permission, do not summarise and pause, just execute the steps.");
|
|
1742
|
+
lines.push("Do NOT report the project as registered until enrichment is done.");
|
|
1743
|
+
}
|
|
1717
1744
|
lines.push("");
|
|
1718
1745
|
lines.push(`PROJECT : ${projectExternalKey}`);
|
|
1719
1746
|
lines.push(`DIR : ${dir}`);
|
|
@@ -1759,6 +1786,19 @@ export async function initProject(args) {
|
|
|
1759
1786
|
if (unresolvedItems.length > 20)
|
|
1760
1787
|
lines.push(` … and ${unresolvedItems.length - 20} more`);
|
|
1761
1788
|
}
|
|
1789
|
+
if (refreshMode && preservedEntities.length > 0) {
|
|
1790
|
+
lines.push("");
|
|
1791
|
+
lines.push(`ENRICHED (${preservedEntities.length} — already have descriptions; not overwritten by scan):`);
|
|
1792
|
+
lines.push(" Review each entry. If the scan detected a real change, run update-entity manually.");
|
|
1793
|
+
for (const p of preservedEntities) {
|
|
1794
|
+
lines.push(` ${p.externalKey ?? "?"}`);
|
|
1795
|
+
lines.push(` current : name="${p.currentValues?.name ?? ""}" subtype="${p.currentValues?.entitySubtypeCode ?? ""}"`);
|
|
1796
|
+
lines.push(` scan : name="${p.scanValues?.name ?? ""}" subtype="${p.scanValues?.entitySubtypeCode ?? ""}"`);
|
|
1797
|
+
if (p.currentValues?.name !== p.scanValues?.name || p.currentValues?.entitySubtypeCode !== p.scanValues?.entitySubtypeCode) {
|
|
1798
|
+
lines.push(` ⚠ values differ — review and update if the change is real`);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1762
1802
|
lines.push("");
|
|
1763
1803
|
lines.push("THEN_RUN (execute these steps — do not pause or ask for confirmation):");
|
|
1764
1804
|
let step = 1;
|
|
@@ -1808,9 +1848,10 @@ export async function initProject(args) {
|
|
|
1808
1848
|
return lines.join("\n");
|
|
1809
1849
|
}
|
|
1810
1850
|
const enrichmentRequired = buildEnrichmentPayload();
|
|
1851
|
+
const outputStatus = enrichmentRequired.status;
|
|
1811
1852
|
const output = {
|
|
1812
1853
|
ok: Number(entitiesResult.summary?.failed ?? 0) === 0,
|
|
1813
|
-
status:
|
|
1854
|
+
status: outputStatus,
|
|
1814
1855
|
mode: refreshMode ? "refresh" : "init",
|
|
1815
1856
|
project: { name: displayName, externalKey: projectExternalKey, entityType: entityTypeOverride, detectedEcosystems },
|
|
1816
1857
|
entities: entitiesResult.summary ?? {},
|
|
@@ -1848,9 +1889,10 @@ export async function initProject(args) {
|
|
|
1848
1889
|
}
|
|
1849
1890
|
console.log(`\nDone.`);
|
|
1850
1891
|
console.log(` Mode : ${refreshMode ? "refresh (update-project)" : "init"}`);
|
|
1851
|
-
|
|
1892
|
+
const preservedCount = output.entities.preserved ?? 0;
|
|
1893
|
+
console.log(` Entities : ${output.entities.succeeded ?? 0} written, ${preservedCount > 0 ? `${preservedCount} preserved (enriched), ` : ""}${output.entities.failed ?? 0} failed`);
|
|
1852
1894
|
console.log(` Relationships: ${output.relationships.succeeded ?? 0} written`);
|
|
1853
|
-
console.log(
|
|
1895
|
+
console.log(` Status : ${output.status === "review_enrichment" ? "all enriched; review preserved entities" : "skeleton created; enrichment pending"}`);
|
|
1854
1896
|
if (output.metrics.relationshipsSkippedAsDuplicate > 0) {
|
|
1855
1897
|
console.log(` Deduped rels : ${output.metrics.relationshipsSkippedAsDuplicate} skipped as duplicates before upsert`);
|
|
1856
1898
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import process from "process";
|
|
2
|
+
import { requireCredentials } from "../lib/credentials.js";
|
|
3
|
+
import { callMcpTool } from "../lib/mcp.js";
|
|
4
|
+
function parseFlag(args, flag) {
|
|
5
|
+
return args.includes(flag);
|
|
6
|
+
}
|
|
7
|
+
function parseOptionValue(args, option) {
|
|
8
|
+
const idx = args.indexOf(option);
|
|
9
|
+
if (idx === -1)
|
|
10
|
+
return null;
|
|
11
|
+
const v = args[idx + 1];
|
|
12
|
+
if (!v || v.startsWith("--"))
|
|
13
|
+
return null;
|
|
14
|
+
return v;
|
|
15
|
+
}
|
|
16
|
+
function parseToolText(result) {
|
|
17
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
18
|
+
return JSON.parse(text);
|
|
19
|
+
}
|
|
20
|
+
export async function policyAuditResults(args) {
|
|
21
|
+
const asJson = parseFlag(args, "--json");
|
|
22
|
+
if (parseFlag(args, "--help") || parseFlag(args, "-h")) {
|
|
23
|
+
console.log(`
|
|
24
|
+
Usage:
|
|
25
|
+
nexarch policy-audit-results --entity <applicationEntityRef> [--limit <1-10>] [--json]
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
--entity <key> Required application reference (e.g. application:my-service).
|
|
29
|
+
Aliases: --entity-ref, --application-ref, --application-key
|
|
30
|
+
--limit <n> Number of most recent runs to return (default 1, max 10)
|
|
31
|
+
--json Print JSON response
|
|
32
|
+
`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const entity = parseOptionValue(args, "--entity") ??
|
|
36
|
+
parseOptionValue(args, "--entity-ref") ??
|
|
37
|
+
parseOptionValue(args, "--application-ref") ??
|
|
38
|
+
parseOptionValue(args, "--application-key");
|
|
39
|
+
if (!entity) {
|
|
40
|
+
console.error("error: --entity <applicationEntityRef> is required (e.g. application:my-service)");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const limitRaw = parseOptionValue(args, "--limit");
|
|
44
|
+
const limit = limitRaw ? Number.parseInt(limitRaw, 10) : null;
|
|
45
|
+
if (limitRaw && (!Number.isFinite(limit) || (limit ?? 0) < 1)) {
|
|
46
|
+
console.error("error: --limit must be a positive integer");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const creds = requireCredentials();
|
|
50
|
+
const raw = await callMcpTool("nexarch_get_policy_audit_results", {
|
|
51
|
+
applicationEntityRef: entity,
|
|
52
|
+
...(limit ? { limit } : {}),
|
|
53
|
+
companyId: creds.companyId,
|
|
54
|
+
}, { companyId: creds.companyId });
|
|
55
|
+
const result = parseToolText(raw);
|
|
56
|
+
if (asJson) {
|
|
57
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (result.ok === false) {
|
|
61
|
+
console.error(`Policy audit results failed${result.error ? `: ${result.error}` : ""}`);
|
|
62
|
+
if (result.hint)
|
|
63
|
+
console.error(result.hint);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const label = result.applicationName
|
|
67
|
+
? `${result.applicationName} (${result.applicationEntityRef ?? entity})`
|
|
68
|
+
: (result.applicationEntityRef ?? entity);
|
|
69
|
+
console.log(`Policy audit results for ${label}`);
|
|
70
|
+
const runs = result.runs ?? [];
|
|
71
|
+
if (runs.length === 0) {
|
|
72
|
+
console.log("No audit runs found.");
|
|
73
|
+
if (result.hint)
|
|
74
|
+
console.log(result.hint);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (const run of runs) {
|
|
78
|
+
const summary = run.summary ?? {};
|
|
79
|
+
console.log(`\nRun ${run.runId} — ${run.status}`);
|
|
80
|
+
if (run.startedAt)
|
|
81
|
+
console.log(` Started: ${run.startedAt}`);
|
|
82
|
+
if (run.completedAt)
|
|
83
|
+
console.log(` Completed: ${run.completedAt}`);
|
|
84
|
+
if (summary && (summary.passCount !== undefined || summary.failCount !== undefined)) {
|
|
85
|
+
console.log(` Summary: ${summary.passCount ?? 0} pass, ${summary.partialCount ?? 0} partial, ${summary.failCount ?? 0} fail` +
|
|
86
|
+
(summary.totalRules !== undefined ? ` (of ${summary.totalRules})` : ""));
|
|
87
|
+
}
|
|
88
|
+
for (const control of run.controls ?? []) {
|
|
89
|
+
console.log(`\n - ${control.controlName} (${control.controlId})`);
|
|
90
|
+
for (const rule of control.rules ?? []) {
|
|
91
|
+
const level = rule.requirementLevel ? ` [${rule.requirementLevel}]` : "";
|
|
92
|
+
console.log(` • [${rule.result}] ${rule.ruleName}${level} (${rule.ruleId})`);
|
|
93
|
+
if (rule.rationale)
|
|
94
|
+
console.log(` ${rule.rationale}`);
|
|
95
|
+
if (Array.isArray(rule.missingRequirements) && rule.missingRequirements.length > 0) {
|
|
96
|
+
for (const m of rule.missingRequirements) {
|
|
97
|
+
console.log(` - missing: ${String(m)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,9 @@ import { commandClaim } from "./commands/command-claim.js";
|
|
|
21
21
|
import { policyControls } from "./commands/policy-controls.js";
|
|
22
22
|
import { policyAuditTemplate } from "./commands/policy-audit-template.js";
|
|
23
23
|
import { policyAuditSubmit } from "./commands/policy-audit-submit.js";
|
|
24
|
+
import { policyAuditResults } from "./commands/policy-audit-results.js";
|
|
25
|
+
import { appliedPolicies } from "./commands/applied-policies.js";
|
|
26
|
+
import { governanceSummary } from "./commands/governance-summary.js";
|
|
24
27
|
const [, , command, ...args] = process.argv;
|
|
25
28
|
const commands = {
|
|
26
29
|
login,
|
|
@@ -46,6 +49,9 @@ const commands = {
|
|
|
46
49
|
"policy-controls": policyControls,
|
|
47
50
|
"policy-audit-template": policyAuditTemplate,
|
|
48
51
|
"policy-audit-submit": policyAuditSubmit,
|
|
52
|
+
"policy-audit-results": policyAuditResults,
|
|
53
|
+
"applied-policies": appliedPolicies,
|
|
54
|
+
"governance-summary": governanceSummary,
|
|
49
55
|
};
|
|
50
56
|
async function main() {
|
|
51
57
|
if (command === "agent") {
|
|
@@ -206,6 +212,20 @@ Usage:
|
|
|
206
212
|
--findings-json <json-array>
|
|
207
213
|
--findings-file <path.json>
|
|
208
214
|
--json
|
|
215
|
+
nexarch policy-audit-results
|
|
216
|
+
Retrieve stored results of previous policy audits for an application.
|
|
217
|
+
Options: --entity <applicationEntityRef> (required)
|
|
218
|
+
--limit <1-10> (default 1)
|
|
219
|
+
--json
|
|
220
|
+
nexarch applied-policies
|
|
221
|
+
List policy documents applied to this company account.
|
|
222
|
+
Options: --pack <packCode> filter to a specific pack
|
|
223
|
+
--markdown include full document markdown
|
|
224
|
+
--json
|
|
225
|
+
nexarch governance-summary
|
|
226
|
+
Print review queue, graph stats, and per-application policy
|
|
227
|
+
audit rollup (latest run status, pass/partial/fail counts).
|
|
228
|
+
Options: --json
|
|
209
229
|
`);
|
|
210
230
|
process.exit(command ? 1 : 0);
|
|
211
231
|
}
|
package/dist/lib/mcp.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import https from "https";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname, join } from "path";
|
|
2
5
|
import { requireCredentials } from "./credentials.js";
|
|
3
6
|
const MCP_GATEWAY_URL = "https://mcp.nexarch.ai";
|
|
7
|
+
function readCliVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const pkgPath = join(here, "..", "..", "package.json");
|
|
11
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
12
|
+
return pkg.version ?? "0.0.0";
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return "0.0.0";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const CLI_VERSION = readCliVersion();
|
|
4
19
|
const REQUEST_TIMEOUT_MS = Number.parseInt(process.env.NEXARCH_MCP_TIMEOUT_MS ?? "90000", 10) || 90_000;
|
|
5
20
|
const REQUEST_RETRIES = Math.max(0, Number.parseInt(process.env.NEXARCH_MCP_RETRIES ?? "2", 10) || 2);
|
|
6
21
|
function sleep(ms) {
|
|
@@ -97,7 +112,7 @@ export async function mcpInitialize(options = {}) {
|
|
|
97
112
|
return callMcpRpc("initialize", {
|
|
98
113
|
protocolVersion: "2024-11-05",
|
|
99
114
|
capabilities: {},
|
|
100
|
-
clientInfo: { name: "nexarch-cli", version:
|
|
115
|
+
clientInfo: { name: "nexarch-cli", version: CLI_VERSION },
|
|
101
116
|
}, options);
|
|
102
117
|
}
|
|
103
118
|
export async function mcpListTools(options = {}) {
|