nexarch 0.1.3 → 0.1.5
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/README.md +1 -0
- package/dist/commands/init-agent.js +86 -0
- package/dist/commands/login.js +3 -1
- package/dist/index.js +3 -0
- package/dist/lib/mcp.js +20 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ npx nexarch setup
|
|
|
19
19
|
| `nexarch setup` | Auto-configure detected MCP clients |
|
|
20
20
|
| `nexarch mcp-config [client]` | Print config block for manual setup (`claude-desktop`, `cursor`, `windsurf`) |
|
|
21
21
|
| `nexarch mcp-proxy` | stdio→HTTP bridge used internally by MCP clients |
|
|
22
|
+
| `nexarch init-agent [--json] [--strict]` | Run onboarding handshake checks (initialize, tools, policy bootstrap, ingest contract) |
|
|
22
23
|
|
|
23
24
|
## Requirements
|
|
24
25
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
|
|
2
|
+
function parseFlag(args, flag) {
|
|
3
|
+
return args.includes(flag);
|
|
4
|
+
}
|
|
5
|
+
function parseToolText(result) {
|
|
6
|
+
const text = result.content?.[0]?.text ?? "{}";
|
|
7
|
+
return JSON.parse(text);
|
|
8
|
+
}
|
|
9
|
+
export async function initAgent(args) {
|
|
10
|
+
const asJson = parseFlag(args, "--json");
|
|
11
|
+
const strict = parseFlag(args, "--strict");
|
|
12
|
+
const checks = [];
|
|
13
|
+
const init = await mcpInitialize();
|
|
14
|
+
checks.push({
|
|
15
|
+
name: "mcp.initialize",
|
|
16
|
+
ok: true,
|
|
17
|
+
detail: `${init.serverInfo?.name ?? "unknown"}@${init.serverInfo?.version ?? "unknown"}`,
|
|
18
|
+
});
|
|
19
|
+
const tools = await mcpListTools();
|
|
20
|
+
const toolNames = new Set(tools.map((t) => t.name));
|
|
21
|
+
const required = [
|
|
22
|
+
"nexarch_get_applied_policies",
|
|
23
|
+
"nexarch_get_ingest_contract",
|
|
24
|
+
"nexarch_upsert_entities",
|
|
25
|
+
"nexarch_upsert_relationships",
|
|
26
|
+
];
|
|
27
|
+
const missing = required.filter((name) => !toolNames.has(name));
|
|
28
|
+
checks.push({
|
|
29
|
+
name: "mcp.tools.list",
|
|
30
|
+
ok: missing.length === 0,
|
|
31
|
+
detail: missing.length ? `missing: ${missing.join(", ")}` : `required tools present (${required.length})`,
|
|
32
|
+
});
|
|
33
|
+
const policiesRaw = await callMcpTool("nexarch_get_applied_policies", {});
|
|
34
|
+
const policies = parseToolText(policiesRaw);
|
|
35
|
+
checks.push({
|
|
36
|
+
name: "governance.bootstrap",
|
|
37
|
+
ok: Boolean(policies.policyBundleHash),
|
|
38
|
+
detail: policies.policyBundleHash
|
|
39
|
+
? `policyBundleHash=${policies.policyBundleHash.slice(0, 12)}… policyCount=${policies.policyCount ?? 0}`
|
|
40
|
+
: "missing policyBundleHash",
|
|
41
|
+
});
|
|
42
|
+
const contractRaw = await callMcpTool("nexarch_get_ingest_contract", {});
|
|
43
|
+
const contract = parseToolText(contractRaw);
|
|
44
|
+
checks.push({
|
|
45
|
+
name: "ingest.contract",
|
|
46
|
+
ok: Boolean(contract.contractVersion),
|
|
47
|
+
detail: `version=${contract.contractVersion ?? "unknown"}; entities=${contract.ontology?.entityCodes?.length ?? 0}; relationships=${contract.ontology?.relationshipCodes?.length ?? 0}`,
|
|
48
|
+
});
|
|
49
|
+
const allPassed = checks.every((c) => c.ok);
|
|
50
|
+
if (asJson) {
|
|
51
|
+
const output = {
|
|
52
|
+
ok: strict ? allPassed : true,
|
|
53
|
+
passed: allPassed,
|
|
54
|
+
strict,
|
|
55
|
+
checks,
|
|
56
|
+
summary: {
|
|
57
|
+
total: checks.length,
|
|
58
|
+
ok: checks.filter((c) => c.ok).length,
|
|
59
|
+
failed: checks.filter((c) => !c.ok).length,
|
|
60
|
+
},
|
|
61
|
+
policyBundleHash: policies.policyBundleHash ?? null,
|
|
62
|
+
contractVersion: contract.contractVersion ?? null,
|
|
63
|
+
};
|
|
64
|
+
process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
|
|
65
|
+
if (strict && !allPassed)
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log("Running agent onboarding handshake…\n");
|
|
70
|
+
for (const check of checks) {
|
|
71
|
+
console.log(`${check.ok ? "✓" : "✗"} ${check.name}`);
|
|
72
|
+
if (check.detail)
|
|
73
|
+
console.log(` ${check.detail}`);
|
|
74
|
+
}
|
|
75
|
+
console.log("");
|
|
76
|
+
if (allPassed) {
|
|
77
|
+
console.log("✅ Agent handshake completed. Ready for policy-aware ingest.");
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log("⚠ Handshake completed with issues.");
|
|
81
|
+
if (strict) {
|
|
82
|
+
console.log("Strict mode enabled, exiting non-zero.");
|
|
83
|
+
process.exitCode = 1;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/commands/login.js
CHANGED
|
@@ -29,7 +29,9 @@ function openBrowser(url) {
|
|
|
29
29
|
const [cmd, args] = process.platform === "darwin"
|
|
30
30
|
? ["open", [url]]
|
|
31
31
|
: process.platform === "win32"
|
|
32
|
-
|
|
32
|
+
// Avoid cmd parsing issues with '&' in query strings (e.g. OAuth state).
|
|
33
|
+
// rundll32 reliably opens the full URL without truncating parameters.
|
|
34
|
+
? ["rundll32", ["url.dll,FileProtocolHandler", url]]
|
|
33
35
|
: ["xdg-open", [url]];
|
|
34
36
|
execFile(cmd, args, (err) => {
|
|
35
37
|
if (err) {
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { status } from "./commands/status.js";
|
|
|
5
5
|
import { setup } from "./commands/setup.js";
|
|
6
6
|
import { mcpConfig } from "./commands/mcp-config.js";
|
|
7
7
|
import { mcpProxy } from "./commands/mcp-proxy.js";
|
|
8
|
+
import { initAgent } from "./commands/init-agent.js";
|
|
8
9
|
const [, , command, ...args] = process.argv;
|
|
9
10
|
const commands = {
|
|
10
11
|
login,
|
|
@@ -13,6 +14,7 @@ const commands = {
|
|
|
13
14
|
setup,
|
|
14
15
|
"mcp-config": mcpConfig,
|
|
15
16
|
"mcp-proxy": mcpProxy,
|
|
17
|
+
"init-agent": initAgent,
|
|
16
18
|
};
|
|
17
19
|
async function main() {
|
|
18
20
|
const handler = commands[command ?? ""];
|
|
@@ -27,6 +29,7 @@ Usage:
|
|
|
27
29
|
nexarch setup Auto-configure your MCP client (Claude Desktop, Cursor, etc.)
|
|
28
30
|
nexarch mcp-config Print MCP server config block for manual setup
|
|
29
31
|
nexarch mcp-proxy Run as stdio MCP proxy (used by MCP clients)
|
|
32
|
+
nexarch init-agent Run onboarding handshake checks (tools/policies/contract)
|
|
30
33
|
`);
|
|
31
34
|
process.exit(command ? 1 : 0);
|
|
32
35
|
}
|
package/dist/lib/mcp.js
CHANGED
|
@@ -2,13 +2,13 @@ import https from "https";
|
|
|
2
2
|
import { requireCredentials } from "./credentials.js";
|
|
3
3
|
const MCP_GATEWAY_URL = "https://mcp.nexarch.ai";
|
|
4
4
|
const REQUEST_TIMEOUT_MS = 30 * 1000;
|
|
5
|
-
|
|
5
|
+
async function callMcpRpc(method, params = {}) {
|
|
6
6
|
const creds = requireCredentials();
|
|
7
7
|
const body = JSON.stringify({
|
|
8
8
|
jsonrpc: "2.0",
|
|
9
9
|
id: 1,
|
|
10
|
-
method
|
|
11
|
-
params
|
|
10
|
+
method,
|
|
11
|
+
params,
|
|
12
12
|
});
|
|
13
13
|
return new Promise((resolve, reject) => {
|
|
14
14
|
const url = new URL("/mcp", MCP_GATEWAY_URL);
|
|
@@ -19,7 +19,7 @@ export async function callMcpTool(toolName, toolArgs = {}) {
|
|
|
19
19
|
method: "POST",
|
|
20
20
|
headers: {
|
|
21
21
|
"Content-Type": "application/json",
|
|
22
|
-
|
|
22
|
+
Authorization: `Bearer ${creds.token}`,
|
|
23
23
|
"x-company-id": creds.companyId,
|
|
24
24
|
"Content-Length": Buffer.byteLength(body),
|
|
25
25
|
},
|
|
@@ -34,7 +34,7 @@ export async function callMcpTool(toolName, toolArgs = {}) {
|
|
|
34
34
|
if (json.error) {
|
|
35
35
|
reject(new Error(json.error.message));
|
|
36
36
|
}
|
|
37
|
-
else if (json.result) {
|
|
37
|
+
else if (json.result !== undefined) {
|
|
38
38
|
resolve(json.result);
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
@@ -54,6 +54,20 @@ export async function callMcpTool(toolName, toolArgs = {}) {
|
|
|
54
54
|
req.end();
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
|
+
export async function callMcpTool(toolName, toolArgs = {}) {
|
|
58
|
+
return callMcpRpc("tools/call", { name: toolName, arguments: toolArgs });
|
|
59
|
+
}
|
|
60
|
+
export async function mcpInitialize() {
|
|
61
|
+
return callMcpRpc("initialize", {
|
|
62
|
+
protocolVersion: "2024-11-05",
|
|
63
|
+
capabilities: {},
|
|
64
|
+
clientInfo: { name: "nexarch-cli", version: "0.1.4" },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export async function mcpListTools() {
|
|
68
|
+
const result = await callMcpRpc("tools/list", {});
|
|
69
|
+
return result.tools ?? [];
|
|
70
|
+
}
|
|
57
71
|
export async function forwardToGateway(token, companyId, body) {
|
|
58
72
|
return new Promise((resolve, reject) => {
|
|
59
73
|
const url = new URL("/mcp", MCP_GATEWAY_URL);
|
|
@@ -64,7 +78,7 @@ export async function forwardToGateway(token, companyId, body) {
|
|
|
64
78
|
method: "POST",
|
|
65
79
|
headers: {
|
|
66
80
|
"Content-Type": "application/json",
|
|
67
|
-
|
|
81
|
+
Authorization: `Bearer ${token}`,
|
|
68
82
|
"x-company-id": companyId,
|
|
69
83
|
"Content-Length": Buffer.byteLength(body),
|
|
70
84
|
},
|