nexarch 0.1.5 → 0.1.6

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
@@ -19,7 +19,8 @@ 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
+ | `nexarch init-agent [--json] [--strict] [--agent-id <id>]` | Run onboarding handshake and mandatory `agent` entity registration in graph |
23
+ | `nexarch init-agent --bind-to-external-key <key> [--bind-relationship-type <code>]` | Optionally bind the agent node to an existing graph external key |
23
24
 
24
25
  ## Requirements
25
26
 
@@ -1,15 +1,75 @@
1
+ import { hostname, userInfo } from "os";
2
+ import { requireCredentials } from "../lib/credentials.js";
1
3
  import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
4
+ const CLI_VERSION = "0.1.6";
2
5
  function parseFlag(args, flag) {
3
6
  return args.includes(flag);
4
7
  }
8
+ function parseOptionValue(args, option) {
9
+ const idx = args.indexOf(option);
10
+ if (idx === -1)
11
+ return null;
12
+ const value = args[idx + 1];
13
+ if (!value || value.startsWith("--"))
14
+ return null;
15
+ return value;
16
+ }
5
17
  function parseToolText(result) {
6
18
  const text = result.content?.[0]?.text ?? "{}";
7
19
  return JSON.parse(text);
8
20
  }
21
+ function getDefaultAgentId() {
22
+ const osUser = process.env.USERNAME || process.env.USER || userInfo().username || "unknown";
23
+ const host = hostname() || "unknown-host";
24
+ return `nexarch-cli:${osUser}@${host}`;
25
+ }
26
+ async function emitInitObservation(params) {
27
+ if (!params.policyBundleHash)
28
+ return;
29
+ const nowIso = new Date().toISOString();
30
+ try {
31
+ await callMcpTool("nexarch_emit_observations", {
32
+ observations: [
33
+ {
34
+ kind: "entity",
35
+ externalKey: `agent:${params.agentId}`,
36
+ message: params.message,
37
+ confidence: params.confidence ?? 0.6,
38
+ evidence: { source: "nexarch init-agent", timestamp: nowIso },
39
+ },
40
+ ],
41
+ agentContext: {
42
+ agentId: params.agentId,
43
+ agentRunId: `init-agent-${Date.now()}`,
44
+ repoRef: "nexarch-cli/init-agent",
45
+ observedAt: nowIso,
46
+ source: "nexarch-cli",
47
+ model: "n/a",
48
+ provider: "n/a",
49
+ },
50
+ policyContext: {
51
+ policyBundleHash: params.policyBundleHash,
52
+ alignmentSummary: {
53
+ score: 1,
54
+ violations: [],
55
+ waivers: [],
56
+ },
57
+ },
58
+ });
59
+ }
60
+ catch {
61
+ // non-fatal telemetry path
62
+ }
63
+ }
9
64
  export async function initAgent(args) {
10
65
  const asJson = parseFlag(args, "--json");
11
66
  const strict = parseFlag(args, "--strict");
67
+ const explicitAgentId = parseOptionValue(args, "--agent-id");
68
+ const bindToExternalKey = parseOptionValue(args, "--bind-to-external-key");
69
+ const bindRelationshipType = parseOptionValue(args, "--bind-relationship-type") ?? "depends_on";
70
+ const agentId = explicitAgentId ?? getDefaultAgentId();
12
71
  const checks = [];
72
+ const creds = requireCredentials();
13
73
  const init = await mcpInitialize();
14
74
  checks.push({
15
75
  name: "mcp.initialize",
@@ -23,6 +83,7 @@ export async function initAgent(args) {
23
83
  "nexarch_get_ingest_contract",
24
84
  "nexarch_upsert_entities",
25
85
  "nexarch_upsert_relationships",
86
+ "nexarch_emit_observations",
26
87
  ];
27
88
  const missing = required.filter((name) => !toolNames.has(name));
28
89
  checks.push({
@@ -46,6 +107,154 @@ export async function initAgent(args) {
46
107
  ok: Boolean(contract.contractVersion),
47
108
  detail: `version=${contract.contractVersion ?? "unknown"}; entities=${contract.ontology?.entityCodes?.length ?? 0}; relationships=${contract.ontology?.relationshipCodes?.length ?? 0}`,
48
109
  });
110
+ const hasAgentType = (contract.ontology?.entityCodes ?? []).some((code) => code.toLowerCase() === "agent");
111
+ checks.push({
112
+ name: "ontology.agent-type",
113
+ ok: hasAgentType,
114
+ detail: hasAgentType
115
+ ? "entity type 'agent' is enabled"
116
+ : "entity type 'agent' is not enabled for this workspace ontology",
117
+ });
118
+ const preflightPassed = checks.every((c) => c.ok);
119
+ let registration = {
120
+ ok: false,
121
+ detail: "registration not attempted",
122
+ };
123
+ let binding = {
124
+ attempted: false,
125
+ ok: true,
126
+ detail: "not requested",
127
+ };
128
+ if (preflightPassed && policies.policyBundleHash) {
129
+ const nowIso = new Date().toISOString();
130
+ const upsertRaw = await callMcpTool("nexarch_upsert_entities", {
131
+ entities: [
132
+ {
133
+ externalKey: `agent:${agentId}`,
134
+ entityTypeCode: "agent",
135
+ name: `Agent ${agentId}`,
136
+ description: "Agent identity registered from nexarch init-agent handshake",
137
+ confidence: 1,
138
+ attributes: {
139
+ kind: "ai_agent",
140
+ client: "nexarch-cli",
141
+ version: CLI_VERSION,
142
+ companyId: creds.companyId,
143
+ handshake: {
144
+ completedAt: nowIso,
145
+ source: "init-agent",
146
+ },
147
+ },
148
+ },
149
+ ],
150
+ agentContext: {
151
+ agentId,
152
+ agentRunId: `init-agent-${Date.now()}`,
153
+ repoRef: "nexarch-cli/init-agent",
154
+ observedAt: nowIso,
155
+ source: "nexarch-cli",
156
+ model: "n/a",
157
+ provider: "n/a",
158
+ },
159
+ policyContext: {
160
+ policyBundleHash: policies.policyBundleHash,
161
+ alignmentSummary: {
162
+ score: 1,
163
+ violations: [],
164
+ waivers: [],
165
+ },
166
+ },
167
+ dryRun: false,
168
+ });
169
+ const upsert = parseToolText(upsertRaw);
170
+ const firstResult = upsert.results?.[0];
171
+ const failed = Number(upsert.summary?.failed ?? 0) > 0;
172
+ registration = {
173
+ ok: !failed,
174
+ detail: failed
175
+ ? `failed to register agent entry (${upsert.errors?.[0]?.error ?? "unknown"})`
176
+ : `agent entry ${firstResult?.action ?? "upserted"}`,
177
+ graphEntityId: firstResult?.graphEntityId ?? null,
178
+ action: firstResult?.action ?? null,
179
+ errors: upsert.errors,
180
+ };
181
+ if (!registration.ok) {
182
+ await emitInitObservation({
183
+ agentId,
184
+ policyBundleHash: policies.policyBundleHash,
185
+ message: `init-agent registration failed: ${registration.detail}`,
186
+ confidence: 1,
187
+ });
188
+ }
189
+ if (registration.ok && bindToExternalKey) {
190
+ binding.attempted = true;
191
+ const relRaw = await callMcpTool("nexarch_upsert_relationships", {
192
+ relationships: [
193
+ {
194
+ relationshipTypeCode: bindRelationshipType,
195
+ fromEntityExternalKey: `agent:${agentId}`,
196
+ toEntityExternalKey: bindToExternalKey,
197
+ confidence: 1,
198
+ attributes: {
199
+ source: "nexarch-cli-init-agent",
200
+ createdAt: nowIso,
201
+ },
202
+ },
203
+ ],
204
+ agentContext: {
205
+ agentId,
206
+ agentRunId: `init-agent-bind-${Date.now()}`,
207
+ repoRef: "nexarch-cli/init-agent",
208
+ observedAt: nowIso,
209
+ source: "nexarch-cli",
210
+ model: "n/a",
211
+ provider: "n/a",
212
+ },
213
+ policyContext: {
214
+ policyBundleHash: policies.policyBundleHash,
215
+ alignmentSummary: {
216
+ score: 1,
217
+ violations: [],
218
+ waivers: [],
219
+ },
220
+ },
221
+ dryRun: false,
222
+ });
223
+ const rel = parseToolText(relRaw);
224
+ const relResult = rel.results?.[0];
225
+ const relFailed = Number(rel.summary?.failed ?? 0) > 0;
226
+ binding = {
227
+ attempted: true,
228
+ ok: !relFailed,
229
+ detail: relFailed
230
+ ? `failed to bind agent (${rel.errors?.[0]?.error ?? "unknown"})`
231
+ : `agent bound via ${bindRelationshipType}`,
232
+ graphRelationshipId: relResult?.graphRelationshipId ?? null,
233
+ action: relResult?.action ?? null,
234
+ errors: rel.errors,
235
+ };
236
+ if (!binding.ok) {
237
+ await emitInitObservation({
238
+ agentId,
239
+ policyBundleHash: policies.policyBundleHash,
240
+ message: `init-agent binding failed: ${binding.detail}`,
241
+ confidence: 1,
242
+ });
243
+ }
244
+ }
245
+ }
246
+ checks.push({
247
+ name: "agent.registration",
248
+ ok: registration.ok,
249
+ detail: registration.detail,
250
+ });
251
+ if (binding.attempted) {
252
+ checks.push({
253
+ name: "agent.binding",
254
+ ok: binding.ok,
255
+ detail: binding.detail,
256
+ });
257
+ }
49
258
  const allPassed = checks.every((c) => c.ok);
50
259
  if (asJson) {
51
260
  const output = {
@@ -60,6 +269,10 @@ export async function initAgent(args) {
60
269
  },
61
270
  policyBundleHash: policies.policyBundleHash ?? null,
62
271
  contractVersion: contract.contractVersion ?? null,
272
+ agentId,
273
+ registration,
274
+ binding,
275
+ companyId: creds.companyId,
63
276
  };
64
277
  process.stdout.write(`${JSON.stringify(output, null, 2)}\n`);
65
278
  if (strict && !allPassed)
@@ -72,12 +285,18 @@ export async function initAgent(args) {
72
285
  if (check.detail)
73
286
  console.log(` ${check.detail}`);
74
287
  }
288
+ if (registration.graphEntityId) {
289
+ console.log(`\nRegistered graph entity: ${registration.graphEntityId}`);
290
+ }
291
+ if (binding.attempted && binding.graphRelationshipId) {
292
+ console.log(`Bound relationship id: ${binding.graphRelationshipId}`);
293
+ }
75
294
  console.log("");
76
295
  if (allPassed) {
77
- console.log("✅ Agent handshake completed. Ready for policy-aware ingest.");
296
+ console.log("✅ Agent handshake + registration completed.");
78
297
  }
79
298
  else {
80
- console.log("⚠ Handshake completed with issues.");
299
+ console.log("⚠ Handshake/registration completed with issues.");
81
300
  if (strict) {
82
301
  console.log("Strict mode enabled, exiting non-zero.");
83
302
  process.exitCode = 1;
package/dist/index.js CHANGED
@@ -29,7 +29,9 @@ Usage:
29
29
  nexarch setup Auto-configure your MCP client (Claude Desktop, Cursor, etc.)
30
30
  nexarch mcp-config Print MCP server config block for manual setup
31
31
  nexarch mcp-proxy Run as stdio MCP proxy (used by MCP clients)
32
- nexarch init-agent Run onboarding handshake checks (tools/policies/contract)
32
+ nexarch init-agent Run handshake + mandatory agent registration in graph
33
+ Options: --agent-id <id> --bind-to-external-key <key>
34
+ --bind-relationship-type <code> --json --strict
33
35
  `);
34
36
  process.exit(command ? 1 : 0);
35
37
  }
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.4" },
64
+ clientInfo: { name: "nexarch-cli", version: "0.1.6" },
65
65
  });
66
66
  }
67
67
  export async function mcpListTools() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexarch",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Connect AI coding tools to your Nexarch architecture workspace",
5
5
  "keywords": [
6
6
  "nexarch",