nexarch 0.1.8 → 0.1.11
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 +9 -2
- package/dist/commands/init-agent.js +18 -10
- package/dist/commands/login.js +27 -5
- package/dist/commands/status.js +2 -3
- package/dist/index.js +2 -1
- package/dist/lib/mcp.js +10 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,9 +13,9 @@ npx nexarch setup
|
|
|
13
13
|
|
|
14
14
|
| Command | Description |
|
|
15
15
|
|---|---|
|
|
16
|
-
| `nexarch login` | Authenticate via browser and store credentials |
|
|
16
|
+
| `nexarch login [--company <id>]` | Authenticate via browser and store company-scoped credentials; prompts for company when multiple memberships exist |
|
|
17
17
|
| `nexarch logout` | Remove local credentials |
|
|
18
|
-
| `nexarch status` | Check connection and show architecture summary |
|
|
18
|
+
| `nexarch status` | Check connection and show architecture summary for the company selected at login |
|
|
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 |
|
|
@@ -23,6 +23,13 @@ npx nexarch setup
|
|
|
23
23
|
| `nexarch init-agent --bind-to-external-key <key> [--bind-relationship-type <code>]` | Optionally bind the agent node to an existing graph external key |
|
|
24
24
|
| `nexarch init-agent` (default behavior) | Also upserts technology component entities (host, OS, Node.js runtime) and links them to the agent |
|
|
25
25
|
|
|
26
|
+
## Company context behavior
|
|
27
|
+
|
|
28
|
+
- Company is selected during `nexarch login`.
|
|
29
|
+
- If your user has one active company, login auto-selects it.
|
|
30
|
+
- If your user has multiple active companies, login requires explicit selection.
|
|
31
|
+
- To switch company later, run `nexarch login` again and pick another company.
|
|
32
|
+
|
|
26
33
|
## Requirements
|
|
27
34
|
|
|
28
35
|
- Node.js 18 or later
|
|
@@ -2,7 +2,7 @@ import { arch, hostname, platform, release, type as osType, userInfo } from "os"
|
|
|
2
2
|
import process from "process";
|
|
3
3
|
import { requireCredentials } from "../lib/credentials.js";
|
|
4
4
|
import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
|
|
5
|
-
const CLI_VERSION = "0.1.
|
|
5
|
+
const CLI_VERSION = "0.1.11";
|
|
6
6
|
const AGENT_ENTITY_TYPE = "agent";
|
|
7
7
|
const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
|
|
8
8
|
function parseFlag(args, flag) {
|
|
@@ -80,7 +80,7 @@ async function emitInitObservation(params) {
|
|
|
80
80
|
waivers: [],
|
|
81
81
|
},
|
|
82
82
|
},
|
|
83
|
-
});
|
|
83
|
+
}, { companyId: params.companyId });
|
|
84
84
|
}
|
|
85
85
|
catch {
|
|
86
86
|
// non-fatal telemetry path
|
|
@@ -105,13 +105,14 @@ export async function initAgent(args) {
|
|
|
105
105
|
};
|
|
106
106
|
const checks = [];
|
|
107
107
|
const creds = requireCredentials();
|
|
108
|
-
const
|
|
108
|
+
const selectedCompanyId = creds.companyId;
|
|
109
|
+
const init = await mcpInitialize({ companyId: selectedCompanyId });
|
|
109
110
|
checks.push({
|
|
110
111
|
name: "mcp.initialize",
|
|
111
112
|
ok: true,
|
|
112
113
|
detail: `${init.serverInfo?.name ?? "unknown"}@${init.serverInfo?.version ?? "unknown"}`,
|
|
113
114
|
});
|
|
114
|
-
const tools = await mcpListTools();
|
|
115
|
+
const tools = await mcpListTools({ companyId: selectedCompanyId });
|
|
115
116
|
const toolNames = new Set(tools.map((t) => t.name));
|
|
116
117
|
const required = [
|
|
117
118
|
"nexarch_get_applied_policies",
|
|
@@ -126,7 +127,7 @@ export async function initAgent(args) {
|
|
|
126
127
|
ok: missing.length === 0,
|
|
127
128
|
detail: missing.length ? `missing: ${missing.join(", ")}` : `required tools present (${required.length})`,
|
|
128
129
|
});
|
|
129
|
-
const policiesRaw = await callMcpTool("nexarch_get_applied_policies", {});
|
|
130
|
+
const policiesRaw = await callMcpTool("nexarch_get_applied_policies", {}, { companyId: selectedCompanyId });
|
|
130
131
|
const policies = parseToolText(policiesRaw);
|
|
131
132
|
checks.push({
|
|
132
133
|
name: "governance.bootstrap",
|
|
@@ -135,7 +136,7 @@ export async function initAgent(args) {
|
|
|
135
136
|
? `policyBundleHash=${policies.policyBundleHash.slice(0, 12)}… policyCount=${policies.policyCount ?? 0}`
|
|
136
137
|
: "missing policyBundleHash",
|
|
137
138
|
});
|
|
138
|
-
const contractRaw = await callMcpTool("nexarch_get_ingest_contract", {});
|
|
139
|
+
const contractRaw = await callMcpTool("nexarch_get_ingest_contract", {}, { companyId: selectedCompanyId });
|
|
139
140
|
const contract = parseToolText(contractRaw);
|
|
140
141
|
checks.push({
|
|
141
142
|
name: "ingest.contract",
|
|
@@ -243,7 +244,7 @@ export async function initAgent(args) {
|
|
|
243
244
|
},
|
|
244
245
|
},
|
|
245
246
|
dryRun: false,
|
|
246
|
-
});
|
|
247
|
+
}, { companyId: selectedCompanyId });
|
|
247
248
|
const upsert = parseToolText(upsertRaw);
|
|
248
249
|
const firstResult = upsert.results?.[0];
|
|
249
250
|
const failed = Number(upsert.summary?.failed ?? 0) > 0;
|
|
@@ -259,6 +260,7 @@ export async function initAgent(args) {
|
|
|
259
260
|
if (!registration.ok) {
|
|
260
261
|
await emitInitObservation({
|
|
261
262
|
agentId,
|
|
263
|
+
companyId: selectedCompanyId,
|
|
262
264
|
policyBundleHash: policies.policyBundleHash,
|
|
263
265
|
message: `init-agent registration failed: ${registration.detail}`,
|
|
264
266
|
confidence: 1,
|
|
@@ -274,6 +276,7 @@ export async function initAgent(args) {
|
|
|
274
276
|
{
|
|
275
277
|
externalKey: hostExternalKey,
|
|
276
278
|
entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
|
|
279
|
+
entitySubtypeCode: "tech_compute",
|
|
277
280
|
name: `Host ${runtime.hostname}`,
|
|
278
281
|
description: "Execution host for registered agent runtimes",
|
|
279
282
|
confidence: 0.95,
|
|
@@ -288,6 +291,7 @@ export async function initAgent(args) {
|
|
|
288
291
|
{
|
|
289
292
|
externalKey: osExternalKey,
|
|
290
293
|
entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
|
|
294
|
+
entitySubtypeCode: "tech_operating_system",
|
|
291
295
|
name: `${runtime.osPlatform} ${runtime.osRelease}`,
|
|
292
296
|
description: "Operating system platform used by registered agents",
|
|
293
297
|
confidence: 0.95,
|
|
@@ -302,6 +306,7 @@ export async function initAgent(args) {
|
|
|
302
306
|
{
|
|
303
307
|
externalKey: nodeExternalKey,
|
|
304
308
|
entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
|
|
309
|
+
entitySubtypeCode: "tech_runtime",
|
|
305
310
|
name: `Node.js ${runtime.nodeVersion}`,
|
|
306
311
|
description: "Node.js runtime used by nexarch-cli agent",
|
|
307
312
|
confidence: 0.95,
|
|
@@ -330,7 +335,7 @@ export async function initAgent(args) {
|
|
|
330
335
|
},
|
|
331
336
|
},
|
|
332
337
|
dryRun: false,
|
|
333
|
-
});
|
|
338
|
+
}, { companyId: selectedCompanyId });
|
|
334
339
|
const techUpsert = parseToolText(techUpsertRaw);
|
|
335
340
|
const techFailed = Number(techUpsert.summary?.failed ?? 0) > 0;
|
|
336
341
|
techComponents = {
|
|
@@ -345,6 +350,7 @@ export async function initAgent(args) {
|
|
|
345
350
|
if (!techComponents.ok) {
|
|
346
351
|
await emitInitObservation({
|
|
347
352
|
agentId,
|
|
353
|
+
companyId: selectedCompanyId,
|
|
348
354
|
policyBundleHash: policies.policyBundleHash,
|
|
349
355
|
message: `init-agent technology component upsert failed: ${techComponents.detail}`,
|
|
350
356
|
confidence: 1,
|
|
@@ -394,7 +400,7 @@ export async function initAgent(args) {
|
|
|
394
400
|
},
|
|
395
401
|
},
|
|
396
402
|
dryRun: false,
|
|
397
|
-
});
|
|
403
|
+
}, { companyId: selectedCompanyId });
|
|
398
404
|
const relUpsert = parseToolText(techRelRaw);
|
|
399
405
|
const relFailed = Number(relUpsert.summary?.failed ?? 0) > 0;
|
|
400
406
|
techRelationships = {
|
|
@@ -409,6 +415,7 @@ export async function initAgent(args) {
|
|
|
409
415
|
if (!techRelationships.ok) {
|
|
410
416
|
await emitInitObservation({
|
|
411
417
|
agentId,
|
|
418
|
+
companyId: selectedCompanyId,
|
|
412
419
|
policyBundleHash: policies.policyBundleHash,
|
|
413
420
|
message: `init-agent technology relationship upsert failed: ${techRelationships.detail}`,
|
|
414
421
|
confidence: 1,
|
|
@@ -449,7 +456,7 @@ export async function initAgent(args) {
|
|
|
449
456
|
},
|
|
450
457
|
},
|
|
451
458
|
dryRun: false,
|
|
452
|
-
});
|
|
459
|
+
}, { companyId: selectedCompanyId });
|
|
453
460
|
const rel = parseToolText(relRaw);
|
|
454
461
|
const relResult = rel.results?.[0];
|
|
455
462
|
const relFailed = Number(rel.summary?.failed ?? 0) > 0;
|
|
@@ -466,6 +473,7 @@ export async function initAgent(args) {
|
|
|
466
473
|
if (!binding.ok) {
|
|
467
474
|
await emitInitObservation({
|
|
468
475
|
agentId,
|
|
476
|
+
companyId: selectedCompanyId,
|
|
469
477
|
policyBundleHash: policies.policyBundleHash,
|
|
470
478
|
message: `init-agent binding failed: ${binding.detail}`,
|
|
471
479
|
confidence: 1,
|
package/dist/commands/login.js
CHANGED
|
@@ -60,6 +60,8 @@ function waitForCallback(port, expectedState) {
|
|
|
60
60
|
const state = url.searchParams.get("state");
|
|
61
61
|
const token = url.searchParams.get("token");
|
|
62
62
|
const companyId = url.searchParams.get("companyId");
|
|
63
|
+
const companyName = url.searchParams.get("companyName") ?? undefined;
|
|
64
|
+
const companyCode = url.searchParams.get("companyCode") ?? undefined;
|
|
63
65
|
const error = url.searchParams.get("error");
|
|
64
66
|
const html = (message) => `<!DOCTYPE html><html><head><meta charset="utf-8"><title>Nexarch CLI</title>
|
|
65
67
|
<style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f8fafc}
|
|
@@ -90,7 +92,7 @@ function waitForCallback(port, expectedState) {
|
|
|
90
92
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
91
93
|
res.end(html("Authorization successful! You can close this tab and return to your terminal."));
|
|
92
94
|
server.close();
|
|
93
|
-
settle(() => resolve({ token, companyId }));
|
|
95
|
+
settle(() => resolve({ token, companyId, companyName, companyCode }));
|
|
94
96
|
});
|
|
95
97
|
const timeout = setTimeout(() => {
|
|
96
98
|
server.close();
|
|
@@ -103,18 +105,38 @@ function waitForCallback(port, expectedState) {
|
|
|
103
105
|
});
|
|
104
106
|
});
|
|
105
107
|
}
|
|
106
|
-
|
|
108
|
+
function getArgValue(args, flag) {
|
|
109
|
+
const idx = args.indexOf(flag);
|
|
110
|
+
if (idx === -1)
|
|
111
|
+
return null;
|
|
112
|
+
const v = args[idx + 1];
|
|
113
|
+
if (!v || v.startsWith("--"))
|
|
114
|
+
return null;
|
|
115
|
+
return v;
|
|
116
|
+
}
|
|
117
|
+
export async function login(args) {
|
|
107
118
|
const state = generateState();
|
|
108
119
|
const port = await findFreePort();
|
|
109
|
-
const
|
|
120
|
+
const requestedCompany = getArgValue(args, "--company");
|
|
121
|
+
const qp = new URLSearchParams({ port: String(port), state });
|
|
122
|
+
if (requestedCompany)
|
|
123
|
+
qp.set("company", requestedCompany);
|
|
124
|
+
const authUrl = `${NEXARCH_URL}/auth/cli?${qp.toString()}`;
|
|
110
125
|
console.log("Opening Nexarch in your browser…");
|
|
111
126
|
console.log(`\n ${authUrl}\n`);
|
|
112
127
|
console.log("If the browser did not open, copy the URL above and paste it in manually.\n");
|
|
113
128
|
openBrowser(authUrl);
|
|
114
|
-
const { token, companyId } = await waitForCallback(port, state);
|
|
129
|
+
const { token, companyId, companyName, companyCode } = await waitForCallback(port, state);
|
|
115
130
|
const expiresAt = new Date();
|
|
116
131
|
expiresAt.setDate(expiresAt.getDate() + 90);
|
|
117
|
-
saveCredentials({
|
|
132
|
+
saveCredentials({
|
|
133
|
+
token,
|
|
134
|
+
email: "",
|
|
135
|
+
company: companyName ?? companyCode ?? "",
|
|
136
|
+
companyCode: companyCode ?? undefined,
|
|
137
|
+
companyId,
|
|
138
|
+
expiresAt: expiresAt.toISOString(),
|
|
139
|
+
});
|
|
118
140
|
console.log("✓ Logged in successfully");
|
|
119
141
|
console.log("\nRun `nexarch status` to verify your connection.");
|
|
120
142
|
}
|
package/dist/commands/status.js
CHANGED
|
@@ -2,14 +2,13 @@ import { requireCredentials } from "../lib/credentials.js";
|
|
|
2
2
|
import { callMcpTool } from "../lib/mcp.js";
|
|
3
3
|
export async function status(_args) {
|
|
4
4
|
const creds = requireCredentials();
|
|
5
|
+
const selectedCompanyId = creds.companyId;
|
|
5
6
|
const expiresAt = new Date(creds.expiresAt);
|
|
6
7
|
const daysLeft = Math.ceil((expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
|
|
7
8
|
process.stdout.write("Connecting to mcp.nexarch.ai… ");
|
|
8
9
|
let governance;
|
|
9
10
|
try {
|
|
10
|
-
const result = await callMcpTool("nexarch_get_governance_summary", {
|
|
11
|
-
companyId: creds.companyId || undefined,
|
|
12
|
-
});
|
|
11
|
+
const result = await callMcpTool("nexarch_get_governance_summary", { companyId: selectedCompanyId || undefined }, { companyId: selectedCompanyId || undefined });
|
|
13
12
|
governance = JSON.parse(result.content[0]?.text ?? "{}");
|
|
14
13
|
}
|
|
15
14
|
catch (err) {
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,8 @@ async function main() {
|
|
|
23
23
|
nexarch — Connect AI coding tools to your architecture workspace
|
|
24
24
|
|
|
25
25
|
Usage:
|
|
26
|
-
nexarch login Authenticate in
|
|
26
|
+
nexarch login Authenticate in browser and store company-scoped credentials
|
|
27
|
+
Option: --company <id>
|
|
27
28
|
nexarch logout Remove stored credentials
|
|
28
29
|
nexarch status Check connection and show architecture summary
|
|
29
30
|
nexarch setup Auto-configure your MCP client (Claude Desktop, Cursor, etc.)
|
package/dist/lib/mcp.js
CHANGED
|
@@ -2,8 +2,9 @@ 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
|
-
async function callMcpRpc(method, params = {}) {
|
|
5
|
+
async function callMcpRpc(method, params = {}, options = {}) {
|
|
6
6
|
const creds = requireCredentials();
|
|
7
|
+
const companyId = options.companyId ?? creds.companyId;
|
|
7
8
|
const body = JSON.stringify({
|
|
8
9
|
jsonrpc: "2.0",
|
|
9
10
|
id: 1,
|
|
@@ -20,7 +21,7 @@ async function callMcpRpc(method, params = {}) {
|
|
|
20
21
|
headers: {
|
|
21
22
|
"Content-Type": "application/json",
|
|
22
23
|
Authorization: `Bearer ${creds.token}`,
|
|
23
|
-
"x-company-id":
|
|
24
|
+
"x-company-id": companyId,
|
|
24
25
|
"Content-Length": Buffer.byteLength(body),
|
|
25
26
|
},
|
|
26
27
|
timeout: REQUEST_TIMEOUT_MS,
|
|
@@ -54,18 +55,18 @@ async function callMcpRpc(method, params = {}) {
|
|
|
54
55
|
req.end();
|
|
55
56
|
});
|
|
56
57
|
}
|
|
57
|
-
export async function callMcpTool(toolName, toolArgs = {}) {
|
|
58
|
-
return callMcpRpc("tools/call", { name: toolName, arguments: toolArgs });
|
|
58
|
+
export async function callMcpTool(toolName, toolArgs = {}, options = {}) {
|
|
59
|
+
return callMcpRpc("tools/call", { name: toolName, arguments: toolArgs }, options);
|
|
59
60
|
}
|
|
60
|
-
export async function mcpInitialize() {
|
|
61
|
+
export async function mcpInitialize(options = {}) {
|
|
61
62
|
return callMcpRpc("initialize", {
|
|
62
63
|
protocolVersion: "2024-11-05",
|
|
63
64
|
capabilities: {},
|
|
64
|
-
clientInfo: { name: "nexarch-cli", version: "0.1.
|
|
65
|
-
});
|
|
65
|
+
clientInfo: { name: "nexarch-cli", version: "0.1.11" },
|
|
66
|
+
}, options);
|
|
66
67
|
}
|
|
67
|
-
export async function mcpListTools() {
|
|
68
|
-
const result = await callMcpRpc("tools/list", {});
|
|
68
|
+
export async function mcpListTools(options = {}) {
|
|
69
|
+
const result = await callMcpRpc("tools/list", {}, options);
|
|
69
70
|
return result.tools ?? [];
|
|
70
71
|
}
|
|
71
72
|
export async function forwardToGateway(token, companyId, body) {
|