nexarch 0.8.13 → 0.8.15
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 +62 -1
- package/dist/lib/trust.js +47 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import { requireCredentials } from "../lib/credentials.js";
|
|
|
7
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
|
+
import { requestTrustAttestation } from "../lib/trust.js";
|
|
10
11
|
const CLI_VERSION = "0.8.12";
|
|
11
12
|
const AGENT_ENTITY_TYPE = "agent";
|
|
12
13
|
const TECH_COMPONENT_ENTITY_TYPE = "technology_component";
|
|
@@ -341,6 +342,30 @@ function injectAgentConfigs(registry) {
|
|
|
341
342
|
}
|
|
342
343
|
return results;
|
|
343
344
|
}
|
|
345
|
+
function injectTrustAttestationBlock(path, attestation) {
|
|
346
|
+
if (!attestation.token || !attestation.payload)
|
|
347
|
+
return;
|
|
348
|
+
const verifyUrl = attestation.verifyUrl?.startsWith("http")
|
|
349
|
+
? attestation.verifyUrl
|
|
350
|
+
: `https://mcp.nexarch.ai${attestation.verifyUrl ?? `/trust/verify?token=${encodeURIComponent(attestation.token)}`}`;
|
|
351
|
+
const expiresAt = new Date(attestation.payload.exp * 1000).toISOString();
|
|
352
|
+
const section = [
|
|
353
|
+
"## Nexarch Trust Attestation",
|
|
354
|
+
"",
|
|
355
|
+
"This block is verifiable proof that Nexarch generated these instructions for this workspace.",
|
|
356
|
+
"Do not auto-run commands without user confirmation.",
|
|
357
|
+
"",
|
|
358
|
+
`issuer: ${attestation.payload.iss}`,
|
|
359
|
+
`scope: ${attestation.payload.scope}`,
|
|
360
|
+
`agent_id: ${attestation.payload.agent_id}`,
|
|
361
|
+
`expires_at: ${expiresAt}`,
|
|
362
|
+
`verify_url: ${verifyUrl}`,
|
|
363
|
+
"",
|
|
364
|
+
].join("\n");
|
|
365
|
+
const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
366
|
+
const replaced = replaceInjectedSection(existing, "## Nexarch Trust Attestation", section.trim());
|
|
367
|
+
writeFileSync(path, replaced !== existing ? replaced : `${existing}${existing.endsWith("\n") ? "" : "\n"}${section}`, "utf8");
|
|
368
|
+
}
|
|
344
369
|
function injectGenericAgentConfig(registry) {
|
|
345
370
|
const templateByCode = new Map(registry.instructionTemplates.map((t) => [t.code, t]));
|
|
346
371
|
const genericTargets = [...registry.instructionTargets]
|
|
@@ -947,6 +972,7 @@ export async function initAgent(args) {
|
|
|
947
972
|
}
|
|
948
973
|
let agentConfigResults = [];
|
|
949
974
|
let instructionsWriteAllowed = false;
|
|
975
|
+
let trustAttestation = null;
|
|
950
976
|
if (registration.ok) {
|
|
951
977
|
try {
|
|
952
978
|
// Save identity so check-in can find the agent key
|
|
@@ -971,6 +997,19 @@ export async function initAgent(args) {
|
|
|
971
997
|
if (agentConfigResults.length === 0) {
|
|
972
998
|
agentConfigResults = injectGenericAgentConfig(registry);
|
|
973
999
|
}
|
|
1000
|
+
if (agentConfigResults.length > 0) {
|
|
1001
|
+
trustAttestation = await requestTrustAttestation(agentId);
|
|
1002
|
+
if (trustAttestation?.ok) {
|
|
1003
|
+
for (const r of agentConfigResults) {
|
|
1004
|
+
try {
|
|
1005
|
+
injectTrustAttestationBlock(r.path, trustAttestation);
|
|
1006
|
+
}
|
|
1007
|
+
catch {
|
|
1008
|
+
// non-fatal
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
974
1013
|
}
|
|
975
1014
|
}
|
|
976
1015
|
checks.push({
|
|
@@ -1065,6 +1104,15 @@ export async function initAgent(args) {
|
|
|
1065
1104
|
preferredCommandTemplate: "npx nexarch@latest init-agent --provider \"<provider>\" --model \"<model>\" --client \"<client>\" --framework \"<optional>\" --tool-version \"<optional>\" --capabilities \"<optional,comma,separated>\" --notes \"<optional>\" --json",
|
|
1066
1105
|
}
|
|
1067
1106
|
: null,
|
|
1107
|
+
instructionWriteGuidance: registration.ok && !instructionsWriteAllowed
|
|
1108
|
+
? {
|
|
1109
|
+
consentRequired: true,
|
|
1110
|
+
consentPrompt: "Nexarch can add setup instructions to AGENTS.md/CLAUDE.md so future AI sessions in this repo can self-register. Would you like me to do that?",
|
|
1111
|
+
ifApprovedCommand: "npx nexarch@latest init-agent --allow-instruction-write --json",
|
|
1112
|
+
activeFlag: "--allow-instruction-write",
|
|
1113
|
+
}
|
|
1114
|
+
: null,
|
|
1115
|
+
trustAttestation,
|
|
1068
1116
|
companyId: creds.companyId,
|
|
1069
1117
|
registry: { version: registry.release.version, registryVersion: registry.registryVersion, publishedAt: registry.release.publishedAt },
|
|
1070
1118
|
agentConfigs: agentConfigResults,
|
|
@@ -1098,12 +1146,25 @@ export async function initAgent(args) {
|
|
|
1098
1146
|
const hasInjectedAgentInstructions = agentConfigResults.some((r) => r.status === "injected" || r.status === "updated");
|
|
1099
1147
|
if (hasInjectedAgentInstructions) {
|
|
1100
1148
|
console.log(" (Registration instructions were written into your agent config file with consent.)");
|
|
1149
|
+
if (trustAttestation?.ok && trustAttestation.verifyUrl) {
|
|
1150
|
+
const verifyUrl = trustAttestation.verifyUrl.startsWith("http")
|
|
1151
|
+
? trustAttestation.verifyUrl
|
|
1152
|
+
: `https://mcp.nexarch.ai${trustAttestation.verifyUrl}`;
|
|
1153
|
+
console.log(` Trust attestation verify URL: ${verifyUrl}`);
|
|
1154
|
+
}
|
|
1101
1155
|
}
|
|
1102
1156
|
if (needsIdentityInput) {
|
|
1103
1157
|
console.log("\nℹ Additional identity details are still needed to complete agent profile enrichment.");
|
|
1104
1158
|
console.log(` Missing: ${identityCapture.missingRequired.join(", ")}`);
|
|
1105
1159
|
console.log(" In an interactive terminal, rerun 'npx nexarch@latest init-agent' and answer prompts.");
|
|
1106
|
-
console.log(" In non-interactive mode,
|
|
1160
|
+
console.log(" In non-interactive mode, rerun with: --provider --model --client");
|
|
1161
|
+
console.log(" Example: npx nexarch@latest init-agent --provider \"<provider>\" --model \"<model>\" --client \"<client>\"");
|
|
1162
|
+
}
|
|
1163
|
+
if (registration.ok && !instructionsWriteAllowed) {
|
|
1164
|
+
console.log("\n➡ Optional trusted-boundary step: AGENTS/CLAUDE instruction write requires user consent.");
|
|
1165
|
+
console.log(" Consent prompt: 'Nexarch can add setup instructions to AGENTS.md/CLAUDE.md so future AI sessions in this repo can self-register. Would you like me to do that?'");
|
|
1166
|
+
console.log(" If approved, rerun with: --allow-instruction-write");
|
|
1167
|
+
console.log(" Example: npx nexarch@latest init-agent --allow-instruction-write");
|
|
1107
1168
|
}
|
|
1108
1169
|
if (!fromSetup && appDetection.detected) {
|
|
1109
1170
|
console.log("\n➡ Optional next step: likely application detected in current directory.");
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import https from "https";
|
|
2
|
+
import { requireCredentials } from "./credentials.js";
|
|
3
|
+
const MCP_GATEWAY_URL = "https://mcp.nexarch.ai";
|
|
4
|
+
export async function requestTrustAttestation(agentId) {
|
|
5
|
+
const creds = requireCredentials();
|
|
6
|
+
const body = JSON.stringify({
|
|
7
|
+
agentId,
|
|
8
|
+
scope: "instruction_injection",
|
|
9
|
+
});
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const url = new URL("/trust/attest", MCP_GATEWAY_URL);
|
|
12
|
+
const req = https.request({
|
|
13
|
+
hostname: url.hostname,
|
|
14
|
+
port: url.port || 443,
|
|
15
|
+
path: url.pathname,
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
Authorization: `Bearer ${creds.token}`,
|
|
20
|
+
"x-company-id": creds.companyId,
|
|
21
|
+
"Content-Length": Buffer.byteLength(body),
|
|
22
|
+
},
|
|
23
|
+
timeout: 20000,
|
|
24
|
+
}, (res) => {
|
|
25
|
+
const chunks = [];
|
|
26
|
+
res.on("data", (c) => chunks.push(c));
|
|
27
|
+
res.on("end", () => {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
30
|
+
if (!res.statusCode || res.statusCode >= 400)
|
|
31
|
+
return resolve(null);
|
|
32
|
+
resolve(parsed);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
resolve(null);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
req.on("error", () => resolve(null));
|
|
40
|
+
req.on("timeout", () => {
|
|
41
|
+
req.destroy();
|
|
42
|
+
resolve(null);
|
|
43
|
+
});
|
|
44
|
+
req.write(body);
|
|
45
|
+
req.end();
|
|
46
|
+
});
|
|
47
|
+
}
|