@agentvalet/register 0.4.12 → 0.4.13
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/index.js +298 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -192,7 +192,7 @@ async function saveOutput(opts) {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// src/commands/refresh.ts
|
|
195
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync, statSync } from "fs";
|
|
195
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2, statSync } from "fs";
|
|
196
196
|
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
197
197
|
|
|
198
198
|
// src/lib/jwt.ts
|
|
@@ -211,7 +211,7 @@ function signJwt(agentId, ownerId, privateKeyPem) {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
// src/lib/skill-writer.ts
|
|
214
|
-
import { existsSync, writeFileSync } from "fs";
|
|
214
|
+
import { existsSync, writeFileSync, mkdirSync } from "fs";
|
|
215
215
|
import { execSync } from "child_process";
|
|
216
216
|
import path from "path";
|
|
217
217
|
import chalk2 from "chalk";
|
|
@@ -316,6 +316,11 @@ The \`.mcp.json\` in this directory has been configured. Run \`/mcp\` in Claude
|
|
|
316
316
|
if (detected.openclaw) {
|
|
317
317
|
lines.push(`### OpenClaw
|
|
318
318
|
See \`SKILL.md\` for platform call instructions.`);
|
|
319
|
+
}
|
|
320
|
+
if (detected.factoryDroid) {
|
|
321
|
+
lines.push(`### Factory Droid
|
|
322
|
+
\`~/.factory/mcp.json\` has been updated with the AgentValet MCP server block.
|
|
323
|
+
Type \`@AgentValet\` in Factory Droid to activate governance. Use \`/av-status\` to verify connections.`);
|
|
319
324
|
}
|
|
320
325
|
if (lines.length === 0) {
|
|
321
326
|
lines.push(`Add the MCP server to your IDE manually. See: https://docs.agentvalet.ai/setup`);
|
|
@@ -370,6 +375,203 @@ AGENT_PRIVATE_KEY_PATH=${keyPath}
|
|
|
370
375
|
console.log(chalk2.green(" \u2713 AGENTVALET.md created \u2014 quick reference for this agent"));
|
|
371
376
|
console.log(chalk2.dim(" Add to .gitignore if it contains sensitive paths"));
|
|
372
377
|
}
|
|
378
|
+
function writeFactoryDroidDroid() {
|
|
379
|
+
const droidsDir = path.join(process.cwd(), ".factory", "droids");
|
|
380
|
+
if (!existsSync(droidsDir)) mkdirSync(droidsDir, { recursive: true });
|
|
381
|
+
const dest = path.join(droidsDir, "agentvalet.yaml");
|
|
382
|
+
if (existsSync(dest)) {
|
|
383
|
+
console.log(chalk2.dim(" Factory Droid: .factory/droids/agentvalet.yaml already exists"));
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const content = `# AgentValet Governance Droid
|
|
387
|
+
# Automatically created by @agentvalet/register
|
|
388
|
+
# Commit this file to your repo
|
|
389
|
+
|
|
390
|
+
name: AgentValet
|
|
391
|
+
description: >
|
|
392
|
+
Routes all platform API calls through AgentValet's credential
|
|
393
|
+
proxy. Enforces per-agent permissions, rate limits, and human
|
|
394
|
+
approval for high-risk operations. Every call is logged.
|
|
395
|
+
|
|
396
|
+
model: inherit
|
|
397
|
+
|
|
398
|
+
mcp_servers:
|
|
399
|
+
- agentvalet
|
|
400
|
+
|
|
401
|
+
autonomy: Low
|
|
402
|
+
|
|
403
|
+
instructions: |
|
|
404
|
+
You are operating under AgentValet credential governance.
|
|
405
|
+
|
|
406
|
+
## Rules \u2014 read before every platform call
|
|
407
|
+
|
|
408
|
+
1. NEVER call platform APIs (Slack, Stripe, Gmail, GitHub, etc.) directly.
|
|
409
|
+
Always use the \`use_platform\` MCP tool.
|
|
410
|
+
|
|
411
|
+
2. Call \`list_platforms\` at the start of any session that involves
|
|
412
|
+
platform calls. Do not assume platforms are available.
|
|
413
|
+
|
|
414
|
+
3. Call \`authzen_evaluate\` before any destructive operation
|
|
415
|
+
(delete, send, charge, publish). Do not proceed if decision=false.
|
|
416
|
+
|
|
417
|
+
4. If \`use_platform\` returns \`{ status: "pending_approval" }\`,
|
|
418
|
+
wait for human approval. Do not retry the call.
|
|
419
|
+
|
|
420
|
+
5. If AgentValet MCP tools are unavailable, stop and tell the user:
|
|
421
|
+
"AgentValet MCP is not connected. Run: npx @agentvalet/register"
|
|
422
|
+
Do not attempt platform calls without governance.
|
|
423
|
+
|
|
424
|
+
## Making a platform call
|
|
425
|
+
|
|
426
|
+
\`\`\`
|
|
427
|
+
use_platform({
|
|
428
|
+
platform: "slack",
|
|
429
|
+
endpoint: "/api/chat.postMessage",
|
|
430
|
+
method: "POST",
|
|
431
|
+
scope: "slack:write",
|
|
432
|
+
data: { channel: "#general", text: "Hello" }
|
|
433
|
+
})
|
|
434
|
+
\`\`\`
|
|
435
|
+
|
|
436
|
+
## Scope categories
|
|
437
|
+
|
|
438
|
+
- Read scopes (*.read, *.list) \u2014 lower risk, may auto-approve
|
|
439
|
+
- Write scopes (*.write, *.create) \u2014 check authzen_evaluate first
|
|
440
|
+
- Destructive scopes (*.delete, stripe:charge, mail:send) \u2014 always
|
|
441
|
+
call authzen_evaluate, always inform user before proceeding
|
|
442
|
+
|
|
443
|
+
Dashboard: https://app.agentvalet.ai
|
|
444
|
+
Docs: https://docs.agentvalet.ai
|
|
445
|
+
`;
|
|
446
|
+
writeFileSync(dest, content, "utf8");
|
|
447
|
+
console.log(chalk2.green(" \u2713 Factory Droid: created .factory/droids/agentvalet.yaml"));
|
|
448
|
+
console.log(chalk2.dim(" Commit this file to your repo"));
|
|
449
|
+
}
|
|
450
|
+
function writeFactoryDroidCommand() {
|
|
451
|
+
const commandsDir = path.join(process.cwd(), ".factory", "commands");
|
|
452
|
+
if (!existsSync(commandsDir)) mkdirSync(commandsDir, { recursive: true });
|
|
453
|
+
const statusDest = path.join(commandsDir, "av-status.md");
|
|
454
|
+
if (!existsSync(statusDest)) {
|
|
455
|
+
const statusContent = `# /av-status
|
|
456
|
+
|
|
457
|
+
Check your AgentValet agent status and approved platform connections.
|
|
458
|
+
|
|
459
|
+
## Instructions for the droid
|
|
460
|
+
|
|
461
|
+
1. Call \`list_platforms\` using the AgentValet MCP server
|
|
462
|
+
2. Display the results in a clean table:
|
|
463
|
+
- Platform name
|
|
464
|
+
- Approved scopes
|
|
465
|
+
- Whether any scope requires human approval
|
|
466
|
+
3. If no platforms are approved yet, tell the user to visit
|
|
467
|
+
https://app.agentvalet.ai/agents to configure permissions
|
|
468
|
+
4. If AgentValet MCP is not connected, explain how to set it up:
|
|
469
|
+
Run: npx @agentvalet/register
|
|
470
|
+
`;
|
|
471
|
+
writeFileSync(statusDest, statusContent, "utf8");
|
|
472
|
+
console.log(chalk2.green(" \u2713 Factory Droid: created .factory/commands/av-status.md"));
|
|
473
|
+
} else {
|
|
474
|
+
console.log(chalk2.dim(" Factory Droid: .factory/commands/av-status.md already exists"));
|
|
475
|
+
}
|
|
476
|
+
const registerDest = path.join(commandsDir, "av-register.md");
|
|
477
|
+
if (!existsSync(registerDest)) {
|
|
478
|
+
const registerContent = `# /av-register
|
|
479
|
+
|
|
480
|
+
Register or re-register this project with AgentValet.
|
|
481
|
+
|
|
482
|
+
## Instructions for the droid
|
|
483
|
+
|
|
484
|
+
Tell the user to run the following command in their terminal:
|
|
485
|
+
|
|
486
|
+
\`\`\`bash
|
|
487
|
+
npx @agentvalet/register
|
|
488
|
+
\`\`\`
|
|
489
|
+
|
|
490
|
+
This will:
|
|
491
|
+
1. Authenticate with GitHub (opens browser)
|
|
492
|
+
2. Create or find their AgentValet account
|
|
493
|
+
3. Register this machine as an agent
|
|
494
|
+
4. Configure Factory Droid MCP integration automatically
|
|
495
|
+
|
|
496
|
+
After running, approve the agent at: https://app.agentvalet.ai/agents
|
|
497
|
+
`;
|
|
498
|
+
writeFileSync(registerDest, registerContent, "utf8");
|
|
499
|
+
console.log(chalk2.green(" \u2713 Factory Droid: created .factory/commands/av-register.md"));
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function writeFactoryDroidReliabilityDroid() {
|
|
503
|
+
const droidsDir = path.join(process.cwd(), ".factory", "droids");
|
|
504
|
+
if (!existsSync(droidsDir)) mkdirSync(droidsDir, { recursive: true });
|
|
505
|
+
const dest = path.join(droidsDir, "agentvalet-reliability.yaml");
|
|
506
|
+
if (existsSync(dest)) return;
|
|
507
|
+
const content = `# AgentValet Reliability Droid
|
|
508
|
+
# Monitors agent call patterns and surfaces governance issues
|
|
509
|
+
# Commit this file to your repo
|
|
510
|
+
|
|
511
|
+
name: AgentValet Reliability
|
|
512
|
+
description: >
|
|
513
|
+
Monitors AI agent behaviour against AgentValet governance rules.
|
|
514
|
+
Surfaces approval-required actions, scope violations, rate limit
|
|
515
|
+
warnings, and audit anomalies directly in Factory Droid.
|
|
516
|
+
|
|
517
|
+
type: reliability
|
|
518
|
+
model: inherit
|
|
519
|
+
mcp_servers:
|
|
520
|
+
- agentvalet
|
|
521
|
+
autonomy: Low
|
|
522
|
+
|
|
523
|
+
triggers:
|
|
524
|
+
- on_agent_action: true
|
|
525
|
+
- on_approval_required: true
|
|
526
|
+
- on_scope_violation: true
|
|
527
|
+
|
|
528
|
+
instructions: |
|
|
529
|
+
You are a governance monitor. You observe what the other droids
|
|
530
|
+
are doing and flag any actions that require human oversight.
|
|
531
|
+
|
|
532
|
+
## Your responsibilities
|
|
533
|
+
|
|
534
|
+
1. BEFORE any droid makes a platform API call, check if the scope
|
|
535
|
+
requires approval using \`authzen_evaluate\`:
|
|
536
|
+
- If decision=false: block the call, explain why, suggest alternatives
|
|
537
|
+
- If decision=true: allow, but log it
|
|
538
|
+
|
|
539
|
+
2. WHEN a droid calls \`use_platform\`, verify:
|
|
540
|
+
- The platform is in the approved list from \`list_platforms\`
|
|
541
|
+
- The scope matches what was approved
|
|
542
|
+
- The call hasn't exceeded rate limits
|
|
543
|
+
|
|
544
|
+
3. SURFACE approval-required actions clearly:
|
|
545
|
+
"\u26A0 This action requires human approval: [action description]
|
|
546
|
+
Waiting for approval at app.agentvalet.ai/approvals"
|
|
547
|
+
|
|
548
|
+
4. MONITOR for unusual patterns:
|
|
549
|
+
- Multiple calls to the same destructive scope in quick succession
|
|
550
|
+
- Calls to platforms not in the approved list
|
|
551
|
+
- Call volume spikes beyond normal operation
|
|
552
|
+
|
|
553
|
+
5. REPORT governance status when asked:
|
|
554
|
+
- Current approved platforms and scopes
|
|
555
|
+
- Pending approvals
|
|
556
|
+
- Recent audit log entries (call list_platforms + agent_status)
|
|
557
|
+
|
|
558
|
+
## What you do NOT do
|
|
559
|
+
|
|
560
|
+
- You do not make platform API calls yourself
|
|
561
|
+
- You do not approve actions on behalf of the human
|
|
562
|
+
- You do not bypass governance even if another droid requests it
|
|
563
|
+
|
|
564
|
+
## Escalation
|
|
565
|
+
|
|
566
|
+
If you detect a potential security concern (unexpected scope,
|
|
567
|
+
unusual call pattern), immediately tell the human:
|
|
568
|
+
"\u{1F534} Governance alert: [description]. Recommend reviewing at
|
|
569
|
+
app.agentvalet.ai/audit"
|
|
570
|
+
`;
|
|
571
|
+
writeFileSync(dest, content, "utf8");
|
|
572
|
+
console.log(chalk2.green(" \u2713 Factory Droid: created .factory/droids/agentvalet-reliability.yaml"));
|
|
573
|
+
console.log(chalk2.dim(" Commit this file to your repo"));
|
|
574
|
+
}
|
|
373
575
|
function ensureMcpServer() {
|
|
374
576
|
try {
|
|
375
577
|
execSync("npx --yes @agentvalet/mcp-server --version", {
|
|
@@ -518,7 +720,7 @@ var HOOK_MARKER = "agentvalet/register refresh";
|
|
|
518
720
|
function writePermissionsFromEvent(agentId, ownerId, platforms, outputPath = "./.claude/agentvalet-permissions.md") {
|
|
519
721
|
const content = generatePermissionsFile(agentId, ownerId, platforms);
|
|
520
722
|
const resolvedPath = resolve3(outputPath);
|
|
521
|
-
|
|
723
|
+
mkdirSync2(dirname2(resolvedPath), { recursive: true });
|
|
522
724
|
writeFileSync2(resolvedPath, content, "utf-8");
|
|
523
725
|
embedInClaudeMd(content);
|
|
524
726
|
ensureHook();
|
|
@@ -565,7 +767,7 @@ async function runRefresh(options) {
|
|
|
565
767
|
const json = await res.json();
|
|
566
768
|
const platforms = json.data?.platforms ?? [];
|
|
567
769
|
const content = generatePermissionsFile(agentId, ownerId, platforms);
|
|
568
|
-
|
|
770
|
+
mkdirSync2(dirname2(outputPath), { recursive: true });
|
|
569
771
|
writeFileSync2(outputPath, content, "utf-8");
|
|
570
772
|
embedInClaudeMd(content);
|
|
571
773
|
ensureHook();
|
|
@@ -627,7 +829,7 @@ function ensureHook() {
|
|
|
627
829
|
perms.allow = [...allow, ...missing];
|
|
628
830
|
settings.permissions = perms;
|
|
629
831
|
}
|
|
630
|
-
|
|
832
|
+
mkdirSync2(dirname2(settingsPath), { recursive: true });
|
|
631
833
|
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
632
834
|
ensureMcpJson();
|
|
633
835
|
}
|
|
@@ -849,7 +1051,7 @@ function formatEnvBlock(vars) {
|
|
|
849
1051
|
}
|
|
850
1052
|
|
|
851
1053
|
// src/config/ide.ts
|
|
852
|
-
import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile2, appendFile as appendFile3 } from "fs/promises";
|
|
1054
|
+
import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile2, appendFile as appendFile3, copyFile } from "fs/promises";
|
|
853
1055
|
import { existsSync as existsSync5 } from "fs";
|
|
854
1056
|
import path4 from "path";
|
|
855
1057
|
import os from "os";
|
|
@@ -980,6 +1182,72 @@ async function writeIdeConfigs(params) {
|
|
|
980
1182
|
console.warn(` Warning: could not write .cursor/mcp.json: ${err.message}`);
|
|
981
1183
|
}
|
|
982
1184
|
}
|
|
1185
|
+
if (detected.factoryDroid) {
|
|
1186
|
+
const fdResults = await writeFactoryDroidConfig(mcpParams);
|
|
1187
|
+
written.push(...fdResults);
|
|
1188
|
+
}
|
|
1189
|
+
return written;
|
|
1190
|
+
}
|
|
1191
|
+
async function mergeFactoryDroidMcpJson(filePath, key, value) {
|
|
1192
|
+
let existing = {};
|
|
1193
|
+
if (existsSync5(filePath)) {
|
|
1194
|
+
try {
|
|
1195
|
+
const text = await readFile2(filePath, "utf8");
|
|
1196
|
+
existing = JSON.parse(text);
|
|
1197
|
+
} catch {
|
|
1198
|
+
await copyFile(filePath, filePath + ".backup");
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
if (existing[key]) return;
|
|
1202
|
+
existing[key] = value;
|
|
1203
|
+
await writeFile4(filePath, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
1204
|
+
}
|
|
1205
|
+
async function updateGitignoreForFactoryDroid() {
|
|
1206
|
+
const gitignorePath = path4.join(process.cwd(), ".gitignore");
|
|
1207
|
+
if (!existsSync5(gitignorePath)) return;
|
|
1208
|
+
const existing = await readFile2(gitignorePath, "utf8");
|
|
1209
|
+
if (existing.includes(".factory/mcp.json")) return;
|
|
1210
|
+
const additions = [
|
|
1211
|
+
"",
|
|
1212
|
+
"# Factory Droid \u2014 private key in MCP config",
|
|
1213
|
+
".factory/mcp.json",
|
|
1214
|
+
"",
|
|
1215
|
+
"# Factory Droid \u2014 commit these:",
|
|
1216
|
+
"# .factory/droids/",
|
|
1217
|
+
"# .factory/commands/"
|
|
1218
|
+
].join("\n");
|
|
1219
|
+
await appendFile3(gitignorePath, additions + "\n", "utf8");
|
|
1220
|
+
}
|
|
1221
|
+
async function writeFactoryDroidConfig(params) {
|
|
1222
|
+
const home = os.homedir();
|
|
1223
|
+
const written = [];
|
|
1224
|
+
const entry = buildMcpEntry(params);
|
|
1225
|
+
const globalDir = path4.join(home, ".factory");
|
|
1226
|
+
const projectDir = path4.join(process.cwd(), ".factory");
|
|
1227
|
+
const globalDirExists = existsSync5(globalDir);
|
|
1228
|
+
const projectDirExists = existsSync5(projectDir);
|
|
1229
|
+
if (globalDirExists) {
|
|
1230
|
+
try {
|
|
1231
|
+
await mergeFactoryDroidMcpJson(path4.join(globalDir, "mcp.json"), "agentvalet", entry);
|
|
1232
|
+
written.push("~/.factory/mcp.json");
|
|
1233
|
+
} catch (err) {
|
|
1234
|
+
console.warn(` Warning: could not write ~/.factory/mcp.json: ${err.message}`);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
if (projectDirExists && !globalDirExists) {
|
|
1238
|
+
try {
|
|
1239
|
+
await mergeFactoryDroidMcpJson(path4.join(projectDir, "mcp.json"), "agentvalet", entry);
|
|
1240
|
+
written.push(".factory/mcp.json");
|
|
1241
|
+
} catch (err) {
|
|
1242
|
+
console.warn(` Warning: could not write .factory/mcp.json: ${err.message}`);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
if (written.length > 0) {
|
|
1246
|
+
try {
|
|
1247
|
+
await updateGitignoreForFactoryDroid();
|
|
1248
|
+
} catch {
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
983
1251
|
return written;
|
|
984
1252
|
}
|
|
985
1253
|
|
|
@@ -1017,7 +1285,8 @@ function detectFrameworks() {
|
|
|
1017
1285
|
codex: existsSync6(path5.join(home, ".codex")) || tryBinary("codex"),
|
|
1018
1286
|
claudeCode: existsSync6(path5.join(home, ".claude")) || tryBinary("claude"),
|
|
1019
1287
|
cursor: existsSync6(path5.join(process.cwd(), ".cursor")) || cursorInstalled(),
|
|
1020
|
-
openclaw: existsSync6(path5.join(home, ".openclaw"))
|
|
1288
|
+
openclaw: existsSync6(path5.join(home, ".openclaw")),
|
|
1289
|
+
factoryDroid: existsSync6(path5.join(home, ".factory")) || existsSync6(path5.join(process.cwd(), ".factory"))
|
|
1021
1290
|
};
|
|
1022
1291
|
}
|
|
1023
1292
|
async function frameworkSetupConsent(detected) {
|
|
@@ -1036,6 +1305,11 @@ async function frameworkSetupConsent(detected) {
|
|
|
1036
1305
|
if (detected.openclaw) {
|
|
1037
1306
|
items.push("OpenClaw \u2192 SKILL.md (usage rules)");
|
|
1038
1307
|
}
|
|
1308
|
+
if (detected.factoryDroid) {
|
|
1309
|
+
items.push("Factory Droid \u2192 add MCP server to ~/.factory/mcp.json");
|
|
1310
|
+
items.push(" \u2192 create .factory/droids/agentvalet.yaml");
|
|
1311
|
+
items.push(" \u2192 create .factory/commands/av-status.md");
|
|
1312
|
+
}
|
|
1039
1313
|
if (items.length === 0) return false;
|
|
1040
1314
|
console.log("");
|
|
1041
1315
|
console.log(chalk6.bold(" Detected agent frameworks"));
|
|
@@ -1255,6 +1529,16 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1255
1529
|
}
|
|
1256
1530
|
const detected = detectFrameworks();
|
|
1257
1531
|
const shouldSetup = await frameworkSetupConsent(detected);
|
|
1532
|
+
let installReliabilityDroid = false;
|
|
1533
|
+
if (detected.factoryDroid && shouldSetup) {
|
|
1534
|
+
const { reliability } = await prompts3({
|
|
1535
|
+
type: "confirm",
|
|
1536
|
+
name: "reliability",
|
|
1537
|
+
message: "Also install AgentValet Reliability Droid for Factory Droid? (monitors agent governance)",
|
|
1538
|
+
initial: false
|
|
1539
|
+
});
|
|
1540
|
+
installReliabilityDroid = reliability ?? false;
|
|
1541
|
+
}
|
|
1258
1542
|
if (shouldSetup) {
|
|
1259
1543
|
console.log("");
|
|
1260
1544
|
console.log(chalk7.bold(" Configuring agent frameworks..."));
|
|
@@ -1284,6 +1568,13 @@ async function registerAgentFlow(apiKey, ownerId) {
|
|
|
1284
1568
|
if (detected.openclaw) {
|
|
1285
1569
|
writeSkillMd();
|
|
1286
1570
|
}
|
|
1571
|
+
if (detected.factoryDroid) {
|
|
1572
|
+
writeFactoryDroidDroid();
|
|
1573
|
+
writeFactoryDroidCommand();
|
|
1574
|
+
if (installReliabilityDroid) {
|
|
1575
|
+
writeFactoryDroidReliabilityDroid();
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1287
1578
|
writeQuickstartDoc({
|
|
1288
1579
|
agentId: agent.agent_id,
|
|
1289
1580
|
ownerId,
|