@svsprotocol/solana 0.1.0
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/LICENSE +158 -0
- package/README.md +365 -0
- package/dist/action-production-proof-evidence.js +553 -0
- package/dist/adapter-catalog.d.ts +29 -0
- package/dist/adapter-catalog.js +146 -0
- package/dist/adapter-core.d.ts +48 -0
- package/dist/adapter-core.js +249 -0
- package/dist/approval-signature.js +197 -0
- package/dist/base58.js +69 -0
- package/dist/bot-auth.js +50 -0
- package/dist/bot-certification-evidence.js +342 -0
- package/dist/bot-first-action-runbook.js +299 -0
- package/dist/bot-integration-contract.js +41 -0
- package/dist/certified-submit-status.js +176 -0
- package/dist/common.d.ts +1135 -0
- package/dist/elizaos.d.ts +43 -0
- package/dist/elizaos.js +227 -0
- package/dist/goat.d.ts +47 -0
- package/dist/goat.js +261 -0
- package/dist/index.d.ts +330 -0
- package/dist/index.js +128 -0
- package/dist/protocol.d.ts +205 -0
- package/dist/protocol.js +900 -0
- package/dist/receipt.js +51 -0
- package/dist/signed-proof-read-protection.js +495 -0
- package/dist/solana-agent-kit.d.ts +35 -0
- package/dist/solana-agent-kit.js +151 -0
- package/dist/svs-client.js +1232 -0
- package/dist/vercel-ai.d.ts +47 -0
- package/dist/vercel-ai.js +266 -0
- package/dist/verified-agent-adoption-kit.js +471 -0
- package/dist/verified-agent-profile.js +329 -0
- package/dist/verified-agent-registry-consumer.js +421 -0
- package/dist/verified-agent-registry.d.ts +36 -0
- package/dist/verified-agent-registry.js +826 -0
- package/dist/verified-agent-trust-score.js +335 -0
- package/dist/webhooks.js +834 -0
- package/package.json +72 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { hashObject } from "./receipt.js";
|
|
4
|
+
import {
|
|
5
|
+
VERIFIED_AGENT_PROFILE_VERSION,
|
|
6
|
+
hashVerifiedAgentProfile
|
|
7
|
+
} from "./verified-agent-profile.js";
|
|
8
|
+
import {
|
|
9
|
+
VERIFIED_AGENT_REGISTRY_VERSION,
|
|
10
|
+
hashVerifiedAgentRegistry
|
|
11
|
+
} from "./verified-agent-registry.js";
|
|
12
|
+
|
|
13
|
+
export const VERIFIED_AGENT_ADOPTION_KIT_VERSION = "svs.verified-agent-adoption-kit.v1";
|
|
14
|
+
export const DEFAULT_VERIFIED_AGENT_ADOPTION_KIT_DIR = "./data/security/verified-agent-adoption-kit";
|
|
15
|
+
|
|
16
|
+
export function createVerifiedAgentAdoptionKit({
|
|
17
|
+
profile,
|
|
18
|
+
registry,
|
|
19
|
+
registryUrl = null,
|
|
20
|
+
expectedRegistryHash = null,
|
|
21
|
+
trustManifestUrl = null,
|
|
22
|
+
registryIndexUrl = null,
|
|
23
|
+
profileUrl = null,
|
|
24
|
+
badgeUrl = null,
|
|
25
|
+
previewReadiness = null,
|
|
26
|
+
consumerEvidence = null,
|
|
27
|
+
protocolId = "svs-protocol",
|
|
28
|
+
generatedAt = new Date()
|
|
29
|
+
} = {}) {
|
|
30
|
+
const generatedAtIso = generatedAt instanceof Date ? generatedAt.toISOString() : new Date(generatedAt).toISOString();
|
|
31
|
+
const botId = profile?.agent?.botId ?? null;
|
|
32
|
+
const effectiveRegistryHash = expectedRegistryHash ?? registry?.registryHash ?? null;
|
|
33
|
+
const registryBase = registryUrl ? getUrlBase(registryUrl) : null;
|
|
34
|
+
const registryAgent = Array.isArray(registry?.agents)
|
|
35
|
+
? registry.agents.find((agent) => agent.botId === botId) ?? null
|
|
36
|
+
: null;
|
|
37
|
+
const effectiveProfileUrl = profileUrl ??
|
|
38
|
+
deriveUrl(registryBase, registryAgent?.profilePath) ??
|
|
39
|
+
profile?.agent?.profileUrl;
|
|
40
|
+
const effectiveBadgeUrl = badgeUrl ??
|
|
41
|
+
deriveUrl(registryBase, registryAgent?.badgePath) ??
|
|
42
|
+
profile?.agent?.badgeUrl;
|
|
43
|
+
const effectiveTrustManifestUrl = trustManifestUrl ??
|
|
44
|
+
previewReadiness?.routes?.trustManifestUrl ??
|
|
45
|
+
deriveUrl(registryBase, "trust-manifest.json");
|
|
46
|
+
const effectiveRegistryIndexUrl = registryIndexUrl ??
|
|
47
|
+
previewReadiness?.routes?.indexUrl ??
|
|
48
|
+
deriveUrl(registryBase, "index.html");
|
|
49
|
+
const protocolEnv = createProtocolEnv({
|
|
50
|
+
registryUrl,
|
|
51
|
+
registryHash: effectiveRegistryHash,
|
|
52
|
+
botId,
|
|
53
|
+
profileUrl: effectiveProfileUrl,
|
|
54
|
+
badgeUrl: effectiveBadgeUrl,
|
|
55
|
+
protocolId
|
|
56
|
+
});
|
|
57
|
+
const sdkSnippet = createSdkSnippet({
|
|
58
|
+
registryUrl,
|
|
59
|
+
registryHash: effectiveRegistryHash,
|
|
60
|
+
botId
|
|
61
|
+
});
|
|
62
|
+
const verificationCommands = {
|
|
63
|
+
hosted: registryUrl && effectiveRegistryHash
|
|
64
|
+
? `npm run verify:verified-agent-registry-url -- --url ${registryUrl} --expected-hash ${effectiveRegistryHash}`
|
|
65
|
+
: null,
|
|
66
|
+
local: "npm run verify:verified-agent-registry -- --file ./data/verified-agent-registry/registry.json",
|
|
67
|
+
preview: previewReadiness?.snippets?.checkCommand ?? null
|
|
68
|
+
};
|
|
69
|
+
const adoptionChecklist = [
|
|
70
|
+
"Publish or share the registry directory containing registry.json, trust-manifest.json, index.html, profile JSON, and badge SVG.",
|
|
71
|
+
"Give protocol teams SVS_VERIFIED_AGENT_REGISTRY_URL and SVS_VERIFIED_AGENT_REGISTRY_HASH from this kit.",
|
|
72
|
+
"Require protocols to run the hosted registry verifier or SDK middleware before accepting the bot.",
|
|
73
|
+
"Display the verified-agent badge and profile link in the bot UI or docs.",
|
|
74
|
+
"Regenerate this kit after certification, registry, profile, or preview-readiness evidence changes."
|
|
75
|
+
];
|
|
76
|
+
const refreshReason = createVerifiedAgentAdoptionKitRefreshReason({
|
|
77
|
+
profile,
|
|
78
|
+
registry,
|
|
79
|
+
expectedRegistryHash: effectiveRegistryHash,
|
|
80
|
+
badgeUrl: effectiveBadgeUrl,
|
|
81
|
+
trustManifestUrl: effectiveTrustManifestUrl,
|
|
82
|
+
previewReadiness,
|
|
83
|
+
consumerEvidence
|
|
84
|
+
});
|
|
85
|
+
const checks = [
|
|
86
|
+
kitCheck("Verified-agent profile version is supported", profile?.version === VERIFIED_AGENT_PROFILE_VERSION, profile?.version ?? "missing"),
|
|
87
|
+
kitCheck("Verified-agent profile hash is valid", profile?.profileHash === hashVerifiedAgentProfile(profile), `declared=${profile?.profileHash ?? "missing"} computed=${hashVerifiedAgentProfile(profile) ?? "missing"}`),
|
|
88
|
+
kitCheck("Verified-agent profile is verified", profile?.status?.ok === true && profile?.status?.value === "verified", profile?.status?.value ?? "missing"),
|
|
89
|
+
kitCheck("Verified-agent registry version is supported", registry?.version === VERIFIED_AGENT_REGISTRY_VERSION, registry?.version ?? "missing"),
|
|
90
|
+
kitCheck("Verified-agent registry hash is valid", registry?.registryHash === hashVerifiedAgentRegistry(registry), `declared=${registry?.registryHash ?? "missing"} computed=${hashVerifiedAgentRegistry(registry) ?? "missing"}`),
|
|
91
|
+
kitCheck("Verified-agent registry hash matches expected hash", !expectedRegistryHash || registry?.registryHash === expectedRegistryHash, `expected=${expectedRegistryHash ?? "none"} actual=${registry?.registryHash ?? "missing"}`),
|
|
92
|
+
kitCheck("Verified-agent registry includes profile bot", Boolean(registryAgent), botId ?? "missing"),
|
|
93
|
+
kitCheck("Verified-agent registry profile hash matches profile", registryAgent?.profileHash === profile?.profileHash, `registry=${registryAgent?.profileHash ?? "missing"} profile=${profile?.profileHash ?? "missing"}`),
|
|
94
|
+
kitCheck("Registry URL is copyable", Boolean(registryUrl), registryUrl ?? "missing"),
|
|
95
|
+
kitCheck("Pinned registry hash is copyable", isSha256(effectiveRegistryHash), effectiveRegistryHash ?? "missing"),
|
|
96
|
+
kitCheck("Profile URL is copyable", Boolean(effectiveProfileUrl), effectiveProfileUrl ?? "missing"),
|
|
97
|
+
kitCheck("Badge URL is copyable", Boolean(effectiveBadgeUrl), effectiveBadgeUrl ?? "missing"),
|
|
98
|
+
kitCheck("Protocol env excludes secret material", !containsSecretMaterial(protocolEnv), "redacted"),
|
|
99
|
+
kitCheck("SDK snippet pins registry URL and hash", Boolean(registryUrl && effectiveRegistryHash && sdkSnippet.includes(registryUrl) && sdkSnippet.includes(effectiveRegistryHash)), "snippet"),
|
|
100
|
+
kitCheck("Preview readiness is ready when provided", !previewReadiness || previewReadiness.ok === true && previewReadiness.status === "ready", previewReadiness?.status ?? "not_provided"),
|
|
101
|
+
kitCheck("Consumer evidence is verified when provided", !consumerEvidence || consumerEvidence.ok === true, consumerEvidence?.status ?? "not_provided")
|
|
102
|
+
];
|
|
103
|
+
const failedChecks = checks.filter((check) => !check.ok);
|
|
104
|
+
const unsigned = {
|
|
105
|
+
version: VERIFIED_AGENT_ADOPTION_KIT_VERSION,
|
|
106
|
+
ok: failedChecks.length === 0,
|
|
107
|
+
status: failedChecks.length === 0 ? "ready" : "failed",
|
|
108
|
+
generatedAt: generatedAtIso,
|
|
109
|
+
bot: {
|
|
110
|
+
botId,
|
|
111
|
+
name: profile?.agent?.name ?? botId,
|
|
112
|
+
status: profile?.status?.value ?? null,
|
|
113
|
+
badgeText: profile?.display?.badgeText ?? null,
|
|
114
|
+
certificationHash: profile?.certification?.certificationHash ?? registryAgent?.certificationHash ?? null,
|
|
115
|
+
recordId: profile?.certification?.recordId ?? registryAgent?.recordId ?? null,
|
|
116
|
+
qualityTarget: profile?.qualityTarget ?? registryAgent?.qualityTarget ?? null
|
|
117
|
+
},
|
|
118
|
+
registry: {
|
|
119
|
+
title: registry?.title ?? null,
|
|
120
|
+
registryHash: registry?.registryHash ?? null,
|
|
121
|
+
expectedRegistryHash: effectiveRegistryHash,
|
|
122
|
+
profileCount: registry?.profileCount ?? null,
|
|
123
|
+
verifiedAgentCount: Array.isArray(registry?.agents)
|
|
124
|
+
? registry.agents.filter((agent) => agent.status === "verified" && agent.verification?.ok === true).length
|
|
125
|
+
: null,
|
|
126
|
+
profileHash: profile?.profileHash ?? null,
|
|
127
|
+
trustManifestHash: previewReadiness?.registry?.trustManifestHash ?? null
|
|
128
|
+
},
|
|
129
|
+
urls: {
|
|
130
|
+
registryUrl,
|
|
131
|
+
trustManifestUrl: effectiveTrustManifestUrl,
|
|
132
|
+
registryIndexUrl: effectiveRegistryIndexUrl,
|
|
133
|
+
profileUrl: effectiveProfileUrl,
|
|
134
|
+
badgeUrl: effectiveBadgeUrl
|
|
135
|
+
},
|
|
136
|
+
copy: {
|
|
137
|
+
protocolEnv,
|
|
138
|
+
sdkSnippet,
|
|
139
|
+
verificationCommands,
|
|
140
|
+
adoptionChecklist
|
|
141
|
+
},
|
|
142
|
+
proofs: {
|
|
143
|
+
previewReadinessHash: previewReadiness?.evidenceHash ?? null,
|
|
144
|
+
previewReadinessStatus: previewReadiness?.status ?? null,
|
|
145
|
+
consumerEvidenceHash: consumerEvidence?.evidenceHash ?? null,
|
|
146
|
+
consumerEvidenceStatus: consumerEvidence?.status ?? null
|
|
147
|
+
},
|
|
148
|
+
refreshReason,
|
|
149
|
+
reportSafety: {
|
|
150
|
+
secretsIncluded: false,
|
|
151
|
+
redactedFields: [
|
|
152
|
+
"SVS_BOT_API_KEY",
|
|
153
|
+
"SVS_BOT_REQUEST_SIGNING_SECRET",
|
|
154
|
+
"SVS_BOT_PENDING_REQUEST_SIGNING_SECRET",
|
|
155
|
+
"apiKey",
|
|
156
|
+
"requestSigningSecret",
|
|
157
|
+
"pendingRequestSigningSecret",
|
|
158
|
+
"webhookSecret",
|
|
159
|
+
"svs-request-signature"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
checkCount: checks.length,
|
|
163
|
+
passedCheckCount: checks.length - failedChecks.length,
|
|
164
|
+
failedCheckCount: failedChecks.length,
|
|
165
|
+
checks,
|
|
166
|
+
failedChecks,
|
|
167
|
+
nextAction: failedChecks.length === 0
|
|
168
|
+
? {
|
|
169
|
+
code: "share_verified_agent_adoption_kit",
|
|
170
|
+
message: "Share this non-secret kit with bot teams, protocols, or auditors so they can verify the registry, profile, and badge without dashboard access."
|
|
171
|
+
}
|
|
172
|
+
: {
|
|
173
|
+
code: "repair_verified_agent_adoption_kit",
|
|
174
|
+
message: "Regenerate the verified profile and registry, provide hosted URLs, and rerun the adoption kit before sharing it."
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
...unsigned,
|
|
180
|
+
adoptionKitHash: hashVerifiedAgentAdoptionKit(unsigned)
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function hashVerifiedAgentAdoptionKit(kit) {
|
|
185
|
+
if (!kit || typeof kit !== "object") {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const { adoptionKitHash: _adoptionKitHash, ...unsigned } = kit;
|
|
190
|
+
|
|
191
|
+
return hashObject(unsigned);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function persistVerifiedAgentAdoptionKit({
|
|
195
|
+
outputDir = DEFAULT_VERIFIED_AGENT_ADOPTION_KIT_DIR,
|
|
196
|
+
...options
|
|
197
|
+
} = {}) {
|
|
198
|
+
const kit = createVerifiedAgentAdoptionKit(options);
|
|
199
|
+
const jsonPath = join(outputDir, "adoption-kit.json");
|
|
200
|
+
const readmePath = join(outputDir, "README.md");
|
|
201
|
+
|
|
202
|
+
await mkdir(outputDir, { recursive: true });
|
|
203
|
+
await Promise.all([
|
|
204
|
+
writeFile(jsonPath, `${JSON.stringify(kit, null, 2)}\n`),
|
|
205
|
+
writeFile(readmePath, renderVerifiedAgentAdoptionKitReadme(kit))
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
version: "svs.verified-agent-adoption-kit-persist-result.v1",
|
|
210
|
+
ok: kit.ok,
|
|
211
|
+
status: kit.status,
|
|
212
|
+
outputDir,
|
|
213
|
+
kitPath: jsonPath,
|
|
214
|
+
readmePath,
|
|
215
|
+
adoptionKitHash: kit.adoptionKitHash,
|
|
216
|
+
botId: kit.bot.botId,
|
|
217
|
+
registryHash: kit.registry.registryHash,
|
|
218
|
+
refreshReason: kit.refreshReason,
|
|
219
|
+
nextAction: kit.nextAction,
|
|
220
|
+
kit
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function createVerifiedAgentAdoptionKitRefreshReason({
|
|
225
|
+
profile = null,
|
|
226
|
+
registry = null,
|
|
227
|
+
expectedRegistryHash = null,
|
|
228
|
+
badgeUrl = null,
|
|
229
|
+
trustManifestUrl = null,
|
|
230
|
+
previewReadiness = null,
|
|
231
|
+
consumerEvidence = null
|
|
232
|
+
} = {}) {
|
|
233
|
+
const sourcePins = {
|
|
234
|
+
profileHash: profile?.profileHash ?? null,
|
|
235
|
+
registryHash: registry?.registryHash ?? null,
|
|
236
|
+
expectedRegistryHash: expectedRegistryHash ?? registry?.registryHash ?? null,
|
|
237
|
+
trustManifestHash: registry?.trustManifestHash ?? previewReadiness?.registry?.trustManifestHash ?? null,
|
|
238
|
+
badgeUrl: badgeUrl ?? profile?.agent?.badgeUrl ?? null,
|
|
239
|
+
trustManifestUrl,
|
|
240
|
+
previewReadinessHash: previewReadiness?.evidenceHash ?? null,
|
|
241
|
+
consumerEvidenceHash: consumerEvidence?.evidenceHash ?? null,
|
|
242
|
+
certificationHash: profile?.certification?.certificationHash ?? null,
|
|
243
|
+
recordId: profile?.certification?.recordId ?? null
|
|
244
|
+
};
|
|
245
|
+
const refreshTriggers = [
|
|
246
|
+
sourcePins.profileHash ? "profile hash" : null,
|
|
247
|
+
sourcePins.registryHash ? "registry hash" : null,
|
|
248
|
+
sourcePins.trustManifestHash || sourcePins.trustManifestUrl ? "trust manifest" : null,
|
|
249
|
+
sourcePins.badgeUrl ? "badge URL" : null,
|
|
250
|
+
sourcePins.previewReadinessHash ? "preview-readiness proof" : null,
|
|
251
|
+
sourcePins.consumerEvidenceHash ? "consumer verification proof" : null,
|
|
252
|
+
sourcePins.certificationHash || sourcePins.recordId ? "bot certification" : null
|
|
253
|
+
].filter(Boolean);
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
version: "svs.verified-agent-adoption-kit-refresh-reason.v1",
|
|
257
|
+
reason: "source_pins_current_at_generation",
|
|
258
|
+
summary: refreshTriggers.length
|
|
259
|
+
? `Generated from current ${refreshTriggers.join(", ")}. Regenerate when any source pin changes or the export freshness window expires.`
|
|
260
|
+
: "Generated without complete source pins. Regenerate after profile, registry, badge, trust-manifest, preview, or consumer proof changes.",
|
|
261
|
+
refreshTriggers,
|
|
262
|
+
sourcePins,
|
|
263
|
+
operatorAction: "Regenerate the adoption kit after registry, profile, badge, trust-manifest, preview-readiness, consumer-proof, or certification changes before cutting a release."
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export function compareVerifiedAgentAdoptionKitSourcePins({
|
|
268
|
+
kit = null,
|
|
269
|
+
profile = null,
|
|
270
|
+
registry = null,
|
|
271
|
+
previewReadiness = null,
|
|
272
|
+
consumerEvidence = null,
|
|
273
|
+
expectedRegistryHash = null
|
|
274
|
+
} = {}) {
|
|
275
|
+
const sourcePins = kit?.refreshReason?.sourcePins ?? {};
|
|
276
|
+
const currentPins = {
|
|
277
|
+
profileHash: profile?.profileHash ?? null,
|
|
278
|
+
registryHash: registry?.registryHash ??
|
|
279
|
+
previewReadiness?.registry?.registryHash ??
|
|
280
|
+
previewReadiness?.registryHash ??
|
|
281
|
+
consumerEvidence?.summary?.registryHash ??
|
|
282
|
+
consumerEvidence?.registryHash ??
|
|
283
|
+
null,
|
|
284
|
+
expectedRegistryHash: expectedRegistryHash ??
|
|
285
|
+
registry?.registryHash ??
|
|
286
|
+
previewReadiness?.registry?.registryHash ??
|
|
287
|
+
previewReadiness?.registryHash ??
|
|
288
|
+
consumerEvidence?.summary?.registryHash ??
|
|
289
|
+
consumerEvidence?.registryHash ??
|
|
290
|
+
null,
|
|
291
|
+
trustManifestHash: registry?.trustManifestHash ?? previewReadiness?.registry?.trustManifestHash ?? null,
|
|
292
|
+
previewReadinessHash: previewReadiness?.evidenceHash ?? null,
|
|
293
|
+
consumerEvidenceHash: consumerEvidence?.evidenceHash ?? null,
|
|
294
|
+
certificationHash: profile?.certification?.certificationHash ?? null,
|
|
295
|
+
recordId: profile?.certification?.recordId ?? null
|
|
296
|
+
};
|
|
297
|
+
const comparableFields = [
|
|
298
|
+
"profileHash",
|
|
299
|
+
"registryHash",
|
|
300
|
+
"expectedRegistryHash",
|
|
301
|
+
"trustManifestHash",
|
|
302
|
+
"previewReadinessHash",
|
|
303
|
+
"consumerEvidenceHash",
|
|
304
|
+
"certificationHash",
|
|
305
|
+
"recordId"
|
|
306
|
+
];
|
|
307
|
+
const checks = comparableFields.map((field) => {
|
|
308
|
+
const pinned = sourcePins[field] ?? null;
|
|
309
|
+
const current = currentPins[field] ?? null;
|
|
310
|
+
const comparable = Boolean(pinned && current);
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
field,
|
|
314
|
+
ok: comparable ? pinned === current : true,
|
|
315
|
+
comparable,
|
|
316
|
+
pinned,
|
|
317
|
+
current,
|
|
318
|
+
status: comparable ? pinned === current ? "matched" : "drifted" : "not_checked"
|
|
319
|
+
};
|
|
320
|
+
});
|
|
321
|
+
const driftedFields = checks.filter((check) => check.status === "drifted").map((check) => check.field);
|
|
322
|
+
const comparableFieldsChecked = checks.filter((check) => check.comparable).map((check) => check.field);
|
|
323
|
+
const notCheckedFields = checks.filter((check) => !check.comparable).map((check) => check.field);
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
version: "svs.verified-agent-adoption-kit-source-pin-comparison.v1",
|
|
327
|
+
ok: driftedFields.length === 0,
|
|
328
|
+
status: driftedFields.length === 0 ? "matched" : "drifted",
|
|
329
|
+
sourcePins,
|
|
330
|
+
currentPins,
|
|
331
|
+
comparableFields: comparableFieldsChecked,
|
|
332
|
+
notCheckedFields,
|
|
333
|
+
driftedFields,
|
|
334
|
+
checks,
|
|
335
|
+
summary: driftedFields.length === 0
|
|
336
|
+
? comparableFieldsChecked.length
|
|
337
|
+
? `Source pins match current evidence for ${comparableFieldsChecked.join(", ")}.`
|
|
338
|
+
: "No current source evidence was available for source-pin comparison."
|
|
339
|
+
: `Source pin drift detected for ${driftedFields.join(", ")}. Regenerate the adoption kit before release.`
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function renderVerifiedAgentAdoptionKitReadme(kit) {
|
|
344
|
+
const commands = kit?.copy?.verificationCommands ?? {};
|
|
345
|
+
const refresh = kit?.refreshReason ?? null;
|
|
346
|
+
|
|
347
|
+
return `# SVS Verified Agent Adoption Kit
|
|
348
|
+
|
|
349
|
+
Bot: ${kit?.bot?.botId ?? "unknown"}
|
|
350
|
+
Status: ${kit?.status ?? "unknown"}
|
|
351
|
+
Registry hash: ${kit?.registry?.registryHash ?? "missing"}
|
|
352
|
+
Adoption kit hash: ${kit?.adoptionKitHash ?? "missing"}
|
|
353
|
+
Refresh reason: ${refresh?.summary ?? "not recorded"}
|
|
354
|
+
|
|
355
|
+
## Protocol Env
|
|
356
|
+
|
|
357
|
+
\`\`\`sh
|
|
358
|
+
${kit?.copy?.protocolEnv ?? ""}
|
|
359
|
+
\`\`\`
|
|
360
|
+
|
|
361
|
+
## SDK Check
|
|
362
|
+
|
|
363
|
+
\`\`\`js
|
|
364
|
+
${kit?.copy?.sdkSnippet ?? ""}
|
|
365
|
+
\`\`\`
|
|
366
|
+
|
|
367
|
+
## Verify
|
|
368
|
+
|
|
369
|
+
\`\`\`sh
|
|
370
|
+
${commands.hosted ?? commands.local ?? ""}
|
|
371
|
+
\`\`\`
|
|
372
|
+
|
|
373
|
+
## Freshness and Fail-Closed Export
|
|
374
|
+
|
|
375
|
+
This kit is a portable handoff for protocols, bot teams, and auditors. It must stay current with the registry, trust manifest, agent profile, badge, and preview-readiness proof that it points to. Deployment-ready verification sets can enforce \`verifiedAgentAdoptionKitStaleAfterMs\`; when that policy is required, export and verifier checks fail closed if the embedded kit is too old or no longer matches the pinned registry/profile proof. Regenerate the kit after registry, profile, badge, trust-manifest, or preview-proof changes before cutting a release.
|
|
376
|
+
|
|
377
|
+
Refresh trigger summary: ${refresh?.summary ?? "not recorded"}
|
|
378
|
+
|
|
379
|
+
Pinned refresh inputs:
|
|
380
|
+
|
|
381
|
+
- Profile hash: ${refresh?.sourcePins?.profileHash ?? "missing"}
|
|
382
|
+
- Registry hash: ${refresh?.sourcePins?.registryHash ?? "missing"}
|
|
383
|
+
- Trust manifest hash: ${refresh?.sourcePins?.trustManifestHash ?? "missing"}
|
|
384
|
+
- Badge URL: ${refresh?.sourcePins?.badgeUrl ?? "missing"}
|
|
385
|
+
- Preview-readiness proof: ${refresh?.sourcePins?.previewReadinessHash ?? "missing"}
|
|
386
|
+
- Consumer verification proof: ${refresh?.sourcePins?.consumerEvidenceHash ?? "missing"}
|
|
387
|
+
- Bot certification: ${refresh?.sourcePins?.certificationHash ?? "missing"}
|
|
388
|
+
|
|
389
|
+
## Links
|
|
390
|
+
|
|
391
|
+
- Registry: ${kit?.urls?.registryUrl ?? "missing"}
|
|
392
|
+
- Trust manifest: ${kit?.urls?.trustManifestUrl ?? "missing"}
|
|
393
|
+
- Profile: ${kit?.urls?.profileUrl ?? "missing"}
|
|
394
|
+
- Badge: ${kit?.urls?.badgeUrl ?? "missing"}
|
|
395
|
+
|
|
396
|
+
## Checklist
|
|
397
|
+
|
|
398
|
+
${(kit?.copy?.adoptionChecklist ?? []).map((item) => `- ${item}`).join("\n")}
|
|
399
|
+
|
|
400
|
+
## Safety
|
|
401
|
+
|
|
402
|
+
This handoff is designed to be non-secret. It should contain public registry URLs, hashes, profile links, badge links, verifier commands, and protocol snippets only.
|
|
403
|
+
`;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function createProtocolEnv({
|
|
407
|
+
registryUrl,
|
|
408
|
+
registryHash,
|
|
409
|
+
botId,
|
|
410
|
+
profileUrl,
|
|
411
|
+
badgeUrl,
|
|
412
|
+
protocolId
|
|
413
|
+
}) {
|
|
414
|
+
return [
|
|
415
|
+
`SVS_PROTOCOL_ID=${protocolId}`,
|
|
416
|
+
`SVS_AGENT_BOT_ID=${botId ?? "REPLACE_WITH_BOT_ID"}`,
|
|
417
|
+
`SVS_VERIFIED_AGENT_REGISTRY_URL=${registryUrl ?? "REPLACE_WITH_REGISTRY_JSON_URL"}`,
|
|
418
|
+
`SVS_VERIFIED_AGENT_REGISTRY_HASH=${registryHash ?? "REPLACE_WITH_REGISTRY_HASH"}`,
|
|
419
|
+
`SVS_VERIFIED_AGENT_PROFILE_URL=${profileUrl ?? "REPLACE_WITH_PROFILE_JSON_URL"}`,
|
|
420
|
+
`SVS_VERIFIED_AGENT_BADGE_URL=${badgeUrl ?? "REPLACE_WITH_BADGE_SVG_URL"}`
|
|
421
|
+
].join("\n");
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function createSdkSnippet({ registryUrl, registryHash, botId }) {
|
|
425
|
+
return `import { createHostedVerifiedAgentRegistryMiddleware } from "@svsprotocol/solana/protocol";
|
|
426
|
+
|
|
427
|
+
const requireSvsAgent = createHostedVerifiedAgentRegistryMiddleware({
|
|
428
|
+
registryUrl: "${registryUrl ?? "REPLACE_WITH_REGISTRY_JSON_URL"}",
|
|
429
|
+
expectedRegistryHash: "${registryHash ?? "REPLACE_WITH_REGISTRY_HASH"}"
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await requireSvsAgent({ botId: "${botId ?? "REPLACE_WITH_BOT_ID"}" });`;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function deriveUrl(baseUrl, relativePath) {
|
|
436
|
+
if (!baseUrl || !relativePath) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
try {
|
|
441
|
+
return new URL(relativePath, baseUrl).toString();
|
|
442
|
+
} catch {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function getUrlBase(url) {
|
|
448
|
+
try {
|
|
449
|
+
return new URL(".", url.endsWith("/") ? url : url).toString();
|
|
450
|
+
} catch {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function kitCheck(name, ok, detail = null) {
|
|
456
|
+
return {
|
|
457
|
+
name,
|
|
458
|
+
ok: ok === true,
|
|
459
|
+
detail
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function isSha256(value) {
|
|
464
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/i.test(value);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function containsSecretMaterial(value) {
|
|
468
|
+
const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
|
|
469
|
+
|
|
470
|
+
return /(SVS_BOT_API_KEY|SVS_BOT_REQUEST_SIGNING_SECRET|requestSigningSecret|pendingRequestSigningSecret|webhookSecret|svs-request-signature)\s*=/i.test(text);
|
|
471
|
+
}
|