nexarch 0.1.7 → 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 CHANGED
@@ -13,14 +13,22 @@ 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 |
22
- | `nexarch init-agent [--json] [--strict] [--agent-id <id>]` | Run onboarding handshake and mandatory `agent` entity registration in graph |
22
+ | `nexarch init-agent [--json] [--strict] [--agent-id <id>] [--redact-hostname]` | Run onboarding handshake and mandatory `agent` entity registration in graph |
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
+ | `nexarch init-agent` (default behavior) | Also upserts technology component entities (host, OS, Node.js runtime) and links them to the agent |
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.
24
32
 
25
33
  ## Requirements
26
34
 
@@ -1,7 +1,10 @@
1
- import { hostname, userInfo } from "os";
1
+ import { arch, hostname, platform, release, type as osType, userInfo } from "os";
2
+ import process from "process";
2
3
  import { requireCredentials } from "../lib/credentials.js";
3
4
  import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
4
- const CLI_VERSION = "0.1.7";
5
+ const CLI_VERSION = "0.1.11";
6
+ const AGENT_ENTITY_TYPE = "agent";
7
+ const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
5
8
  function parseFlag(args, flag) {
6
9
  return args.includes(flag);
7
10
  }
@@ -23,6 +26,28 @@ function getDefaultAgentId() {
23
26
  const host = hostname() || "unknown-host";
24
27
  return `nexarch-cli:${osUser}@${host}`;
25
28
  }
29
+ function getRuntimeMode() {
30
+ if (process.env.CI)
31
+ return "ci";
32
+ return "interactive";
33
+ }
34
+ function getSanitizedHostname(redactHostname) {
35
+ const raw = hostname() || "unknown-host";
36
+ return redactHostname ? "redacted" : raw;
37
+ }
38
+ function hasEntityType(contract, code) {
39
+ return (contract.ontology?.entityCodes ?? []).some((entityCode) => entityCode.toLowerCase() === code.toLowerCase());
40
+ }
41
+ function pickRelationshipType(contract) {
42
+ const available = new Set((contract.ontology?.relationshipCodes ?? []).map((c) => c.toLowerCase()));
43
+ if (available.has("depends_on"))
44
+ return "depends_on";
45
+ if (available.has("uses"))
46
+ return "uses";
47
+ if (available.has("runs_on"))
48
+ return "runs_on";
49
+ return null;
50
+ }
26
51
  async function emitInitObservation(params) {
27
52
  if (!params.policyBundleHash)
28
53
  return;
@@ -55,7 +80,7 @@ async function emitInitObservation(params) {
55
80
  waivers: [],
56
81
  },
57
82
  },
58
- });
83
+ }, { companyId: params.companyId });
59
84
  }
