@twin3-ai/agent-id 0.3.20 → 0.3.22
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/bin/agent-id-b1-sync.js +2 -2
- package/bin/agent-id-cloudflare-a1.js +2 -2
- package/bin/agent-id.js +46 -8
- package/domain-proof.js +1 -1
- package/installer.js +13 -13
- package/package.json +6 -2
- package/repository-connector.js +1 -1
- package/site-agent.js +1 -1
package/bin/agent-id-b1-sync.js
CHANGED
|
@@ -15,8 +15,8 @@ Usage:
|
|
|
15
15
|
agent-id-b1-sync --orders ./crm-orders.json --source-id crm-main --url https://example.com
|
|
16
16
|
|
|
17
17
|
Shared environment:
|
|
18
|
-
SITE_AGENT_KEY
|
|
19
|
-
AGENT_ID_ENDPOINT Parent
|
|
18
|
+
SITE_AGENT_KEY xAgent ID Site Agent Key
|
|
19
|
+
AGENT_ID_ENDPOINT Parent xAgent ID origin
|
|
20
20
|
AGENT_ID_B1_STATE Local cursor and retry state path
|
|
21
21
|
|
|
22
22
|
GA4 environment:
|
|
@@ -17,12 +17,12 @@ Usage:
|
|
|
17
17
|
agent-id-cloudflare-a1 --url https://example.com --status
|
|
18
18
|
|
|
19
19
|
Required environment:
|
|
20
|
-
SITE_AGENT_KEY
|
|
20
|
+
SITE_AGENT_KEY xAgent ID Site Agent Key
|
|
21
21
|
CLOUDFLARE_API_TOKEN Read-only Cloudflare Analytics token
|
|
22
22
|
CLOUDFLARE_ZONE_ID Website zone ID
|
|
23
23
|
|
|
24
24
|
Optional environment:
|
|
25
|
-
AGENT_ID_ENDPOINT Parent
|
|
25
|
+
AGENT_ID_ENDPOINT Parent xAgent ID origin
|
|
26
26
|
AGENT_ID_A1_STATE Local cursor and retry state path
|
|
27
27
|
AGENT_ID_A1_INTERVAL_MS Minimum interval between successful syncs
|
|
28
28
|
`);
|
package/bin/agent-id.js
CHANGED
|
@@ -57,6 +57,22 @@ function readJsonFlag(argv, flag) {
|
|
|
57
57
|
return idx >= 0 ? JSON.parse(fs.readFileSync(argv[idx + 1], "utf8")) : undefined;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
function detectPublicRootCandidates(projectRoot) {
|
|
61
|
+
// Conventional publish directories across the common static hosts and
|
|
62
|
+
// frameworks. Only ones that actually exist are offered, and we offer rather
|
|
63
|
+
// than choose: picking a directory to write into is the owner's decision.
|
|
64
|
+
const conventional = ["public", "dist", "build", "out", "_site", "www", "static", "docs"];
|
|
65
|
+
const found = [];
|
|
66
|
+
for (const name of conventional) {
|
|
67
|
+
try {
|
|
68
|
+
if (fs.statSync(path.join(projectRoot, name)).isDirectory()) found.push(`./${name}`);
|
|
69
|
+
} catch (_error) {
|
|
70
|
+
// Absent is the normal case; nothing to report.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return found;
|
|
74
|
+
}
|
|
75
|
+
|
|
60
76
|
function readFlagValue(argv, flag) {
|
|
61
77
|
const idx = argv.indexOf(flag);
|
|
62
78
|
return idx >= 0 ? argv[idx + 1] : undefined;
|
|
@@ -152,7 +168,7 @@ function printReleaseResult(value) {
|
|
|
152
168
|
const manifest = value.manifest || {};
|
|
153
169
|
const packageInfo = manifest.package || {};
|
|
154
170
|
const lines = [
|
|
155
|
-
`
|
|
171
|
+
`xAgent ID release: ${value.ok ? "READY" : "BLOCKED"}`,
|
|
156
172
|
`API: ${manifest.api_origin || endpoint}`,
|
|
157
173
|
`Package: ${packageInfo.name || "@twin3-ai/agent-id"}@${packageInfo.version || "unknown"}`,
|
|
158
174
|
`Signature: ${value.signature_verified ? "verified" : "not verified"}`,
|
|
@@ -370,7 +386,7 @@ function printSignedInstallResult(value) {
|
|
|
370
386
|
const enrollment = value.enrollment || {};
|
|
371
387
|
const executableCommand = (enrollment.next_commands || [])[0];
|
|
372
388
|
const lines = value.dry_run ? [
|
|
373
|
-
"
|
|
389
|
+
"xAgent ID signed installation plan",
|
|
374
390
|
`Site: ${plan.site_url || "unknown"}`,
|
|
375
391
|
`Framework: ${plan.framework || "unknown"}`,
|
|
376
392
|
"Identity: Ed25519, domain-bound",
|
|
@@ -378,7 +394,7 @@ function printSignedInstallResult(value) {
|
|
|
378
394
|
"Copy and run:",
|
|
379
395
|
value.next_command,
|
|
380
396
|
] : [
|
|
381
|
-
"
|
|
397
|
+
"xAgent ID signed installation started",
|
|
382
398
|
`Site: ${plan.site_url || "unknown"}`,
|
|
383
399
|
"Signed identity: created",
|
|
384
400
|
`Domain proof: ${enrollment.proof_receipt?.relative_path || "pending"}`,
|
|
@@ -388,7 +404,7 @@ function printSignedInstallResult(value) {
|
|
|
388
404
|
lines.push(`Deploy ${enrollment.proof_receipt?.relative_path || "the domain proof"}, then run:`);
|
|
389
405
|
lines.push(executableCommand);
|
|
390
406
|
} else {
|
|
391
|
-
lines.push("Next action: publish the domain proof, then verify the domain with
|
|
407
|
+
lines.push("Next action: publish the domain proof, then verify the domain with xAgent ID.");
|
|
392
408
|
}
|
|
393
409
|
}
|
|
394
410
|
lines.push("Use --json for the complete machine-readable result.");
|
|
@@ -1349,7 +1365,7 @@ async function runCli(argv) {
|
|
|
1349
1365
|
const [cmd, url] = argv;
|
|
1350
1366
|
if (!cmd || cmd === "help" || cmd === "--help") {
|
|
1351
1367
|
print([
|
|
1352
|
-
"
|
|
1368
|
+
"xAgent ID",
|
|
1353
1369
|
"",
|
|
1354
1370
|
"Commands:",
|
|
1355
1371
|
"",
|
|
@@ -2809,15 +2825,37 @@ async function runCli(argv) {
|
|
|
2809
2825
|
const projectRoot = readFlagValue(argv, "--project-root") || process.cwd();
|
|
2810
2826
|
const modules = readCsvFlag(argv, "--modules");
|
|
2811
2827
|
const grantedPermissions = readCsvFlag(argv, "--grant");
|
|
2828
|
+
// Existence is checked before the plan is built. buildInstallPlan reports a
|
|
2829
|
+
// missing directory as PROJECT_ROOT_NOT_SITE -- "not a recognizable website
|
|
2830
|
+
// project" -- which sends someone looking for the wrong problem when the
|
|
2831
|
+
// path simply is not there.
|
|
2832
|
+
let realProjectRoot;
|
|
2833
|
+
try {
|
|
2834
|
+
realProjectRoot = fs.realpathSync(path.resolve(projectRoot));
|
|
2835
|
+
} catch (_error) {
|
|
2836
|
+
throw new Error(
|
|
2837
|
+
`INVALID_PROJECT_ROOT: ${path.resolve(projectRoot)} does not exist. ` +
|
|
2838
|
+
"Run this from your website's project directory, or pass --project-root <path>."
|
|
2839
|
+
);
|
|
2840
|
+
}
|
|
2812
2841
|
const detectedPlan = await buildInstallPlan({ url, projectRoot, endpoint, modules, grantedPermissions });
|
|
2813
2842
|
const publicRoot = path.resolve(readFlagValue(argv, "--public-root") || projectRoot);
|
|
2814
|
-
let realProjectRoot;
|
|
2815
2843
|
let realPublicRoot;
|
|
2816
2844
|
try {
|
|
2817
|
-
realProjectRoot = fs.realpathSync(path.resolve(projectRoot));
|
|
2818
2845
|
realPublicRoot = fs.realpathSync(publicRoot);
|
|
2819
2846
|
} catch (_error) {
|
|
2820
|
-
|
|
2847
|
+
// The first command a new user pastes fails here whenever their publish
|
|
2848
|
+
// directory is not named "public". Naming the candidates we can see beats
|
|
2849
|
+
// making them guess, and beats guessing on their behalf.
|
|
2850
|
+
const candidates = detectPublicRootCandidates(realProjectRoot);
|
|
2851
|
+
const hint = candidates.length
|
|
2852
|
+
? `Directories here that look like a publish root: ${candidates.join(", ")}.`
|
|
2853
|
+
: "No conventional publish directory was found here. If the site publishes " +
|
|
2854
|
+
"from the project root itself, pass --public-root .";
|
|
2855
|
+
throw new Error(
|
|
2856
|
+
`INVALID_PUBLIC_ROOT: ${publicRoot} does not exist. ${hint} ` +
|
|
2857
|
+
"Pass --public-root <path> pointing at the directory your site publishes."
|
|
2858
|
+
);
|
|
2821
2859
|
}
|
|
2822
2860
|
const relativePublicRoot = path.relative(realProjectRoot, realPublicRoot);
|
|
2823
2861
|
if (relativePublicRoot.startsWith("..") || path.isAbsolute(relativePublicRoot)) {
|
package/domain-proof.js
CHANGED
|
@@ -215,7 +215,7 @@ function buildSiteAgentVerificationDocument(registration) {
|
|
|
215
215
|
const host = exactHostname(registration.host);
|
|
216
216
|
const verificationToken = requiredString(registration.verification.token, "verification.token");
|
|
217
217
|
if (!verificationToken.startsWith("av_")) {
|
|
218
|
-
throw proofError("invalid_site_registration", "verification.token must be an
|
|
218
|
+
throw proofError("invalid_site_registration", "verification.token must be an xAgent ID verification token");
|
|
219
219
|
}
|
|
220
220
|
return {
|
|
221
221
|
schema: SITE_VERIFICATION_SCHEMA,
|
package/installer.js
CHANGED
|
@@ -32,7 +32,7 @@ function normalizeInstallSelection(modules, grantedPermissions) {
|
|
|
32
32
|
const selected = [...new Set((Array.isArray(modules) && modules.length ? modules : DEFAULT_INSTALL_MODULES).map(String))];
|
|
33
33
|
const unknown = selected.filter((name) => !INSTALL_MODULES[name]);
|
|
34
34
|
if (unknown.length) throw installError("INVALID_INSTALL_MODULE", `Unknown install modules: ${unknown.join(", ")}`);
|
|
35
|
-
if (!selected.includes("identity")) throw installError("INSTALL_IDENTITY_REQUIRED", "The identity module is required for every
|
|
35
|
+
if (!selected.includes("identity")) throw installError("INSTALL_IDENTITY_REQUIRED", "The identity module is required for every xAgent ID installation.");
|
|
36
36
|
const granted = [...new Set((Array.isArray(grantedPermissions) ? grantedPermissions : selected.map((name) => INSTALL_MODULES[name].permission)).map(String))];
|
|
37
37
|
const missing = selected.filter((name) => !granted.includes(INSTALL_MODULES[name].permission));
|
|
38
38
|
if (missing.length) throw installError("INSTALL_PERMISSION_REQUIRED", `Missing permissions for modules: ${missing.join(", ")}`);
|
|
@@ -226,7 +226,7 @@ async function call(action, payload = {}) {
|
|
|
226
226
|
let body;
|
|
227
227
|
try { body = JSON.parse(text || "{}"); } catch (_error) { body = { text }; }
|
|
228
228
|
if (!response.ok || body.ok === false) {
|
|
229
|
-
const error = new Error("
|
|
229
|
+
const error = new Error("xAgent ID sync failed: " + response.status);
|
|
230
230
|
error.status = response.status;
|
|
231
231
|
error.body = redact(body);
|
|
232
232
|
throw error;
|
|
@@ -235,7 +235,7 @@ async function call(action, payload = {}) {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
async function main() {
|
|
238
|
-
if (!AGENT_ID_ENDPOINT) throw new Error("AGENT_ID_ENDPOINT is required. Use the stable
|
|
238
|
+
if (!AGENT_ID_ENDPOINT) throw new Error("AGENT_ID_ENDPOINT is required. Use the stable xAgent ID API domain supplied by the service owner.");
|
|
239
239
|
if (!SITE_AGENT_KEY) throw new Error("SITE_AGENT_KEY is required in the customer-owned runner environment.");
|
|
240
240
|
if (!["heartbeat", "monthly", "full"].includes(SYNC_MODE)) throw new Error("AGENT_ID_SYNC_MODE must be heartbeat, monthly, or full.");
|
|
241
241
|
const observedAt = new Date().toISOString();
|
|
@@ -279,7 +279,7 @@ main().catch((error) => {
|
|
|
279
279
|
|
|
280
280
|
function staticWorkflowTemplate(siteUrl) {
|
|
281
281
|
return [
|
|
282
|
-
"name:
|
|
282
|
+
"name: xAgent ID website sync",
|
|
283
283
|
"",
|
|
284
284
|
"on:",
|
|
285
285
|
" workflow_dispatch:",
|
|
@@ -299,7 +299,7 @@ function staticWorkflowTemplate(siteUrl) {
|
|
|
299
299
|
" - uses: actions/setup-node@v4",
|
|
300
300
|
" with:",
|
|
301
301
|
" node-version: '20'",
|
|
302
|
-
" - name: Pull verified insights from
|
|
302
|
+
" - name: Pull verified insights from xAgent ID",
|
|
303
303
|
" run: node .agent-id/runner.cjs",
|
|
304
304
|
" env:",
|
|
305
305
|
` SITE_URL: ${siteUrl}`,
|
|
@@ -320,7 +320,7 @@ function staticWorkflowTemplate(siteUrl) {
|
|
|
320
320
|
|
|
321
321
|
function readmeTemplate(siteUrl, framework, packageManager, endpoint) {
|
|
322
322
|
if (framework === "static") {
|
|
323
|
-
return `#
|
|
323
|
+
return `# xAgent ID Site Agent installation
|
|
324
324
|
|
|
325
325
|
- Site URL: ${siteUrl}
|
|
326
326
|
- Parent service: ${endpoint}
|
|
@@ -328,17 +328,17 @@ function readmeTemplate(siteUrl, framework, packageManager, endpoint) {
|
|
|
328
328
|
|
|
329
329
|
## Required owner actions
|
|
330
330
|
|
|
331
|
-
1. Publish the domain verification document returned by
|
|
331
|
+
1. Publish the domain verification document returned by xAgent ID.
|
|
332
332
|
2. Verify domain ownership and obtain the Site Agent Key.
|
|
333
333
|
3. Save the stable API origin as the repository variable \`AGENT_ID_ENDPOINT\`; do not use a Cloud Run revision URL.
|
|
334
334
|
4. Save the key as the repository secret \`SITE_AGENT_KEY\`.
|
|
335
|
-
5. Run the \`
|
|
335
|
+
5. Run the \`xAgent ID website sync\` workflow once. Keep the daily heartbeat and monthly insights schedules enabled.
|
|
336
336
|
6. Review the uploaded \`agent-id-sync-report\` artifact before approving website changes.
|
|
337
337
|
|
|
338
|
-
The Runner sends a daily connection heartbeat. It pulls evidence-bound optimization insights on the first day of each month; a manual run performs both. It does not expose the key, commit code, deploy the site, or give
|
|
338
|
+
The Runner sends a daily connection heartbeat. It pulls evidence-bound optimization insights on the first day of each month; a manual run performs both. It does not expose the key, commit code, deploy the site, or give xAgent ID direct write access to this repository.
|
|
339
339
|
`;
|
|
340
340
|
}
|
|
341
|
-
return `#
|
|
341
|
+
return `# xAgent ID Site Agent installation
|
|
342
342
|
|
|
343
343
|
- Site URL: ${siteUrl}
|
|
344
344
|
- Detected framework: ${framework}
|
|
@@ -346,13 +346,13 @@ The Runner sends a daily connection heartbeat. It pulls evidence-bound optimizat
|
|
|
346
346
|
|
|
347
347
|
## Next steps
|
|
348
348
|
|
|
349
|
-
1. Publish the domain verification file or DNS record returned by
|
|
349
|
+
1. Publish the domain verification file or DNS record returned by xAgent ID.
|
|
350
350
|
2. Run domain verification from the website owner environment.
|
|
351
351
|
3. Install \`@twin3-ai/agent-id\` in the website server, Worker, CMS connector, or Agent runtime.
|
|
352
352
|
4. Store the issued Site Agent Key as \`SITE_AGENT_KEY\` in the server secret store.
|
|
353
353
|
5. Start \`agent-id-sync --url ${siteUrl} --once\` for a first evidence exchange.
|
|
354
354
|
|
|
355
|
-
This directory contains only the local install state and a server-side helper template. It never contains a Site Agent Key, browser token, customer content, or deployment credentials. The
|
|
355
|
+
This directory contains only the local install state and a server-side helper template. It never contains a Site Agent Key, browser token, customer content, or deployment credentials. The xAgent ID service does not receive direct write access to this website by installing this package.
|
|
356
356
|
`;
|
|
357
357
|
}
|
|
358
358
|
|
|
@@ -578,7 +578,7 @@ function validatePlan(plan) {
|
|
|
578
578
|
for (const file of plan.files) {
|
|
579
579
|
const allowedWorkflow = plan.framework === "static" && file && file.path === ".github/workflows/agent-id-sync.yml";
|
|
580
580
|
if (!file || typeof file.path !== "string" || path.isAbsolute(file.path) || file.path.split(/[\\/]+/).includes("..") || (!file.path.startsWith(`${MANAGED_DIR}/`) && !allowedWorkflow)) {
|
|
581
|
-
throw installError("UNSAFE_INSTALL_PATH", "Installation can only write managed
|
|
581
|
+
throw installError("UNSAFE_INSTALL_PATH", "Installation can only write managed xAgent ID files and its dedicated GitHub Actions workflow.");
|
|
582
582
|
}
|
|
583
583
|
}
|
|
584
584
|
return root;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin3-ai/agent-id",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.22",
|
|
4
4
|
"description": "Domain-bound AgentX portable alias, AEO evidence, and website-Agent integration SDK.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/
|
|
9
|
+
"url": "git+https://github.com/twin3-ai/agent-id.git"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"bin",
|
|
@@ -52,5 +52,9 @@
|
|
|
52
52
|
"agent-id-sync": "bin/agent-id-sync.js",
|
|
53
53
|
"agent-id-cloudflare-a1": "bin/agent-id-cloudflare-a1.js",
|
|
54
54
|
"agent-id-b1-sync": "bin/agent-id-b1-sync.js"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://xagent.id",
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/twin3-ai/agent-id/issues"
|
|
55
59
|
}
|
|
56
60
|
}
|
package/repository-connector.js
CHANGED
|
@@ -201,7 +201,7 @@ async function buildVerifiedArtifactPatch({ repositoryRoot = process.cwd(), arti
|
|
|
201
201
|
changes: artifactBundle.artifacts.map((artifact) => ({
|
|
202
202
|
path: artifact.path,
|
|
203
203
|
content: artifact.content,
|
|
204
|
-
reason: `Signed
|
|
204
|
+
reason: `Signed xAgent ID artifact bundle ${verification.bundle_hash}`
|
|
205
205
|
}))
|
|
206
206
|
});
|
|
207
207
|
return {
|
package/site-agent.js
CHANGED
|
@@ -322,7 +322,7 @@ function createSiteAgentClient(options = {}) {
|
|
|
322
322
|
if (!res.ok || data.ok === false) {
|
|
323
323
|
const error = siteAgentError(
|
|
324
324
|
data.code || "AGENT_ID_PUBLIC_CALL_FAILED",
|
|
325
|
-
data.error || data.message || `
|
|
325
|
+
data.error || data.message || `xAgent ID public call failed with HTTP ${res.status}`
|
|
326
326
|
);
|
|
327
327
|
error.status = res.status;
|
|
328
328
|
const retryAfter = res.headers && typeof res.headers.get === "function" ? res.headers.get("retry-after") : "";
|