nexarch 0.8.15 → 0.8.17
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/dist/commands/init-agent.js +119 -26
- package/dist/lib/trust.js +8 -6
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import { fetchAgentRegistryOrThrow } from "../lib/agent-registry.js";
|
|
|
8
8
|
import { callMcpTool, mcpInitialize, mcpListTools } from "../lib/mcp.js";
|
|
9
9
|
import { buildVersionAttributes } from "../lib/version-normalization.js";
|
|
10
10
|
import { requestTrustAttestation } from "../lib/trust.js";
|
|
11
|
-
const CLI_VERSION = "0.8.
|
|
11
|
+
const CLI_VERSION = "0.8.17";
|
|
12
12
|
const AGENT_ENTITY_TYPE = "agent";
|
|
13
13
|
const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
|
|
14
14
|
function parseFlag(args, flag) {
|
|
@@ -287,13 +287,39 @@ After running, confirm \`"ok": true\` in the JSON output. No further action is n
|
|
|
287
287
|
writeFileSync(filePath, content, "utf8");
|
|
288
288
|
return filePath;
|
|
289
289
|
}
|
|
290
|
+
function managedMarkers(key) {
|
|
291
|
+
return {
|
|
292
|
+
start: `<!-- nexarch:${key}:start -->`,
|
|
293
|
+
end: `<!-- nexarch:${key}:end -->`,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function wrapManagedSection(key, body) {
|
|
297
|
+
const markers = managedMarkers(key);
|
|
298
|
+
return `${markers.start}\n${body.trim()}\n${markers.end}`;
|
|
299
|
+
}
|
|
300
|
+
function replaceManagedSection(existing, key, body) {
|
|
301
|
+
const markers = managedMarkers(key);
|
|
302
|
+
const escapedStart = markers.start.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
303
|
+
const escapedEnd = markers.end.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
304
|
+
const managedRegex = new RegExp(`${escapedStart}[\\s\\S]*?${escapedEnd}`, "gm");
|
|
305
|
+
if (!managedRegex.test(existing))
|
|
306
|
+
return existing;
|
|
307
|
+
const canonicalBlock = wrapManagedSection(key, body);
|
|
308
|
+
let replaced = existing.replace(managedRegex, canonicalBlock);
|
|
309
|
+
// collapse accidental duplicates if multiple managed blocks exist
|
|
310
|
+
replaced = replaced.replace(new RegExp(`(${escapedStart}[\\s\\S]*?${escapedEnd})(?:\\s*${escapedStart}[\\s\\S]*?${escapedEnd})+`, "gm"), "$1");
|
|
311
|
+
return replaced.endsWith("\n") ? replaced : `${replaced}\n`;
|
|
312
|
+
}
|
|
290
313
|
function replaceInjectedSection(existing, sectionHeading, sectionBody) {
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
314
|
+
const escapedHeading = sectionHeading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
315
|
+
const blockRegex = new RegExp(`^${escapedHeading}[\\t ]*\\n[\\s\\S]*?(?=^##\\s|$)`, "gm");
|
|
316
|
+
const matches = existing.match(blockRegex);
|
|
317
|
+
if (!matches || matches.length === 0)
|
|
318
|
+
return existing;
|
|
319
|
+
const canonicalBlock = `${sectionBody.trim()}\n`;
|
|
320
|
+
let replaced = existing.replace(blockRegex, "");
|
|
321
|
+
replaced = replaced.replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
322
|
+
return `${replaced}${replaced ? "\n\n" : ""}${canonicalBlock}`;
|
|
297
323
|
}
|
|
298
324
|
function injectAgentConfigs(registry) {
|
|
299
325
|
const templateByCode = new Map(registry.instructionTemplates.map((t) => [t.code, t]));
|
|
@@ -312,30 +338,37 @@ function injectAgentConfigs(registry) {
|
|
|
312
338
|
const sectionBody = template.body.trim();
|
|
313
339
|
const sectionHeading = target.sectionHeading ?? "## Nexarch Agent Registration";
|
|
314
340
|
const sectionMarker = target.sectionMarker ?? sectionHeading;
|
|
341
|
+
const managedBody = wrapManagedSection("agent-registration", sectionBody);
|
|
315
342
|
if (target.insertionMode === "replace_section") {
|
|
316
|
-
let replaced =
|
|
343
|
+
let replaced = replaceManagedSection(existing, "agent-registration", sectionBody);
|
|
344
|
+
if (replaced === existing) {
|
|
345
|
+
replaced = replaceInjectedSection(existing, sectionHeading, managedBody);
|
|
346
|
+
}
|
|
317
347
|
if (replaced === existing && existing.includes(sectionMarker)) {
|
|
318
348
|
const markerIndex = existing.indexOf(sectionMarker);
|
|
319
349
|
const before = existing.slice(0, markerIndex).replace(/\s*$/, "\n\n");
|
|
320
|
-
replaced = `${before}${
|
|
350
|
+
replaced = `${before}${managedBody}\n`;
|
|
321
351
|
}
|
|
322
352
|
if (replaced !== existing) {
|
|
323
353
|
writeFileSync(filePath, replaced, "utf8");
|
|
324
354
|
results.push({ path: filePath, status: "updated" });
|
|
325
355
|
}
|
|
356
|
+
else if (existing.includes(managedBody) || existing.includes(sectionBody)) {
|
|
357
|
+
results.push({ path: filePath, status: "already_present" });
|
|
358
|
+
}
|
|
326
359
|
else {
|
|
327
360
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
328
|
-
writeFileSync(filePath, existing + separator +
|
|
361
|
+
writeFileSync(filePath, existing + separator + managedBody + "\n", "utf8");
|
|
329
362
|
results.push({ path: filePath, status: "injected" });
|
|
330
363
|
}
|
|
331
364
|
continue;
|
|
332
365
|
}
|
|
333
|
-
|
|
334
|
-
const next = existing + separator + sectionBody + "\n";
|
|
335
|
-
if (next === existing) {
|
|
366
|
+
if (existing.includes(managedBody) || existing.includes(sectionBody)) {
|
|
336
367
|
results.push({ path: filePath, status: "already_present" });
|
|
337
368
|
}
|
|
338
369
|
else {
|
|
370
|
+
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
371
|
+
const next = existing + separator + managedBody + "\n";
|
|
339
372
|
writeFileSync(filePath, next, "utf8");
|
|
340
373
|
results.push({ path: filePath, status: "injected" });
|
|
341
374
|
}
|
|
@@ -360,11 +393,33 @@ function injectTrustAttestationBlock(path, attestation) {
|
|
|
360
393
|
`agent_id: ${attestation.payload.agent_id}`,
|
|
361
394
|
`expires_at: ${expiresAt}`,
|
|
362
395
|
`verify_url: ${verifyUrl}`,
|
|
396
|
+
`token: ${attestation.token}`,
|
|
397
|
+
"",
|
|
398
|
+
].join("\n");
|
|
399
|
+
const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
400
|
+
const managed = wrapManagedSection("trust-attestation", section.trim());
|
|
401
|
+
let replaced = replaceManagedSection(existing, "trust-attestation", section.trim());
|
|
402
|
+
if (replaced === existing) {
|
|
403
|
+
replaced = replaceInjectedSection(existing, "## Nexarch Trust Attestation", managed);
|
|
404
|
+
}
|
|
405
|
+
writeFileSync(path, replaced !== existing ? replaced : `${existing}${existing.endsWith("\n") ? "" : "\n"}${managed}\n`, "utf8");
|
|
406
|
+
}
|
|
407
|
+
function injectTrustAttestationUnavailableBlock(path, reason) {
|
|
408
|
+
const section = [
|
|
409
|
+
"## Nexarch Trust Attestation",
|
|
410
|
+
"",
|
|
411
|
+
"Trust attestation was requested but is currently unavailable.",
|
|
412
|
+
`status: unavailable (${reason})`,
|
|
413
|
+
"action: check MCP gateway TRUST_ATTESTATION_SECRET and restart gateway",
|
|
363
414
|
"",
|
|
364
415
|
].join("\n");
|
|
365
416
|
const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
366
|
-
const
|
|
367
|
-
|
|
417
|
+
const managed = wrapManagedSection("trust-attestation", section.trim());
|
|
418
|
+
let replaced = replaceManagedSection(existing, "trust-attestation", section.trim());
|
|
419
|
+
if (replaced === existing) {
|
|
420
|
+
replaced = replaceInjectedSection(existing, "## Nexarch Trust Attestation", managed);
|
|
421
|
+
}
|
|
422
|
+
writeFileSync(path, replaced !== existing ? replaced : `${existing}${existing.endsWith("\n") ? "" : "\n"}${managed}\n`, "utf8");
|
|
368
423
|
}
|
|
369
424
|
function injectGenericAgentConfig(registry) {
|
|
370
425
|
const templateByCode = new Map(registry.instructionTemplates.map((t) => [t.code, t]));
|
|
@@ -378,20 +433,30 @@ function injectGenericAgentConfig(registry) {
|
|
|
378
433
|
const filePath = join(process.cwd(), target.filePathPattern);
|
|
379
434
|
const sectionBody = template.body.trim();
|
|
380
435
|
const sectionHeading = target.sectionHeading ?? "## Nexarch Agent Registration";
|
|
436
|
+
const managedBody = wrapManagedSection("agent-registration", sectionBody);
|
|
381
437
|
if (!existsSync(filePath)) {
|
|
382
|
-
writeFileSync(filePath, `${
|
|
438
|
+
writeFileSync(filePath, `${managedBody}\n`, "utf8");
|
|
383
439
|
return [{ path: filePath, status: "injected" }];
|
|
384
440
|
}
|
|
385
441
|
const existing = readFileSync(filePath, "utf8");
|
|
386
442
|
if (target.insertionMode === "replace_section") {
|
|
387
|
-
|
|
443
|
+
let replaced = replaceManagedSection(existing, "agent-registration", sectionBody);
|
|
444
|
+
if (replaced === existing) {
|
|
445
|
+
replaced = replaceInjectedSection(existing, sectionHeading, managedBody);
|
|
446
|
+
}
|
|
388
447
|
if (replaced !== existing) {
|
|
389
448
|
writeFileSync(filePath, replaced, "utf8");
|
|
390
449
|
return [{ path: filePath, status: "updated" }];
|
|
391
450
|
}
|
|
451
|
+
if (existing.includes(managedBody) || existing.includes(sectionBody)) {
|
|
452
|
+
return [{ path: filePath, status: "already_present" }];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (existing.includes(managedBody) || existing.includes(sectionBody)) {
|
|
456
|
+
return [{ path: filePath, status: "already_present" }];
|
|
392
457
|
}
|
|
393
458
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
394
|
-
writeFileSync(filePath, existing + separator +
|
|
459
|
+
writeFileSync(filePath, existing + separator + managedBody + "\n", "utf8");
|
|
395
460
|
return [{ path: filePath, status: "injected" }];
|
|
396
461
|
}
|
|
397
462
|
const fallbackTemplate = templateByCode.get("nexarch_agent_registration_v1") ?? registry.instructionTemplates[0];
|
|
@@ -399,19 +464,26 @@ function injectGenericAgentConfig(registry) {
|
|
|
399
464
|
return [];
|
|
400
465
|
const fallbackPath = join(process.cwd(), "AGENTS.md");
|
|
401
466
|
const sectionBody = fallbackTemplate.body.trim();
|
|
467
|
+
const managedBody = wrapManagedSection("agent-registration", sectionBody);
|
|
402
468
|
if (!existsSync(fallbackPath)) {
|
|
403
|
-
writeFileSync(fallbackPath, `${
|
|
469
|
+
writeFileSync(fallbackPath, `${managedBody}\n`, "utf8");
|
|
404
470
|
return [{ path: fallbackPath, status: "injected" }];
|
|
405
471
|
}
|
|
406
472
|
const existing = readFileSync(fallbackPath, "utf8");
|
|
407
473
|
const sectionHeading = "## Nexarch Agent Registration";
|
|
408
|
-
|
|
474
|
+
let replaced = replaceManagedSection(existing, "agent-registration", sectionBody);
|
|
475
|
+
if (replaced === existing) {
|
|
476
|
+
replaced = replaceInjectedSection(existing, sectionHeading, managedBody);
|
|
477
|
+
}
|
|
409
478
|
if (replaced !== existing) {
|
|
410
479
|
writeFileSync(fallbackPath, replaced, "utf8");
|
|
411
480
|
return [{ path: fallbackPath, status: "updated" }];
|
|
412
481
|
}
|
|
482
|
+
if (existing.includes(managedBody) || existing.includes(sectionBody)) {
|
|
483
|
+
return [{ path: fallbackPath, status: "already_present" }];
|
|
484
|
+
}
|
|
413
485
|
const separator = existing.endsWith("\n") ? "" : "\n";
|
|
414
|
-
writeFileSync(fallbackPath, existing + separator +
|
|
486
|
+
writeFileSync(fallbackPath, existing + separator + managedBody + "\n", "utf8");
|
|
415
487
|
return [{ path: fallbackPath, status: "injected" }];
|
|
416
488
|
}
|
|
417
489
|
export async function initAgent(args) {
|
|
@@ -973,6 +1045,7 @@ export async function initAgent(args) {
|
|
|
973
1045
|
let agentConfigResults = [];
|
|
974
1046
|
let instructionsWriteAllowed = false;
|
|
975
1047
|
let trustAttestation = null;
|
|
1048
|
+
let trustAttestationAttempted = false;
|
|
976
1049
|
if (registration.ok) {
|
|
977
1050
|
try {
|
|
978
1051
|
// Save identity so check-in can find the agent key
|
|
@@ -998,16 +1071,20 @@ export async function initAgent(args) {
|
|
|
998
1071
|
agentConfigResults = injectGenericAgentConfig(registry);
|
|
999
1072
|
}
|
|
1000
1073
|
if (agentConfigResults.length > 0) {
|
|
1074
|
+
trustAttestationAttempted = true;
|
|
1001
1075
|
trustAttestation = await requestTrustAttestation(agentId);
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1076
|
+
for (const r of agentConfigResults) {
|
|
1077
|
+
try {
|
|
1078
|
+
if (trustAttestation.ok) {
|
|
1005
1079
|
injectTrustAttestationBlock(r.path, trustAttestation);
|
|
1006
1080
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1081
|
+
else {
|
|
1082
|
+
injectTrustAttestationUnavailableBlock(r.path, trustAttestation.reason ?? "unknown");
|
|
1009
1083
|
}
|
|
1010
1084
|
}
|
|
1085
|
+
catch {
|
|
1086
|
+
// non-fatal
|
|
1087
|
+
}
|
|
1011
1088
|
}
|
|
1012
1089
|
}
|
|
1013
1090
|
}
|
|
@@ -1038,6 +1115,19 @@ export async function initAgent(args) {
|
|
|
1038
1115
|
? `updated ${agentConfigResults.length} instruction target file(s)`
|
|
1039
1116
|
: "no runtime instruction target matched this repository (non-fatal; create AGENTS.md/CLAUDE.md or configure a generic target)",
|
|
1040
1117
|
});
|
|
1118
|
+
checks.push({
|
|
1119
|
+
name: "agent.trust.attestation",
|
|
1120
|
+
ok: !registration.ok || !instructionsWriteAllowed || !trustAttestationAttempted || Boolean(trustAttestation?.ok),
|
|
1121
|
+
detail: !registration.ok
|
|
1122
|
+
? "skipped (registration failed)"
|
|
1123
|
+
: !instructionsWriteAllowed
|
|
1124
|
+
? "skipped (consent not granted)"
|
|
1125
|
+
: !trustAttestationAttempted
|
|
1126
|
+
? "skipped (no instruction target written)"
|
|
1127
|
+
: trustAttestation?.ok
|
|
1128
|
+
? "minted and injected into instruction file(s)"
|
|
1129
|
+
: `unavailable (${trustAttestation?.reason ?? "unknown"})`,
|
|
1130
|
+
});
|
|
1041
1131
|
checks.push({
|
|
1042
1132
|
name: "technology.components",
|
|
1043
1133
|
ok: techComponents.ok,
|
|
@@ -1152,6 +1242,9 @@ export async function initAgent(args) {
|
|
|
1152
1242
|
: `https://mcp.nexarch.ai${trustAttestation.verifyUrl}`;
|
|
1153
1243
|
console.log(` Trust attestation verify URL: ${verifyUrl}`);
|
|
1154
1244
|
}
|
|
1245
|
+
else if (trustAttestationAttempted) {
|
|
1246
|
+
console.log(` Trust attestation unavailable (${trustAttestation?.reason ?? "unknown"}).`);
|
|
1247
|
+
}
|
|
1155
1248
|
}
|
|
1156
1249
|
if (needsIdentityInput) {
|
|
1157
1250
|
console.log("\nℹ Additional identity details are still needed to complete agent profile enrichment.");
|
package/dist/lib/trust.js
CHANGED
|
@@ -26,20 +26,22 @@ export async function requestTrustAttestation(agentId) {
|
|
|
26
26
|
res.on("data", (c) => chunks.push(c));
|
|
27
27
|
res.on("end", () => {
|
|
28
28
|
try {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
30
|
+
const parsed = JSON.parse(raw);
|
|
31
|
+
if (!res.statusCode || res.statusCode >= 400) {
|
|
32
|
+
return resolve({ ok: false, reason: parsed.error?.code ?? parsed.error?.message ?? `http_${res.statusCode ?? 0}` });
|
|
33
|
+
}
|
|
32
34
|
resolve(parsed);
|
|
33
35
|
}
|
|
34
36
|
catch {
|
|
35
|
-
resolve(
|
|
37
|
+
resolve({ ok: false, reason: "parse_error" });
|
|
36
38
|
}
|
|
37
39
|
});
|
|
38
40
|
});
|
|
39
|
-
req.on("error", () => resolve(
|
|
41
|
+
req.on("error", () => resolve({ ok: false, reason: "network_error" }));
|
|
40
42
|
req.on("timeout", () => {
|
|
41
43
|
req.destroy();
|
|
42
|
-
resolve(
|
|
44
|
+
resolve({ ok: false, reason: "timeout" });
|
|
43
45
|
});
|
|
44
46
|
req.write(body);
|
|
45
47
|
req.end();
|