nexarch 0.1.7 → 0.1.8
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 +2 -1
- package/dist/commands/init-agent.js +252 -7
- package/dist/index.js +2 -1
- package/dist/lib/mcp.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,8 +19,9 @@ 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] [--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 |
|
|
24
25
|
|
|
25
26
|
## Requirements
|
|
26
27
|
|
|
@@ -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.
|
|
5
|
+
const CLI_VERSION = "0.1.8";
|
|
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;
|
|
@@ -64,10 +89,20 @@ 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
108
|
const init = await mcpInitialize();
|
|
@@ -107,7 +142,7 @@ export async function initAgent(args) {
|
|
|
107
142
|
ok: Boolean(contract.contractVersion),
|
|
108
143
|
detail: `version=${contract.contractVersion ?? "unknown"}; entities=${contract.ontology?.entityCodes?.length ?? 0}; relationships=${contract.ontology?.relationshipCodes?.length ?? 0}`,
|
|
109
144
|
});
|
|
110
|
-
const hasAgentType = (contract
|
|
145
|
+
const hasAgentType = hasEntityType(contract, AGENT_ENTITY_TYPE);
|
|
111
146
|
checks.push({
|
|
112
147
|
name: "ontology.agent-type",
|
|
113
148
|
ok: hasAgentType,
|
|
@@ -115,23 +150,51 @@ export async function initAgent(args) {
|
|
|
115
150
|
? "entity type 'agent' is enabled"
|
|
116
151
|
: "entity type 'agent' is not enabled for this workspace ontology",
|
|
117
152
|
});
|
|
153
|
+
const hasTechComponentType = hasEntityType(contract, TECH_COMPONENT_ENTITY_TYPE);
|
|
154
|
+
checks.push({
|
|
155
|
+
name: "ontology.technology-component-type",
|
|
156
|
+
ok: hasTechComponentType,
|
|
157
|
+
detail: hasTechComponentType
|
|
158
|
+
? "entity type 'technology_component' is enabled"
|
|
159
|
+
: "entity type 'technology_component' is not enabled for this workspace ontology",
|
|
160
|
+
});
|
|
161
|
+
const relForTechBinding = pickRelationshipType(contract);
|
|
162
|
+
checks.push({
|
|
163
|
+
name: "ontology.agent-tech-relationship",
|
|
164
|
+
ok: Boolean(relForTechBinding),
|
|
165
|
+
detail: relForTechBinding
|
|
166
|
+
? `using relationship '${relForTechBinding}' for agent->technology_component links`
|
|
167
|
+
: "no supported relationship code found (expected one of depends_on|uses|runs_on)",
|
|
168
|
+
});
|
|
118
169
|
const preflightPassed = checks.every((c) => c.ok);
|
|
119
170
|
let registration = {
|
|
120
171
|
ok: false,
|
|
121
172
|
detail: "registration not attempted",
|
|
122
173
|
};
|
|
174
|
+
let techComponents = {
|
|
175
|
+
attempted: false,
|
|
176
|
+
ok: true,
|
|
177
|
+
detail: "not attempted",
|
|
178
|
+
};
|
|
179
|
+
let techRelationships = {
|
|
180
|
+
attempted: false,
|
|
181
|
+
ok: true,
|
|
182
|
+
detail: "not attempted",
|
|
183
|
+
};
|
|
123
184
|
let binding = {
|
|
124
185
|
attempted: false,
|
|
125
186
|
ok: true,
|
|
126
187
|
detail: "not requested",
|
|
127
188
|
};
|
|
128
|
-
if (preflightPassed && policies.policyBundleHash) {
|
|
189
|
+
if (preflightPassed && policies.policyBundleHash && relForTechBinding) {
|
|
129
190
|
const nowIso = new Date().toISOString();
|
|
191
|
+
const agentRunId = `init-agent-${Date.now()}`;
|
|
192
|
+
const agentExternalKey = `agent:${agentId}`;
|
|
130
193
|
const upsertRaw = await callMcpTool("nexarch_upsert_entities", {
|
|
131
194
|
entities: [
|
|
132
195
|
{
|
|
133
|
-
externalKey:
|
|
134
|
-
entityTypeCode:
|
|
196
|
+
externalKey: agentExternalKey,
|
|
197
|
+
entityTypeCode: AGENT_ENTITY_TYPE,
|
|
135
198
|
name: `Agent ${agentId}`,
|
|
136
199
|
description: "Agent identity registered from nexarch init-agent handshake",
|
|
137
200
|
confidence: 1,
|
|
@@ -140,6 +203,21 @@ export async function initAgent(args) {
|
|
|
140
203
|
client: "nexarch-cli",
|
|
141
204
|
version: CLI_VERSION,
|
|
142
205
|
companyId: creds.companyId,
|
|
206
|
+
governance: {
|
|
207
|
+
policyBundleHash: policies.policyBundleHash,
|
|
208
|
+
contractVersion: contract.contractVersion ?? null,
|
|
209
|
+
policyCount: policies.policyCount ?? null,
|
|
210
|
+
strict,
|
|
211
|
+
},
|
|
212
|
+
runtime: {
|
|
213
|
+
os: runtime.osPlatform,
|
|
214
|
+
osType: runtime.osType,
|
|
215
|
+
osRelease: runtime.osRelease,
|
|
216
|
+
arch: runtime.arch,
|
|
217
|
+
hostname: runtime.hostname,
|
|
218
|
+
nodeVersion: runtime.nodeVersion,
|
|
219
|
+
mode: runtime.mode,
|
|
220
|
+
},
|
|
143
221
|
handshake: {
|
|
144
222
|
completedAt: nowIso,
|
|
145
223
|
source: "init-agent",
|
|
@@ -149,7 +227,7 @@ export async function initAgent(args) {
|
|
|
149
227
|
],
|
|
150
228
|
agentContext: {
|
|
151
229
|
agentId,
|
|
152
|
-
agentRunId
|
|
230
|
+
agentRunId,
|
|
153
231
|
repoRef: "nexarch-cli/init-agent",
|
|
154
232
|
observedAt: nowIso,
|
|
155
233
|
source: "nexarch-cli",
|
|
@@ -186,6 +264,158 @@ export async function initAgent(args) {
|
|
|
186
264
|
confidence: 1,
|
|
187
265
|
});
|
|
188
266
|
}
|
|
267
|
+
if (registration.ok) {
|
|
268
|
+
techComponents.attempted = true;
|
|
269
|
+
const hostExternalKey = `tech:host:${runtime.hostname}:${runtime.arch}`;
|
|
270
|
+
const osExternalKey = `tech:os:${runtime.osPlatform}:${runtime.osRelease}:${runtime.arch}`;
|
|
271
|
+
const nodeExternalKey = `tech:runtime:nodejs:${runtime.nodeVersion}`;
|
|
272
|
+
const techUpsertRaw = await callMcpTool("nexarch_upsert_entities", {
|
|
273
|
+
entities: [
|
|
274
|
+
{
|
|
275
|
+
externalKey: hostExternalKey,
|
|
276
|
+
entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
|
|
277
|
+
name: `Host ${runtime.hostname}`,
|
|
278
|
+
description: "Execution host for registered agent runtimes",
|
|
279
|
+
confidence: 0.95,
|
|
280
|
+
attributes: {
|
|
281
|
+
kind: "host_machine",
|
|
282
|
+
hostname: runtime.hostname,
|
|
283
|
+
arch: runtime.arch,
|
|
284
|
+
os: runtime.osPlatform,
|
|
285
|
+
osRelease: runtime.osRelease,
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
externalKey: osExternalKey,
|
|
290
|
+
entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
|
|
291
|
+
name: `${runtime.osPlatform} ${runtime.osRelease}`,
|
|
292
|
+
description: "Operating system platform used by registered agents",
|
|
293
|
+
confidence: 0.95,
|
|
294
|
+
attributes: {
|
|
295
|
+
kind: "operating_system",
|
|
296
|
+
os: runtime.osPlatform,
|
|
297
|
+
osType: runtime.osType,
|
|
298
|
+
osRelease: runtime.osRelease,
|
|
299
|
+
arch: runtime.arch,
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
externalKey: nodeExternalKey,
|
|
304
|
+
entityTypeCode: TECH_COMPONENT_ENTITY_TYPE,
|
|
305
|
+
name: `Node.js ${runtime.nodeVersion}`,
|
|
306
|
+
description: "Node.js runtime used by nexarch-cli agent",
|
|
307
|
+
confidence: 0.95,
|
|
308
|
+
attributes: {
|
|
309
|
+
kind: "runtime",
|
|
310
|
+
runtime: "nodejs",
|
|
311
|
+
version: runtime.nodeVersion,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
agentContext: {
|
|
316
|
+
agentId,
|
|
317
|
+
agentRunId: `${agentRunId}-tech`,
|
|
318
|
+
repoRef: "nexarch-cli/init-agent",
|
|
319
|
+
observedAt: nowIso,
|
|
320
|
+
source: "nexarch-cli",
|
|
321
|
+
model: "n/a",
|
|
322
|
+
provider: "n/a",
|
|
323
|
+
},
|
|
324
|
+
policyContext: {
|
|
325
|
+
policyBundleHash: policies.policyBundleHash,
|
|
326
|
+
alignmentSummary: {
|
|
327
|
+
score: 1,
|
|
328
|
+
violations: [],
|
|
329
|
+
waivers: [],
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
dryRun: false,
|
|
333
|
+
});
|
|
334
|
+
const techUpsert = parseToolText(techUpsertRaw);
|
|
335
|
+
const techFailed = Number(techUpsert.summary?.failed ?? 0) > 0;
|
|
336
|
+
techComponents = {
|
|
337
|
+
attempted: true,
|
|
338
|
+
ok: !techFailed,
|
|
339
|
+
detail: techFailed
|
|
340
|
+
? `technology component upsert failed (${techUpsert.errors?.[0]?.error ?? "unknown"})`
|
|
341
|
+
: `upserted ${(techUpsert.summary?.succeeded ?? 0)} technology components`,
|
|
342
|
+
results: techUpsert.results,
|
|
343
|
+
errors: techUpsert.errors,
|
|
344
|
+
};
|
|
345
|
+
if (!techComponents.ok) {
|
|
346
|
+
await emitInitObservation({
|
|
347
|
+
agentId,
|
|
348
|
+
policyBundleHash: policies.policyBundleHash,
|
|
349
|
+
message: `init-agent technology component upsert failed: ${techComponents.detail}`,
|
|
350
|
+
confidence: 1,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (techComponents.ok) {
|
|
354
|
+
techRelationships.attempted = true;
|
|
355
|
+
const techRelRaw = await callMcpTool("nexarch_upsert_relationships", {
|
|
356
|
+
relationships: [
|
|
357
|
+
{
|
|
358
|
+
relationshipTypeCode: relForTechBinding,
|
|
359
|
+
fromEntityExternalKey: agentExternalKey,
|
|
360
|
+
toEntityExternalKey: hostExternalKey,
|
|
361
|
+
confidence: 0.95,
|
|
362
|
+
attributes: { source: "nexarch-cli-init-agent", kind: "execution_host", createdAt: nowIso },
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
relationshipTypeCode: relForTechBinding,
|
|
366
|
+
fromEntityExternalKey: agentExternalKey,
|
|
367
|
+
toEntityExternalKey: osExternalKey,
|
|
368
|
+
confidence: 0.95,
|
|
369
|
+
attributes: { source: "nexarch-cli-init-agent", kind: "operating_system", createdAt: nowIso },
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
relationshipTypeCode: relForTechBinding,
|
|
373
|
+
fromEntityExternalKey: agentExternalKey,
|
|
374
|
+
toEntityExternalKey: nodeExternalKey,
|
|
375
|
+
confidence: 0.95,
|
|
376
|
+
attributes: { source: "nexarch-cli-init-agent", kind: "runtime", createdAt: nowIso },
|
|
377
|
+
},
|
|
378
|
+
],
|
|
379
|
+
agentContext: {
|
|
380
|
+
agentId,
|
|
381
|
+
agentRunId: `${agentRunId}-tech-rel`,
|
|
382
|
+
repoRef: "nexarch-cli/init-agent",
|
|
383
|
+
observedAt: nowIso,
|
|
384
|
+
source: "nexarch-cli",
|
|
385
|
+
model: "n/a",
|
|
386
|
+
provider: "n/a",
|
|
387
|
+
},
|
|
388
|
+
policyContext: {
|
|
389
|
+
policyBundleHash: policies.policyBundleHash,
|
|
390
|
+
alignmentSummary: {
|
|
391
|
+
score: 1,
|
|
392
|
+
violations: [],
|
|
393
|
+
waivers: [],
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
dryRun: false,
|
|
397
|
+
});
|
|
398
|
+
const relUpsert = parseToolText(techRelRaw);
|
|
399
|
+
const relFailed = Number(relUpsert.summary?.failed ?? 0) > 0;
|
|
400
|
+
techRelationships = {
|
|
401
|
+
attempted: true,
|
|
402
|
+
ok: !relFailed,
|
|
403
|
+
detail: relFailed
|
|
404
|
+
? `technology relationship upsert failed (${relUpsert.errors?.[0]?.error ?? "unknown"})`
|
|
405
|
+
: `upserted ${(relUpsert.summary?.succeeded ?? 0)} technology relationships`,
|
|
406
|
+
results: relUpsert.results,
|
|
407
|
+
errors: relUpsert.errors,
|
|
408
|
+
};
|
|
409
|
+
if (!techRelationships.ok) {
|
|
410
|
+
await emitInitObservation({
|
|
411
|
+
agentId,
|
|
412
|
+
policyBundleHash: policies.policyBundleHash,
|
|
413
|
+
message: `init-agent technology relationship upsert failed: ${techRelationships.detail}`,
|
|
414
|
+
confidence: 1,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
189
419
|
if (registration.ok && bindToExternalKey) {
|
|
190
420
|
binding.attempted = true;
|
|
191
421
|
const relRaw = await callMcpTool("nexarch_upsert_relationships", {
|
|
@@ -248,6 +478,16 @@ export async function initAgent(args) {
|
|
|
248
478
|
ok: registration.ok,
|
|
249
479
|
detail: registration.detail,
|
|
250
480
|
});
|
|
481
|
+
checks.push({
|
|
482
|
+
name: "technology.components",
|
|
483
|
+
ok: techComponents.ok,
|
|
484
|
+
detail: techComponents.detail,
|
|
485
|
+
});
|
|
486
|
+
checks.push({
|
|
487
|
+
name: "technology.relationships",
|
|
488
|
+
ok: techRelationships.ok,
|
|
489
|
+
detail: techRelationships.detail,
|
|
490
|
+
});
|
|
251
491
|
if (binding.attempted) {
|
|
252
492
|
checks.push({
|
|
253
493
|
name: "agent.binding",
|
|
@@ -270,7 +510,12 @@ export async function initAgent(args) {
|
|
|
270
510
|
policyBundleHash: policies.policyBundleHash ?? null,
|
|
271
511
|
contractVersion: contract.contractVersion ?? null,
|
|
272
512
|
agentId,
|
|
513
|
+
runtime,
|
|
273
514
|
registration,
|
|
515
|
+
technology: {
|
|
516
|
+
components: techComponents,
|
|
517
|
+
relationships: techRelationships,
|
|
518
|
+
},
|
|
274
519
|
binding,
|
|
275
520
|
companyId: creds.companyId,
|
|
276
521
|
};
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,8 @@ Usage:
|
|
|
31
31
|
nexarch mcp-proxy Run as stdio MCP proxy (used by MCP clients)
|
|
32
32
|
nexarch init-agent Run handshake + mandatory agent registration in graph
|
|
33
33
|
Options: --agent-id <id> --bind-to-external-key <key>
|
|
34
|
-
--bind-relationship-type <code> --
|
|
34
|
+
--bind-relationship-type <code> --redact-hostname
|
|
35
|
+
--json --strict
|
|
35
36
|
`);
|
|
36
37
|
process.exit(command ? 1 : 0);
|
|
37
38
|
}
|
package/dist/lib/mcp.js
CHANGED
|
@@ -61,7 +61,7 @@ export async function mcpInitialize() {
|
|
|
61
61
|
return callMcpRpc("initialize", {
|
|
62
62
|
protocolVersion: "2024-11-05",
|
|
63
63
|
capabilities: {},
|
|
64
|
-
clientInfo: { name: "nexarch-cli", version: "0.1.
|
|
64
|
+
clientInfo: { name: "nexarch-cli", version: "0.1.8" },
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
export async function mcpListTools() {
|