60
85
  catch {
61
86
  // non-fatal telemetry path
@@ -64,19 +89,30 @@ async function emitInitObservation(params) {
64
89
  export async function initAgent(args) {
65
90
  const asJson = parseFlag(args, "--json");
66
91
  const strict = parseFlag(args, "--strict");
92
+ const redactHostname = parseFlag(args, "--redact-hostname");
67
93
  const explicitAgentId = parseOptionValue(args, "--agent-id");
68
94
  const bindToExternalKey = parseOptionValue(args, "--bind-to-external-key");
69
95
  const bindRelationshipType = parseOptionValue(args, "--bind-relationship-type") ?? "depends_on";
70
96
  const agentId = explicitAgentId ?? getDefaultAgentId();
97
+ const runtime = {
98
+ osPlatform: platform(),
99
+ osType: osType(),
100
+ osRelease: release(),
101
+ arch: arch(),
102
+ hostname: getSanitizedHostname(redactHostname),
103
+ nodeVersion: process.version,
104
+ mode: getRuntimeMode(),
105
+ };
71
106
  const checks = [];
72
107
  const creds = requireCredentials();
73
- const init = await mcpInitialize();
108
+ const selectedCompanyId = creds.companyId;
109
+ const init = await mcpInitialize({ companyId: selectedCompanyId });
74
110
  checks.push({
75
111
  name: "mcp.initialize",
76
112
  ok: true,
77
113
  detail: `${init.serverInfo?.name ?? "unknown"}@${init.serverInfo?.version ?? "unknown"}`,
78
114
  });
79
- const tools = await mcpListTools();
115
+ const tools = await mcpListTools({ companyId: selectedCompanyId });
80
116
  const toolNames = new Set(tools.map((t) => t.name));
81
117
  const required = [
82
118
  "nexarch_get_applied_policies",
@@ -91,7 +127,7 @@ export async function initAgent(args) {
91
127
  ok: missing.length === 0,
92
128
  detail: missing.length ? `missing: ${missing.join(", ")}` : `required tools present (${required.length})`,
93
129
  });
94
- const policiesRaw = await callMcpTool("nexarch_get_applied_policies", {});
130
+ const policiesRaw = await callMcpTool("nexarch_get_applied_policies", {}, { companyId: selectedCompanyId });
95
131
  const policies = parseToolText(policiesRaw);
96
132
  checks.push({
97
133
  name: "governance.bootstrap",
@@ -100,14 +136,14 @@ export async function initAgent(args) {
100
136
  ? `policyBundleHash=${policies.policyBundleHash.slice(0, 12)}… policyCount=${policies.policyCount ?? 0}`
101
137
  : "missing policyBundleHash",
102
138
  });
103
- const contractRaw = await callMcpTool("nexarch_get_ingest_contract", {});
139
+ const contractRaw = await callMcpTool("nexarch_get_ingest_contract", {}, { companyId: selectedCompanyId });
104
140
  const contract = parseToolText(contractRaw);
105
141
  checks.push({
106
142
  name: "ingest.contract",
107
143
  ok: Boolean(contract.contractVersion),
108
144
  detail: `version=${contract.contractVersion ?? "unknown"}; entities=${contract.ontology?.entityCodes?.length ?? 0}; relationships=${contract.ontology?.relationshipCodes?.length ?? 0}`,
109
145
  });
110
- const hasAgentType = (contract.ontology?.entityCodes ?? []).some((code) => code.toLowerCase() === "agent");
146
+ const hasAgentType = hasEntityType(contract, AGENT_ENTITY_TYPE);
111
147
  checks.push({
112
148
  name: "ontology.agent-type",
113
149
  ok: hasAgentType,
@@ -115,23 +151,51 @@ export async function initAgent(args) {
115
151
  ? "entity type 'agent' is enabled"
116
152
  : "entity type 'agent' is not enabled for this workspace ontology",
117
153
  });
154
+ const hasTechComponentType = hasEntityType(contract, TECH_COMPONENT_ENTITY_TYPE);
155
+ checks.push({
156
+ name: "ontology.technology-component-type",
157
+ ok: hasTechComponentType,
158
+ detail: hasTechComponentType
159
+ ? "entity type 'technology_component' is enabled"
160
+ : "entity type 'technology_component' is not enabled for this workspace ontology",
161
+ });
162
+ const relForTechBinding = pickRelationshipType(contract);
163
+ checks.push({
164
+ name: "ontology.agent-tech-relationship",
165
+ ok: Boolean(relForTechBinding),
166
+ detail: relForTechBinding
167
+ ? `using relationship '${relForTechBinding}' for agent->technology_component links`
168
+ : "no supported relationship code found (expected one of depends_on|uses|runs_on)",
169
+ });
118
170
  const preflightPassed = checks.every((c) => c.ok);
119
171
  let registration = {
120
172
  ok: false,
121
173
  detail: "registration not attempted",
122
174
  };
175
+ let techComponents = {
176
+ attempted: false,
177
+ ok: true,
178
+ detail: "not attempted",
179
+ };
180
+ let techRelationships = {
181
+ attempted: false,
182
+ ok: true,
183
+ detail: "not attempted",
184
+ };
123
185
  let binding = {
124
186
  attempted: false,
125
187
  ok: true,
126
188
  detail: "not requested",
127
189
  };
128
- if (preflightPassed && policies.policyBundleHash) {
190
+ if (preflightPassed && policies.policyBundleHash && relForTechBinding) {
129
191
  const nowIso = new Date().toISOString();
192
+ const agentRunId = `init-agent-${Date.now()}`;
193
+ const agentExternalKey = `agent:${agentId}`;
130
194
  const upsertRaw = await callMcpTool("nexarch_upsert_entities", {
131
195
  entities: [
132
196
  {
133
- externalKey: `agent:${agentId}`,
134
- entityTypeCode: "agent",
197
+ externalKey: agentExternalKey,
198
+ entityTypeCode: AGENT_ENTITY_TYPE,
135
199
  name: `Agent ${agentId}`,
136
200
  description: "Agent identity registered from nexarch init-agent handshake",
137
201
  confidence: 1,
@@ -140,6 +204,21 @@ export async function initAgent(args) {
140
204
  client: "nexarch-cli",
141
205
  version: CLI_VERSION,
142
206
  companyId: creds.companyId,
207
+ governance: {
208
+ policyBundleHash: policies.policyBundleHash,
209
+ contractVersion: contract.contractVersion ?? null,
210
+ policyCount: policies.policyCount ?? null,
211
+ strict,
212
+ },
213
+ runtime: {
214
+ os: runtime.osPlatform,
215
+ osType: runtime.osType,
216
+ osRelease: runtime.osRelease,
217
+ arch: runtime.arch,
218
+ hostname: runtime.hostname,
219
+ nodeVersion: runtime.nodeVersion,
220
+ mode: runtime.mode,
221
+ },
143
222
  handshake: {
144
223
  completedAt: nowIso,
145
224
  source: "init-agent",
@@ -149,7 +228,7 @@ export async function initAgent(args) {
149
228
  ],
150
229
  agentContext: {
151
230
  agentId,
152
- agentRunId: `init-agent-${Date.now()}`,
231
+ agentRunId,
153
232
  repoRef: "nexarch-cli/init-agent",
154
233
  observedAt: nowIso,
155
234
  source: "nexarch-cli",
@@ -165,7 +244,7 @@ export async function initAgent(args) {
165
244
  },
166
245
  },
167
246
  dryRun: false,
168
- });
247
+ }, { companyId: selectedCompanyId });
169
248
  const upsert = parseToolText(upsertRaw);
170
249
  const firstResult = upsert.results?.[0];
171
250
  const failed = Number(upsert.summary?.failed ?? 0) > 0;
@@ -181,11 +260,169 @@ export async function initAgent(args) {
181
260
  if (!registration.ok) {
182
261
  await emitInitObservation({
183
262
  agentId,
263
+ companyId: selectedCompanyId,
184
264
  policyBundleHash: policies.policyBundleHash,
185
265
  message: `init-agent registration failed: ${registration.detail}`,
186
266
  confidence: 1,
187
267
  });
188
268
  }
269
+ if (registration.ok) {
270
+ techComponents.attempted = true;
271
+ const hostExternalKey = `tech:host:${runtime.hostname}:${runtime.arch}`;
272
+ const osExternalKey = `tech:os:${runtime.osPlatform}:${runtime.osRelease}:${runtime.arch}`;
273
+ const nodeExternalKey = `tech:runtime:nodejs:${runtime.nodeVersion}`;
274
+ const techUpsertRaw = await callMcpTool("nexarch_upsert_entities", {
275
+ entities: [
276
+ {
277
+ externalKey: hostExternalKey,
278
+ entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
279
+ entitySubtypeCode: "tech_compute",
280
+ name: `Host ${runtime.hostname}`,
281
+ description: "Execution host for registered agent runtimes",
282
+ confidence: 0.95,
283
+ attributes: {
284
+ kind: "host_machine",
285
+ hostname: runtime.hostname,
286
+ arch: runtime.arch,
287
+ os: runtime.osPlatform,
288
+ osRelease: runtime.osRelease,
289
+ },
290
+ },
291
+ {
292
+ externalKey: osExternalKey,
293
+ entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
294
+ entitySubtypeCode: "tech_operating_system",
295
+ name: `${runtime.osPlatform} ${runtime.osRelease}`,
296
+ description: "Operating system platform used by registered agents",
297
+ confidence: 0.95,
298
+ attributes: {
299
+ kind: "operating_system",
300
+ os: runtime.osPlatform,
301
+ osType: runtime.osType,
302
+ osRelease: runtime.osRelease,
303
+ arch: runtime.arch,
304
+ },
305
+ },
306
+ {
307
+ externalKey: nodeExternalKey,
308
+ entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
309
+ entitySubtypeCode: "tech_runtime",
310
+ name: `Node.js ${runtime.nodeVersion}`,
311
+ description: "Node.js runtime used by nexarch-cli agent",
312
+ confidence: 0.95,
313
+ attributes: {
314
+ kind: "runtime",
315
+ runtime: "nodejs",
316
+ version: runtime.nodeVersion,
317
+ },
318
+ },
319
+ ],
320
+ agentContext: {
321
+ agentId,
322
+ agentRunId: `${agentRunId}-tech`,
323
+ repoRef: "nexarch-cli/init-agent",
324
+ observedAt: nowIso,
325
+ source: "nexarch-cli",
326
+ model: "n/a",
327
+ provider: "n/a",
328
+ },
329
+ policyContext: {
330
+ policyBundleHash: policies.policyBundleHash,
331
+ alignmentSummary: {
332
+ score: 1,
333
+ violations: [],
334
+ waivers: [],
335
+ },
336
+ },
337
+ dryRun: false,
338
+ }, { companyId: selectedCompanyId });
339
+ const techUpsert = parseToolText(techUpsertRaw);
340
+ const techFailed = Number(techUpsert.summary?.failed ?? 0) > 0;
341
+ techComponents = {
342
+ attempted: true,
343
+ ok: !techFailed,
344
+ detail: techFailed
345
+ ? `technology component upsert failed (${techUpsert.errors?.[0]?.error ?? "unknown"})`
346
+ : `upserted ${(techUpsert.summary?.succeeded ?? 0)} technology components`,
347
+ results: techUpsert.results,
348
+ errors: techUpsert.errors,
349
+ };
350
+ if (!techComponents.ok) {
351
+ await emitInitObservation({
352
+ agentId,
353
+ companyId: selectedCompanyId,
354
+ policyBundleHash: policies.policyBundleHash,
355
+ message: `init-agent technology component upsert failed: ${techComponents.detail}`,
356
+ confidence: 1,
357
+ });
358
+ }
359
+ if (techComponents.ok) {
360
+ techRelationships.attempted = true;
361
+ const techRelRaw = await callMcpTool("nexarch_upsert_relationships", {
362
+ relationships: [
363
+ {
364
+ relationshipTypeCode: relForTechBinding,
365
+ fromEntityExternalKey: agentExternalKey,
366
+ toEntityExternalKey: hostExternalKey,
367
+ confidence: 0.95,
368
+ attributes: { source: "nexarch-cli-init-agent", kind: "execution_host", createdAt: nowIso },
369
+ },
370
+ {
371
+ relationshipTypeCode: relForTechBinding,
372
+ fromEntityExternalKey: agentExternalKey,
373
+ toEntityExternalKey: osExternalKey,
374
+ confidence: 0.95,
375
+ attributes: { source: "nexarch-cli-init-agent", kind: "operating_system", createdAt: nowIso },
376
+ },
377
+ {
378
+ relationshipTypeCode: relForTechBinding,
379
+ fromEntityExternalKey: agentExternalKey,
380
+ toEntityExternalKey: nodeExternalKey,
381
+ confidence: 0.95,
382
+ attributes: { source: "nexarch-cli-init-agent", kind: "runtime", createdAt: nowIso },
383
+ },
384
+ ],
385
+ agentContext: {
386
+ agentId,
387
+ agentRunId: `${agentRunId}-tech-rel`,
388
+ repoRef: "nexarch-cli/init-agent",
389
+ observedAt: nowIso,
390
+ source: "nexarch-cli",
391
+ model: "n/a",
392
+ provider: "n/a",
393
+ },
394
+ policyContext: {
395
+ policyBundleHash: policies.policyBundleHash,
396
+ alignmentSummary: {
397
+ score: 1,
398
+ violations: [],
399
+ waivers: [],
400
+ },
401
+ },
402
+ dryRun: false,
403
+ }, { companyId: selectedCompanyId });
404
+ const relUpsert = parseToolText(techRelRaw);
405
+ const relFailed = Number(relUpsert.summary?.failed ?? 0) > 0;
406
+ techRelationships = {
407
+ attempted: true,
408
+ ok: !relFailed,
409
+ detail: relFailed
410
+ ? `technology relationship upsert failed (${relUpsert.errors?.[0]?.error ?? "unknown"})`
411
+ : `upserted ${(relUpsert.summary?.succeeded ?? 0)} technology relationships`,
412
+ results: relUpsert.results,
413
+ errors: relUpsert.errors,
414
+ };
415
+ if (!techRelationships.ok) {
416
+ await emitInitObservation({
417
+ agentId,
418
+ companyId: selectedCompanyId,
419
+ policyBundleHash: policies.policyBundleHash,
420
+ message: `init-agent technology relationship upsert failed: ${techRelationships.detail}`,
421
+ confidence: 1,
422
+ });
423
+ }
424
+ }
425
+ }
189
426
  if (registration.ok && bindToExternalKey) {
190
427
  binding.attempted = true;
191
428
  const relRaw = await callMcpTool("nexarch_upsert_relationships", {
@@ -219,7 +456,7 @@ export async function initAgent(args) {
219
456
  },
220
457
  },
221
458
  dryRun: false,
222
- });
459
+ }, { companyId: selectedCompanyId });
223
460
  const rel = parseToolText(relRaw);
224
461
  const relResult = rel.results?.[0];
225
462
  const relFailed = Number(rel.summary?.failed ?? 0) > 0;
@@ -236,6 +473,7 @@ export async function initAgent(args) {
236
473
  if (!binding.ok) {
237
474
  await emitInitObservation({
238
475
  agentId,
476
+ companyId: selectedCompanyId,
239
477
  policyBundleHash: policies.policyBundleHash,
240
478
  message: `init-agent binding failed: ${binding.detail}`,
241
479
  confidence: 1,
@@ -248,6 +486,16 @@ export async function initAgent(args) {
248
486
  ok: registration.ok,
249
487
  detail: registration.detail,
250
488
  });
489
+ checks.push({
490
+ name: "technology.components",
491
+ ok: techComponents.ok,
492
+ detail: techComponents.detail,
493
+ });
494
+ checks.push({
495
+ name: "technology.relationships",
496
+ ok: techRelationships.ok,
497
+ detail: techRelationships.detail,
498
+ });
251
499
  if (binding.attempted) {
252
500
  checks.push({
253
501
  name: "agent.binding",
@@ -270,7 +518,12 @@ export async function initAgent(args) {
270
518
  policyBundleHash: policies.policyBundleHash ?? null,
271
519
  contractVersion: contract.contractVersion ?? null,
272
520
  agentId,
521
+ runtime,
273
522
  registration,
523
+ technology: {
524
+ components: techComponents,
525
+ relationships: techRelationships,
526
+ },
274
527
  binding,
275
528
  companyId: creds.companyId,
276
529
  };
@@ -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
- export async function login(_args) {
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 authUrl = `${NEXARCH_URL}/auth/cli?port=${port}&state=${state}`;
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({ token, email: "", company: "", companyId, expiresAt: expiresAt.toISOString() });
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
  }
@@ -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 the browser and store credentials
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.)
@@ -31,7 +32,8 @@ Usage:
31
32
  nexarch mcp-proxy Run as stdio MCP proxy (used by MCP clients)
32
33
  nexarch init-agent Run handshake + mandatory agent registration in graph
33
34
  Options: --agent-id <id> --bind-to-external-key <key>
34
- --bind-relationship-type <code> --json --strict
35
+ --bind-relationship-type <code> --redact-hostname
36
+ --json --strict
35
37
  `);
36
38
  process.exit(command ? 1 : 0);
37
39
  }
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": creds.companyId,
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.7" },
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.1.7",
3
+ "version": "0.1.11",
4
4
  "description": "Connect AI coding tools to your Nexarch architecture workspace",
5
5
  "keywords": [
6
6
  "nexarch",