@agentvalet/register 1.1.1 → 1.4.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/README.md +21 -1
- package/dist/index.js +292 -183
- package/package.json +15 -13
package/README.md
CHANGED
|
@@ -15,9 +15,29 @@ No installation required. Authenticate with GitHub, and your agent is registered
|
|
|
15
15
|
1. Opens your browser to authenticate with GitHub
|
|
16
16
|
2. Creates your AgentValet account (or finds your existing one)
|
|
17
17
|
3. Registers this machine as an agent
|
|
18
|
-
4. Writes config to
|
|
18
|
+
4. Writes config and your private key to `~/.agentvalet/` in your **home**
|
|
19
|
+
directory (not the current directory)
|
|
19
20
|
5. Outputs the environment variables you need
|
|
20
21
|
|
|
22
|
+
## Already have an agent on this machine?
|
|
23
|
+
|
|
24
|
+
An agent's private key exists only on your machine — the proxy never sees it,
|
|
25
|
+
and there is no rotation endpoint. Overwriting it destroys that identity, along
|
|
26
|
+
with its grants and audit continuity.
|
|
27
|
+
|
|
28
|
+
So registering while `~/.agentvalet/agent.key` already belongs to a **different**
|
|
29
|
+
agent stops with an error rather than overwriting it. You have two options:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Keep both — store the new agent under ~/.agentvalet/<label>/
|
|
33
|
+
npx @agentvalet/register claim <bind_secret> --label work-laptop
|
|
34
|
+
|
|
35
|
+
# Replace the existing one — a timestamped backup is written first
|
|
36
|
+
npx @agentvalet/register --force
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Re-registering the *same* agent over its own key is always allowed.
|
|
40
|
+
|
|
21
41
|
## Requirements
|
|
22
42
|
|
|
23
43
|
- Node.js 18+
|
package/dist/index.js
CHANGED
|
@@ -180,8 +180,72 @@ function sleep(ms) {
|
|
|
180
180
|
|
|
181
181
|
// src/save.ts
|
|
182
182
|
import { writeFile, mkdir } from "fs/promises";
|
|
183
|
+
|
|
184
|
+
// src/config/key-guard.ts
|
|
185
|
+
import { existsSync, copyFileSync, readFileSync } from "fs";
|
|
186
|
+
import { dirname, join } from "path";
|
|
187
|
+
var KeyClobberError = class extends Error {
|
|
188
|
+
constructor(keyPath, existingAgentId, message) {
|
|
189
|
+
super(message);
|
|
190
|
+
this.keyPath = keyPath;
|
|
191
|
+
this.existingAgentId = existingAgentId;
|
|
192
|
+
this.name = "KeyClobberError";
|
|
193
|
+
}
|
|
194
|
+
keyPath;
|
|
195
|
+
existingAgentId;
|
|
196
|
+
};
|
|
197
|
+
function existingKeyOwner(keyPath) {
|
|
198
|
+
if (!existsSync(keyPath)) return null;
|
|
199
|
+
const configPath = join(dirname(keyPath), "config.json");
|
|
200
|
+
if (!existsSync(configPath)) return null;
|
|
201
|
+
try {
|
|
202
|
+
const parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
203
|
+
const id = parsed.agentId ?? parsed.lastAgentId;
|
|
204
|
+
return typeof id === "string" && id ? id : null;
|
|
205
|
+
} catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function backupExistingKey(keyPath) {
|
|
210
|
+
if (!existsSync(keyPath)) return null;
|
|
211
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
212
|
+
let backup = `${keyPath}.bak.${stamp}`;
|
|
213
|
+
let n = 1;
|
|
214
|
+
while (existsSync(backup)) backup = `${keyPath}.bak.${stamp}-${n++}`;
|
|
215
|
+
copyFileSync(keyPath, backup);
|
|
216
|
+
return backup;
|
|
217
|
+
}
|
|
218
|
+
function assertSafeToWriteKey(keyPath, incomingAgentId, opts = {}) {
|
|
219
|
+
if (!existsSync(keyPath)) return;
|
|
220
|
+
const owner = existingKeyOwner(keyPath);
|
|
221
|
+
if (owner && owner === incomingAgentId) return;
|
|
222
|
+
if (opts.force) {
|
|
223
|
+
backupExistingKey(keyPath);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const whose = owner ? `agent ${owner}` : "another agent (owner unknown)";
|
|
227
|
+
throw new KeyClobberError(
|
|
228
|
+
keyPath,
|
|
229
|
+
owner,
|
|
230
|
+
[
|
|
231
|
+
`${keyPath} already holds the private key for ${whose}.`,
|
|
232
|
+
"",
|
|
233
|
+
"Overwriting it would destroy that identity permanently: the key exists",
|
|
234
|
+
"only on this machine and there is no way to recover or rotate it.",
|
|
235
|
+
"",
|
|
236
|
+
"Options:",
|
|
237
|
+
` \u2022 Keep both \u2014 move ${keyPath} aside first, or use 'claim --label <name>'`,
|
|
238
|
+
" to store an additional agent under ~/.agentvalet/<name>/.",
|
|
239
|
+
" \u2022 Replace it \u2014 re-run with --force. The existing key is copied to",
|
|
240
|
+
` ${keyPath}.bak.<timestamp> before being replaced.`
|
|
241
|
+
].join("\n")
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/save.ts
|
|
183
246
|
async function saveOutput(opts) {
|
|
184
247
|
await mkdir(AGENT_DIR, { recursive: true });
|
|
248
|
+
assertSafeToWriteKey(AGENT_KEY_PATH, opts.agentId, { force: opts.force });
|
|
185
249
|
await writeFile(AGENT_KEY_PATH, opts.privateKey, { mode: 384 });
|
|
186
250
|
saveConfig({
|
|
187
251
|
agentId: opts.agentId,
|
|
@@ -196,8 +260,8 @@ async function saveOutput(opts) {
|
|
|
196
260
|
}
|
|
197
261
|
|
|
198
262
|
// src/commands/refresh.ts
|
|
199
|
-
import { readFileSync as
|
|
200
|
-
import { dirname, resolve as resolve2 } from "path";
|
|
263
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync2, statSync } from "fs";
|
|
264
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
201
265
|
|
|
202
266
|
// src/lib/jwt.ts
|
|
203
267
|
import { createSign, createPrivateKey } from "crypto";
|
|
@@ -215,13 +279,13 @@ function signJwt(agentId, ownerId, privateKeyPem) {
|
|
|
215
279
|
}
|
|
216
280
|
|
|
217
281
|
// src/lib/skill-writer.ts
|
|
218
|
-
import { existsSync, writeFileSync, mkdirSync } from "fs";
|
|
282
|
+
import { existsSync as existsSync2, writeFileSync, mkdirSync } from "fs";
|
|
219
283
|
import { execSync } from "child_process";
|
|
220
284
|
import path from "path";
|
|
221
285
|
import chalk2 from "chalk";
|
|
222
286
|
function writeAgentsMd() {
|
|
223
287
|
const dest = path.join(process.cwd(), "AGENTS.md");
|
|
224
|
-
if (
|
|
288
|
+
if (existsSync2(dest)) {
|
|
225
289
|
console.log(chalk2.dim(" AGENTS.md already exists \u2014 skipping"));
|
|
226
290
|
return;
|
|
227
291
|
}
|
|
@@ -232,15 +296,18 @@ Never call platform APIs (Slack, Stripe, Gmail, GitHub, etc.) directly.
|
|
|
232
296
|
|
|
233
297
|
## Making a platform call
|
|
234
298
|
|
|
235
|
-
|
|
299
|
+
Pick the tool that matches what you are doing:
|
|
300
|
+
|
|
301
|
+
- \`read_platform\` to read (always GET)
|
|
302
|
+
- \`write_platform\` to create or update (POST, PUT or PATCH)
|
|
303
|
+
- \`delete_platform\` to remove (always DELETE)
|
|
236
304
|
|
|
237
305
|
\`\`\`
|
|
238
|
-
|
|
306
|
+
write_platform({
|
|
239
307
|
platform: "slack",
|
|
240
308
|
endpoint: "/api/chat.postMessage",
|
|
241
|
-
method: "POST",
|
|
242
309
|
scope: "slack:write",
|
|
243
|
-
|
|
310
|
+
body: { channel: "#general", text: "Hello" }
|
|
244
311
|
})
|
|
245
312
|
\`\`\`
|
|
246
313
|
|
|
@@ -261,7 +328,7 @@ Do not call platform APIs directly. Tell the user:
|
|
|
261
328
|
}
|
|
262
329
|
function writeSkillMd() {
|
|
263
330
|
const dest = path.join(process.cwd(), "SKILL.md");
|
|
264
|
-
if (
|
|
331
|
+
if (existsSync2(dest)) {
|
|
265
332
|
console.log(chalk2.dim(" SKILL.md already exists \u2014 skipping"));
|
|
266
333
|
return;
|
|
267
334
|
}
|
|
@@ -271,15 +338,16 @@ Routes all platform API calls through AgentValet's credential proxy.
|
|
|
271
338
|
|
|
272
339
|
## Making platform calls
|
|
273
340
|
|
|
274
|
-
Use
|
|
341
|
+
Use \`read_platform\`, \`write_platform\` or \`delete_platform\` instead of
|
|
342
|
+
calling APIs directly. Reads use read_platform; creates and updates use
|
|
343
|
+
write_platform; deletions use delete_platform.
|
|
275
344
|
|
|
276
345
|
\`\`\`
|
|
277
|
-
|
|
346
|
+
write_platform({
|
|
278
347
|
platform: "slack",
|
|
279
348
|
endpoint: "/api/chat.postMessage",
|
|
280
|
-
method: "POST",
|
|
281
349
|
scope: "slack:write",
|
|
282
|
-
|
|
350
|
+
body: { channel: "#general", text: "Hello" }
|
|
283
351
|
})
|
|
284
352
|
\`\`\`
|
|
285
353
|
|
|
@@ -298,7 +366,7 @@ Dashboard: https://app.agentvalet.ai
|
|
|
298
366
|
}
|
|
299
367
|
function writeQuickstartDoc(opts) {
|
|
300
368
|
const dest = path.join(process.cwd(), "AGENTVALET.md");
|
|
301
|
-
if (
|
|
369
|
+
if (existsSync2(dest)) {
|
|
302
370
|
console.log(chalk2.dim(" AGENTVALET.md already exists \u2014 skipping"));
|
|
303
371
|
return;
|
|
304
372
|
}
|
|
@@ -381,9 +449,9 @@ AGENT_PRIVATE_KEY_PATH=${keyPath}
|
|
|
381
449
|
}
|
|
382
450
|
function writeFactoryDroidDroid() {
|
|
383
451
|
const droidsDir = path.join(process.cwd(), ".factory", "droids");
|
|
384
|
-
if (!
|
|
452
|
+
if (!existsSync2(droidsDir)) mkdirSync(droidsDir, { recursive: true });
|
|
385
453
|
const dest = path.join(droidsDir, "agentvalet.yaml");
|
|
386
|
-
if (
|
|
454
|
+
if (existsSync2(dest)) {
|
|
387
455
|
console.log(chalk2.dim(" Factory Droid: .factory/droids/agentvalet.yaml already exists"));
|
|
388
456
|
return;
|
|
389
457
|
}
|
|
@@ -410,7 +478,8 @@ instructions: |
|
|
|
410
478
|
## Rules \u2014 read before every platform call
|
|
411
479
|
|
|
412
480
|
1. NEVER call platform APIs (Slack, Stripe, Gmail, GitHub, etc.) directly.
|
|
413
|
-
Always use
|
|
481
|
+
Always use \`read_platform\` (reads), \`write_platform\` (creates and
|
|
482
|
+
updates) or \`delete_platform\` (deletions).
|
|
414
483
|
|
|
415
484
|
2. Call \`list_platforms\` at the start of any session that involves
|
|
416
485
|
platform calls. Do not assume platforms are available.
|
|
@@ -418,7 +487,7 @@ instructions: |
|
|
|
418
487
|
3. Call \`authzen_evaluate\` before any destructive operation
|
|
419
488
|
(delete, send, charge, publish). Do not proceed if decision=false.
|
|
420
489
|
|
|
421
|
-
4. If
|
|
490
|
+
4. If a platform call returns \`{ status: "pending_approval" }\`,
|
|
422
491
|
wait for human approval. Do not retry the call.
|
|
423
492
|
|
|
424
493
|
5. If AgentValet MCP tools are unavailable, stop and tell the user:
|
|
@@ -428,12 +497,11 @@ instructions: |
|
|
|
428
497
|
## Making a platform call
|
|
429
498
|
|
|
430
499
|
\`\`\`
|
|
431
|
-
|
|
500
|
+
write_platform({
|
|
432
501
|
platform: "slack",
|
|
433
502
|
endpoint: "/api/chat.postMessage",
|
|
434
|
-
method: "POST",
|
|
435
503
|
scope: "slack:write",
|
|
436
|
-
|
|
504
|
+
body: { channel: "#general", text: "Hello" }
|
|
437
505
|
})
|
|
438
506
|
\`\`\`
|
|
439
507
|
|
|
@@ -453,9 +521,9 @@ instructions: |
|
|
|
453
521
|
}
|
|
454
522
|
function writeFactoryDroidCommand() {
|
|
455
523
|
const commandsDir = path.join(process.cwd(), ".factory", "commands");
|
|
456
|
-
if (!
|
|
524
|
+
if (!existsSync2(commandsDir)) mkdirSync(commandsDir, { recursive: true });
|
|
457
525
|
const statusDest = path.join(commandsDir, "av-status.md");
|
|
458
|
-
if (!
|
|
526
|
+
if (!existsSync2(statusDest)) {
|
|
459
527
|
const statusContent = `# /av-status
|
|
460
528
|
|
|
461
529
|
Check your AgentValet agent status and approved platform connections.
|
|
@@ -478,7 +546,7 @@ Check your AgentValet agent status and approved platform connections.
|
|
|
478
546
|
console.log(chalk2.dim(" Factory Droid: .factory/commands/av-status.md already exists"));
|
|
479
547
|
}
|
|
480
548
|
const registerDest = path.join(commandsDir, "av-register.md");
|
|
481
|
-
if (!
|
|
549
|
+
if (!existsSync2(registerDest)) {
|
|
482
550
|
const registerContent = `# /av-register
|
|
483
551
|
|
|
484
552
|
Register or re-register this project with AgentValet.
|
|
@@ -505,9 +573,9 @@ After running, approve the agent at: https://app.agentvalet.ai/agents
|
|
|
505
573
|
}
|
|
506
574
|
function writeFactoryDroidReliabilityDroid() {
|
|
507
575
|
const droidsDir = path.join(process.cwd(), ".factory", "droids");
|
|
508
|
-
if (!
|
|
576
|
+
if (!existsSync2(droidsDir)) mkdirSync(droidsDir, { recursive: true });
|
|
509
577
|
const dest = path.join(droidsDir, "agentvalet-reliability.yaml");
|
|
510
|
-
if (
|
|
578
|
+
if (existsSync2(dest)) return;
|
|
511
579
|
const content = `# AgentValet Reliability Droid
|
|
512
580
|
# Monitors agent call patterns and surfaces governance issues
|
|
513
581
|
# Commit this file to your repo
|
|
@@ -540,7 +608,8 @@ instructions: |
|
|
|
540
608
|
- If decision=false: block the call, explain why, suggest alternatives
|
|
541
609
|
- If decision=true: allow, but log it
|
|
542
610
|
|
|
543
|
-
2. WHEN a droid calls \`
|
|
611
|
+
2. WHEN a droid calls \`read_platform\`, \`write_platform\` or
|
|
612
|
+
\`delete_platform\`, verify:
|
|
544
613
|
- The platform is in the approved list from \`list_platforms\`
|
|
545
614
|
- The scope matches what was approved
|
|
546
615
|
- The call hasn't exceeded rate limits
|
|
@@ -589,7 +658,8 @@ function ensureMcpServer() {
|
|
|
589
658
|
function generatePermissionsFile(agentId, ownerId, permissions) {
|
|
590
659
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
591
660
|
const platformSections = permissions.length === 0 ? "_No platforms approved yet. Visit https://app.agentvalet.ai to connect platforms._" : permissions.map((p) => {
|
|
592
|
-
const
|
|
661
|
+
const gated = new Set(p.approvalScopes ?? []);
|
|
662
|
+
const scopeList = p.scopes.map((s) => ` - \`${s}\`${gated.has(s) ? " \u2014 requires human approval" : ""}`).join("\n");
|
|
593
663
|
const approvalNote = p.requireApproval ? "\n > Requires human approval before executing.\n" : "";
|
|
594
664
|
return `### ${p.platformName} (\`${p.platformId}\`)
|
|
595
665
|
|
|
@@ -611,19 +681,58 @@ ${platformSections}
|
|
|
611
681
|
|
|
612
682
|
---
|
|
613
683
|
|
|
684
|
+
## Before any platform call
|
|
685
|
+
|
|
686
|
+
1. **Check AgentValet first.** For any action on an external platform (Slack,
|
|
687
|
+
GitHub, Stripe, Gmail, Outlook, Notion, Linear, Jira, HubSpot, Salesforce,
|
|
688
|
+
or any other SaaS), call \`mcp__agentvalet__list_platforms\` **before** you
|
|
689
|
+
assume the platform is unavailable or reach for another route.
|
|
690
|
+
2. **If the platform is listed here, you must use it.** Do not call the
|
|
691
|
+
platform's API directly, and do not use another MCP server's tool for a
|
|
692
|
+
platform AgentValet covers \u2014 that bypasses the audit log, the approval
|
|
693
|
+
flow, and the scope limits the owner configured.
|
|
694
|
+
3. **If it is not listed**, say so: "AgentValet doesn't cover <platform> yet."
|
|
695
|
+
Ask the user whether to request the integration from their AgentValet
|
|
696
|
+
owner. Do not silently fall back to direct API calls or raw keys found in
|
|
697
|
+
the environment.
|
|
698
|
+
4. **Destructive scopes** (\`*.delete\`, \`stripe:charge\`, \`mail:send\`) need
|
|
699
|
+
human approval. Warn the user before invoking them.
|
|
700
|
+
5. **On \`pending_approval\`** \u2014 the action is queued and runs when the owner
|
|
701
|
+
approves. Tell the user and **do not retry**; a retry queues a duplicate.
|
|
702
|
+
6. **If the AgentValet MCP tools are unavailable**, stop. Tell the user
|
|
703
|
+
"AgentValet MCP is not connected. Run: npx @agentvalet/register". Do not
|
|
704
|
+
attempt the platform call without governance.
|
|
705
|
+
|
|
706
|
+
Read scopes are auto-approved. Write scopes may require approval. Destructive
|
|
707
|
+
scopes always require approval.
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
614
711
|
## How to call a platform
|
|
615
712
|
|
|
616
|
-
All platform calls **must** go through the
|
|
713
|
+
All platform calls **must** go through the AgentValet MCP tools. Pick the one
|
|
714
|
+
that matches the operation:
|
|
617
715
|
|
|
618
|
-
|
|
716
|
+
| Operation | Tool | Method |
|
|
717
|
+
|---|---|---|
|
|
718
|
+
| Read | \`mcp__agentvalet__read_platform\` | always GET |
|
|
719
|
+
| Create or update | \`mcp__agentvalet__write_platform\` | POST (default), PUT or PATCH |
|
|
720
|
+
| Delete | \`mcp__agentvalet__delete_platform\` | always DELETE |
|
|
721
|
+
|
|
722
|
+
**NEVER** write inline JWT signing code, \`node -e\` scripts, or manual HTTP calls. The MCP tools handle all authentication internally.
|
|
619
723
|
|
|
620
724
|
\`\`\`
|
|
621
|
-
|
|
725
|
+
mcp__agentvalet__read_platform({
|
|
726
|
+
platform: "<platformId>",
|
|
727
|
+
endpoint: "<endpoint>",
|
|
728
|
+
scope: "<scope>"
|
|
729
|
+
})
|
|
730
|
+
|
|
731
|
+
mcp__agentvalet__write_platform({
|
|
622
732
|
platform: "<platformId>",
|
|
623
733
|
endpoint: "<endpoint>",
|
|
624
|
-
method: "POST",
|
|
625
734
|
scope: "<scope>",
|
|
626
|
-
|
|
735
|
+
body: { ... }
|
|
627
736
|
})
|
|
628
737
|
\`\`\`
|
|
629
738
|
|
|
@@ -632,7 +741,7 @@ To refresh this file: \`npx @agentvalet/register refresh\`
|
|
|
632
741
|
}
|
|
633
742
|
|
|
634
743
|
// src/lib/require-agent.ts
|
|
635
|
-
import { existsSync as
|
|
744
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
636
745
|
import { resolve } from "path";
|
|
637
746
|
import chalk3 from "chalk";
|
|
638
747
|
var NO_AGENT_MSG = chalk3.red("\n \u2717 No agent registered.\n") + chalk3.dim(
|
|
@@ -665,9 +774,9 @@ function tryResolveAgent(envFile = ".env.agentvalet") {
|
|
|
665
774
|
if (!keyPath) keyPath = AGENT_KEY_PATH;
|
|
666
775
|
if (!agentId || !ownerId) {
|
|
667
776
|
const envPath = resolve(envFile);
|
|
668
|
-
if (
|
|
777
|
+
if (existsSync3(envPath)) {
|
|
669
778
|
try {
|
|
670
|
-
const vars = parseEnvFile(
|
|
779
|
+
const vars = parseEnvFile(readFileSync3(envPath, "utf-8"));
|
|
671
780
|
agentId = agentId ?? vars["AGENTVALET_AGENT_ID"];
|
|
672
781
|
ownerId = ownerId ?? vars["AGENTVALET_OWNER_ID"];
|
|
673
782
|
apiUrl = vars["AGENTVALET_API_URL"] ?? apiUrl;
|
|
@@ -681,12 +790,12 @@ function tryResolveAgent(envFile = ".env.agentvalet") {
|
|
|
681
790
|
if (process.env["AGENTVALET_API_URL"]) apiUrl = process.env["AGENTVALET_API_URL"];
|
|
682
791
|
if (process.env["AGENTVALET_PRIVATE_KEY_PATH"]) keyPath = process.env["AGENTVALET_PRIVATE_KEY_PATH"];
|
|
683
792
|
if (!agentId || !ownerId || !keyPath) return null;
|
|
684
|
-
if (!
|
|
793
|
+
if (!existsSync3(resolve(keyPath))) return null;
|
|
685
794
|
return { agentId, ownerId, keyPath, apiUrl };
|
|
686
795
|
}
|
|
687
796
|
|
|
688
797
|
// src/config/frameworks.ts
|
|
689
|
-
import { existsSync as
|
|
798
|
+
import { existsSync as existsSync4 } from "fs";
|
|
690
799
|
import { execSync as execSync2 } from "child_process";
|
|
691
800
|
import os from "os";
|
|
692
801
|
import path2 from "path";
|
|
@@ -704,27 +813,27 @@ function codexDesktopInstalled() {
|
|
|
704
813
|
const home = os.homedir();
|
|
705
814
|
const platform = process.platform;
|
|
706
815
|
if (platform === "darwin") {
|
|
707
|
-
return
|
|
816
|
+
return existsSync4("/Applications/Codex.app") || existsSync4(path2.join(home, "Applications", "Codex.app"));
|
|
708
817
|
}
|
|
709
818
|
if (platform === "win32") {
|
|
710
819
|
const localAppData = process.env.LOCALAPPDATA ?? path2.join(home, "AppData", "Local");
|
|
711
820
|
const programFiles = process.env["ProgramFiles"] ?? "C:\\Program Files";
|
|
712
|
-
return
|
|
821
|
+
return existsSync4(path2.join(localAppData, "Programs", "codex")) || existsSync4(path2.join(localAppData, "Programs", "Codex")) || existsSync4(path2.join(programFiles, "Codex"));
|
|
713
822
|
}
|
|
714
|
-
return
|
|
823
|
+
return existsSync4("/usr/share/applications/codex.desktop") || existsSync4(path2.join(home, ".local", "share", "applications", "codex.desktop"));
|
|
715
824
|
}
|
|
716
825
|
function claudeDesktopInstalled() {
|
|
717
826
|
const home = os.homedir();
|
|
718
827
|
const platform = process.platform;
|
|
719
828
|
if (platform === "darwin") {
|
|
720
|
-
return
|
|
829
|
+
return existsSync4("/Applications/Claude.app") || existsSync4(path2.join(home, "Library", "Application Support", "Claude"));
|
|
721
830
|
}
|
|
722
831
|
if (platform === "win32") {
|
|
723
832
|
const appData = process.env.APPDATA ?? path2.join(home, "AppData", "Roaming");
|
|
724
833
|
const localAppData = process.env.LOCALAPPDATA ?? path2.join(home, "AppData", "Local");
|
|
725
|
-
return
|
|
834
|
+
return existsSync4(path2.join(appData, "Claude")) || existsSync4(path2.join(localAppData, "AnthropicClaude")) || existsSync4(path2.join(localAppData, "Programs", "claude"));
|
|
726
835
|
}
|
|
727
|
-
return
|
|
836
|
+
return existsSync4(path2.join(home, ".config", "Claude"));
|
|
728
837
|
}
|
|
729
838
|
function cursorInstalled() {
|
|
730
839
|
const home = os.homedir();
|
|
@@ -732,24 +841,24 @@ function cursorInstalled() {
|
|
|
732
841
|
if (platform === "win32") {
|
|
733
842
|
const appData = process.env.APPDATA ?? path2.join(home, "AppData", "Roaming");
|
|
734
843
|
const localAppData = process.env.LOCALAPPDATA ?? path2.join(home, "AppData", "Local");
|
|
735
|
-
return
|
|
844
|
+
return existsSync4(path2.join(appData, "Cursor")) || existsSync4(path2.join(localAppData, "Programs", "cursor"));
|
|
736
845
|
}
|
|
737
846
|
if (platform === "darwin") {
|
|
738
|
-
return
|
|
847
|
+
return existsSync4(path2.join(home, "Library", "Application Support", "Cursor")) || existsSync4("/Applications/Cursor.app");
|
|
739
848
|
}
|
|
740
|
-
return
|
|
849
|
+
return existsSync4(path2.join(home, ".config", "Cursor")) || existsSync4("/usr/share/applications/cursor.desktop");
|
|
741
850
|
}
|
|
742
851
|
function detectFrameworks() {
|
|
743
852
|
const home = os.homedir();
|
|
744
853
|
return {
|
|
745
|
-
codex:
|
|
854
|
+
codex: existsSync4(path2.join(home, ".codex")) || tryBinary("codex"),
|
|
746
855
|
codexDesktop: codexDesktopInstalled(),
|
|
747
|
-
claudeCode:
|
|
856
|
+
claudeCode: existsSync4(path2.join(home, ".claude")) || tryBinary("claude"),
|
|
748
857
|
claudeDesktop: claudeDesktopInstalled(),
|
|
749
|
-
cursor:
|
|
858
|
+
cursor: existsSync4(path2.join(process.cwd(), ".cursor")) || cursorInstalled(),
|
|
750
859
|
cursorCli: tryBinary("cursor-agent"),
|
|
751
|
-
openclaw:
|
|
752
|
-
factoryDroid:
|
|
860
|
+
openclaw: existsSync4(path2.join(home, ".openclaw")),
|
|
861
|
+
factoryDroid: existsSync4(path2.join(home, ".factory")) || existsSync4(path2.join(process.cwd(), ".factory"))
|
|
753
862
|
};
|
|
754
863
|
}
|
|
755
864
|
function resolveAgentType(detected) {
|
|
@@ -816,22 +925,55 @@ var CLAUDE_START = "<!-- agentvalet:start -->";
|
|
|
816
925
|
var CLAUDE_END = "<!-- agentvalet:end -->";
|
|
817
926
|
var HOOK_COMMAND = "npx @agentvalet/register refresh --if-stale --quiet 2>/dev/null || true";
|
|
818
927
|
var HOOK_MARKER = "agentvalet/register refresh";
|
|
928
|
+
function projectRootFor(outputPath) {
|
|
929
|
+
return dirname2(dirname2(resolve2(outputPath)));
|
|
930
|
+
}
|
|
819
931
|
function writePermissionsFromEvent(agentId, ownerId, platforms, outputPath = "./.claude/agentvalet-permissions.md") {
|
|
820
932
|
const content = generatePermissionsFile(agentId, ownerId, platforms);
|
|
821
933
|
const resolvedPath = resolve2(outputPath);
|
|
822
|
-
|
|
934
|
+
const projectRoot = projectRootFor(resolvedPath);
|
|
935
|
+
mkdirSync2(dirname2(resolvedPath), { recursive: true });
|
|
823
936
|
writeFileSync2(resolvedPath, content, "utf-8");
|
|
824
|
-
embedInClaudeMd(content);
|
|
825
|
-
ensureHook();
|
|
937
|
+
embedInClaudeMd(content, projectRoot);
|
|
938
|
+
ensureHook(projectRoot);
|
|
939
|
+
}
|
|
940
|
+
async function writeGovernanceInstructions(agentId, ownerId) {
|
|
941
|
+
const writeRulesOnly = () => {
|
|
942
|
+
try {
|
|
943
|
+
writePermissionsFromEvent(agentId, ownerId, []);
|
|
944
|
+
console.log(" \u2713 CLAUDE.md \u2014 AgentValet governance rules");
|
|
945
|
+
return true;
|
|
946
|
+
} catch {
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
if (!tryResolveAgent()) {
|
|
951
|
+
writeRulesOnly();
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
try {
|
|
955
|
+
await runRefresh({
|
|
956
|
+
envFile: ".env.agentvalet",
|
|
957
|
+
outputPath: ".claude/agentvalet-permissions.md",
|
|
958
|
+
ifStale: false,
|
|
959
|
+
quiet: true
|
|
960
|
+
});
|
|
961
|
+
console.log(" \u2713 CLAUDE.md \u2014 AgentValet governance rules and approved platforms");
|
|
962
|
+
} catch {
|
|
963
|
+
if (writeRulesOnly()) {
|
|
964
|
+
console.log(" Run `npx @agentvalet/register refresh` once approved to fill in platforms");
|
|
965
|
+
}
|
|
966
|
+
}
|
|
826
967
|
}
|
|
827
968
|
async function runRefresh(options) {
|
|
828
969
|
const outputPath = resolve2(options.outputPath);
|
|
970
|
+
const projectRoot = projectRootFor(outputPath);
|
|
829
971
|
if (options.ifStale) {
|
|
830
972
|
try {
|
|
831
973
|
const stat = statSync(outputPath);
|
|
832
974
|
const fileIsFresh = Date.now() - stat.mtimeMs < 36e5;
|
|
833
|
-
const claudeMdPath =
|
|
834
|
-
const claudeMd =
|
|
975
|
+
const claudeMdPath = join2(projectRoot, "CLAUDE.md");
|
|
976
|
+
const claudeMd = existsSync5(claudeMdPath) ? readFileSync4(claudeMdPath, "utf-8") : "";
|
|
835
977
|
const blockStart = claudeMd.indexOf(CLAUDE_START);
|
|
836
978
|
const blockEnd = claudeMd.indexOf(CLAUDE_END);
|
|
837
979
|
const blockContent = blockStart !== -1 && blockEnd !== -1 ? claudeMd.slice(blockStart, blockEnd) : "";
|
|
@@ -841,14 +983,14 @@ async function runRefresh(options) {
|
|
|
841
983
|
}
|
|
842
984
|
}
|
|
843
985
|
const creds = tryResolveAgent(options.envFile);
|
|
844
|
-
if (!creds || !
|
|
986
|
+
if (!creds || !existsSync5(resolve2(creds.keyPath))) {
|
|
845
987
|
console.error(" \u2717 No agent registered.\n Run the following command first to register an agent in this directory:\n\n npx @agentvalet/register\n");
|
|
846
988
|
process.exit(1);
|
|
847
989
|
}
|
|
848
990
|
const { agentId, ownerId, keyPath, apiUrl } = creds;
|
|
849
991
|
let privateKeyPem;
|
|
850
992
|
try {
|
|
851
|
-
privateKeyPem =
|
|
993
|
+
privateKeyPem = readFileSync4(keyPath, "utf-8");
|
|
852
994
|
} catch {
|
|
853
995
|
throw new Error(`Cannot read private key: ${keyPath}`);
|
|
854
996
|
}
|
|
@@ -866,17 +1008,17 @@ async function runRefresh(options) {
|
|
|
866
1008
|
const json = await res.json();
|
|
867
1009
|
const platforms = json.data?.platforms ?? [];
|
|
868
1010
|
const content = generatePermissionsFile(agentId, ownerId, platforms);
|
|
869
|
-
mkdirSync2(
|
|
1011
|
+
mkdirSync2(dirname2(outputPath), { recursive: true });
|
|
870
1012
|
writeFileSync2(outputPath, content, "utf-8");
|
|
871
|
-
embedInClaudeMd(content);
|
|
872
|
-
ensureHook();
|
|
1013
|
+
embedInClaudeMd(content, projectRoot);
|
|
1014
|
+
ensureHook(projectRoot);
|
|
873
1015
|
const detected = detectFrameworks();
|
|
874
1016
|
const refreshed = [];
|
|
875
1017
|
if (detected.codex || detected.codexDesktop) {
|
|
876
|
-
if (embedPermissionsBlock(
|
|
1018
|
+
if (embedPermissionsBlock(join2(projectRoot, "AGENTS.md"), content)) refreshed.push("AGENTS.md");
|
|
877
1019
|
}
|
|
878
1020
|
if (detected.openclaw) {
|
|
879
|
-
if (embedPermissionsBlock(
|
|
1021
|
+
if (embedPermissionsBlock(join2(projectRoot, "SKILL.md"), content)) refreshed.push("SKILL.md");
|
|
880
1022
|
}
|
|
881
1023
|
if (!options.quiet) {
|
|
882
1024
|
const extras = refreshed.length > 0 ? ` (also: ${refreshed.join(", ")})` : "";
|
|
@@ -884,9 +1026,9 @@ async function runRefresh(options) {
|
|
|
884
1026
|
}
|
|
885
1027
|
}
|
|
886
1028
|
function embedPermissionsBlock(filePath, permissionsContent) {
|
|
887
|
-
if (!
|
|
1029
|
+
if (!existsSync5(filePath)) return false;
|
|
888
1030
|
try {
|
|
889
|
-
const existing =
|
|
1031
|
+
const existing = readFileSync4(filePath, "utf-8");
|
|
890
1032
|
const block = `${PERMISSIONS_START}
|
|
891
1033
|
${permissionsContent.trimEnd()}
|
|
892
1034
|
${PERMISSIONS_END}`;
|
|
@@ -908,19 +1050,19 @@ ${block}
|
|
|
908
1050
|
return false;
|
|
909
1051
|
}
|
|
910
1052
|
}
|
|
911
|
-
function embedInClaudeMd(permissionsContent) {
|
|
912
|
-
const claudeMdPath =
|
|
1053
|
+
function embedInClaudeMd(permissionsContent, projectRoot) {
|
|
1054
|
+
const claudeMdPath = join2(projectRoot, "CLAUDE.md");
|
|
913
1055
|
const block = `${CLAUDE_START}
|
|
914
1056
|
${permissionsContent.trimEnd()}
|
|
915
1057
|
${CLAUDE_END}`;
|
|
916
|
-
if (!
|
|
1058
|
+
if (!existsSync5(claudeMdPath)) {
|
|
917
1059
|
writeFileSync2(claudeMdPath, `# Agent Instructions
|
|
918
1060
|
|
|
919
1061
|
${block}
|
|
920
1062
|
`, "utf-8");
|
|
921
1063
|
return;
|
|
922
1064
|
}
|
|
923
|
-
const existing =
|
|
1065
|
+
const existing = readFileSync4(claudeMdPath, "utf-8");
|
|
924
1066
|
if (existing.includes(CLAUDE_START)) {
|
|
925
1067
|
const replaced = existing.replace(
|
|
926
1068
|
new RegExp(`${CLAUDE_START}[\\s\\S]*?${CLAUDE_END}`, "m"),
|
|
@@ -935,12 +1077,12 @@ ${block}
|
|
|
935
1077
|
`, "utf-8");
|
|
936
1078
|
}
|
|
937
1079
|
}
|
|
938
|
-
function ensureHook() {
|
|
939
|
-
const settingsPath =
|
|
1080
|
+
function ensureHook(projectRoot) {
|
|
1081
|
+
const settingsPath = join2(projectRoot, ".claude", "settings.local.json");
|
|
940
1082
|
let settings = {};
|
|
941
|
-
if (
|
|
1083
|
+
if (existsSync5(settingsPath)) {
|
|
942
1084
|
try {
|
|
943
|
-
settings = JSON.parse(
|
|
1085
|
+
settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
|
|
944
1086
|
} catch {
|
|
945
1087
|
return;
|
|
946
1088
|
}
|
|
@@ -956,22 +1098,28 @@ function ensureHook() {
|
|
|
956
1098
|
}
|
|
957
1099
|
const perms = settings.permissions ?? {};
|
|
958
1100
|
const allow = perms.allow ?? [];
|
|
959
|
-
const mcpAllows = [
|
|
1101
|
+
const mcpAllows = [
|
|
1102
|
+
"mcp__agentvalet__list_platforms",
|
|
1103
|
+
"mcp__agentvalet__read_platform",
|
|
1104
|
+
"mcp__agentvalet__write_platform",
|
|
1105
|
+
"mcp__agentvalet__delete_platform",
|
|
1106
|
+
"mcp__agentvalet__use_platform"
|
|
1107
|
+
];
|
|
960
1108
|
const missing = mcpAllows.filter((e) => !allow.includes(e));
|
|
961
1109
|
if (missing.length > 0) {
|
|
962
1110
|
perms.allow = [...allow, ...missing];
|
|
963
1111
|
settings.permissions = perms;
|
|
964
1112
|
}
|
|
965
|
-
mkdirSync2(
|
|
1113
|
+
mkdirSync2(dirname2(settingsPath), { recursive: true });
|
|
966
1114
|
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
967
|
-
ensureMcpJson();
|
|
1115
|
+
ensureMcpJson(projectRoot);
|
|
968
1116
|
}
|
|
969
|
-
function ensureMcpJson() {
|
|
970
|
-
const mcpJsonPath =
|
|
1117
|
+
function ensureMcpJson(projectRoot) {
|
|
1118
|
+
const mcpJsonPath = join2(projectRoot, ".mcp.json");
|
|
971
1119
|
let mcpConfig = {};
|
|
972
|
-
if (
|
|
1120
|
+
if (existsSync5(mcpJsonPath)) {
|
|
973
1121
|
try {
|
|
974
|
-
mcpConfig = JSON.parse(
|
|
1122
|
+
mcpConfig = JSON.parse(readFileSync4(mcpJsonPath, "utf-8"));
|
|
975
1123
|
} catch {
|
|
976
1124
|
return;
|
|
977
1125
|
}
|
|
@@ -1170,7 +1318,7 @@ async function writeLocalConfig(config) {
|
|
|
1170
1318
|
// src/output/env.ts
|
|
1171
1319
|
import chalk6 from "chalk";
|
|
1172
1320
|
import { appendFile as appendFile2, writeFile as writeFile3 } from "fs/promises";
|
|
1173
|
-
import { existsSync as
|
|
1321
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1174
1322
|
import path4 from "path";
|
|
1175
1323
|
function formatEnvBlock(vars) {
|
|
1176
1324
|
return Object.entries(vars).map(([key, value]) => {
|
|
@@ -1181,7 +1329,7 @@ function formatEnvBlock(vars) {
|
|
|
1181
1329
|
|
|
1182
1330
|
// src/config/ide.ts
|
|
1183
1331
|
import { mkdir as mkdir3, writeFile as writeFile4, readFile as readFile2, appendFile as appendFile3, copyFile } from "fs/promises";
|
|
1184
|
-
import { existsSync as
|
|
1332
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1185
1333
|
import path5 from "path";
|
|
1186
1334
|
import os2 from "os";
|
|
1187
1335
|
function buildMcpEntry(params) {
|
|
@@ -1218,7 +1366,7 @@ function claudeDesktopFriendly() {
|
|
|
1218
1366
|
}
|
|
1219
1367
|
async function mergeJsonFile(filePath, key, value) {
|
|
1220
1368
|
let existing = {};
|
|
1221
|
-
if (
|
|
1369
|
+
if (existsSync7(filePath)) {
|
|
1222
1370
|
try {
|
|
1223
1371
|
const text = await readFile2(filePath, "utf8");
|
|
1224
1372
|
existing = JSON.parse(text);
|
|
@@ -1230,48 +1378,6 @@ async function mergeJsonFile(filePath, key, value) {
|
|
|
1230
1378
|
existing.mcpServers = mcpServers;
|
|
1231
1379
|
await writeFile4(filePath, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
1232
1380
|
}
|
|
1233
|
-
function buildClaudeMd(agentId, ownerId, proxyUrl) {
|
|
1234
|
-
return `# AgentValet \u2014 Credential Governance
|
|
1235
|
-
|
|
1236
|
-
Agent ID: \`${agentId}\`
|
|
1237
|
-
Owner ID: \`${ownerId}\`
|
|
1238
|
-
|
|
1239
|
-
All external platform API calls **must** go through the AgentValet proxy.
|
|
1240
|
-
Never call platform APIs (Slack, Stripe, Gmail, GitHub, etc.) directly.
|
|
1241
|
-
|
|
1242
|
-
## Making a platform call
|
|
1243
|
-
|
|
1244
|
-
Use the \`mcp__agentvalet__use_platform\` MCP tool:
|
|
1245
|
-
|
|
1246
|
-
\`\`\`
|
|
1247
|
-
mcp__agentvalet__use_platform({
|
|
1248
|
-
platform: "slack",
|
|
1249
|
-
endpoint: "/api/chat.postMessage",
|
|
1250
|
-
method: "POST",
|
|
1251
|
-
scope: "slack:write",
|
|
1252
|
-
data: { channel: "#general", text: "Hello" }
|
|
1253
|
-
})
|
|
1254
|
-
\`\`\`
|
|
1255
|
-
|
|
1256
|
-
## Before any platform session
|
|
1257
|
-
|
|
1258
|
-
1. Call \`mcp__agentvalet__list_platforms\` to see approved platforms and scopes
|
|
1259
|
-
2. Call \`mcp__agentvalet__authzen_evaluate\` before destructive operations
|
|
1260
|
-
3. If a call returns \`pending_approval\` \u2014 wait, do not retry
|
|
1261
|
-
|
|
1262
|
-
## Rules
|
|
1263
|
-
|
|
1264
|
-
- **NEVER** write inline JWT signing code, \`node -e\` scripts, or manual HTTP calls
|
|
1265
|
-
- The MCP tool handles authentication automatically
|
|
1266
|
-
- \`AGENT_PRIVATE_KEY_PATH\` points to your key \u2014 do not read or log it
|
|
1267
|
-
|
|
1268
|
-
## If AgentValet MCP is not connected
|
|
1269
|
-
|
|
1270
|
-
Tell the user: "AgentValet MCP is not connected. Run: npx @agentvalet/register"
|
|
1271
|
-
|
|
1272
|
-
Dashboard: ${proxyUrl.replace("api.", "app.")}
|
|
1273
|
-
`;
|
|
1274
|
-
}
|
|
1275
1381
|
function buildCodexTomlBlock(params) {
|
|
1276
1382
|
return `
|
|
1277
1383
|
[mcp_servers.agentvalet]
|
|
@@ -1282,8 +1388,8 @@ env = { AGENT_ID = "${params.agentId}", OWNER_ID = "${params.ownerId}", PROXY_UR
|
|
|
1282
1388
|
}
|
|
1283
1389
|
async function appendCodexConfig(configPath) {
|
|
1284
1390
|
const dir = path5.dirname(configPath);
|
|
1285
|
-
if (!
|
|
1286
|
-
const existing =
|
|
1391
|
+
if (!existsSync7(dir)) await mkdir3(dir, { recursive: true });
|
|
1392
|
+
const existing = existsSync7(configPath) ? await readFile2(configPath, "utf8") : "";
|
|
1287
1393
|
if (existing.includes("[mcp_servers.agentvalet]")) return false;
|
|
1288
1394
|
return true;
|
|
1289
1395
|
}
|
|
@@ -1292,7 +1398,7 @@ async function writeGlobalFrameworkConfigs(params) {
|
|
|
1292
1398
|
const codexDir = path5.join(os2.homedir(), ".codex");
|
|
1293
1399
|
const codexConfigPath = path5.join(codexDir, "config.toml");
|
|
1294
1400
|
try {
|
|
1295
|
-
if (!
|
|
1401
|
+
if (!existsSync7(codexDir)) await mkdir3(codexDir, { recursive: true });
|
|
1296
1402
|
if (await appendCodexConfig(codexConfigPath)) {
|
|
1297
1403
|
await appendFile3(codexConfigPath, buildCodexTomlBlock(params), "utf8");
|
|
1298
1404
|
written.push("~/.codex/config.toml");
|
|
@@ -1317,7 +1423,7 @@ async function writeCodexProjectConfig(params) {
|
|
|
1317
1423
|
return written;
|
|
1318
1424
|
}
|
|
1319
1425
|
async function stripAgentvaletFromMcpJson(filePath) {
|
|
1320
|
-
if (!
|
|
1426
|
+
if (!existsSync7(filePath)) return false;
|
|
1321
1427
|
try {
|
|
1322
1428
|
const text = await readFile2(filePath, "utf8");
|
|
1323
1429
|
const config = JSON.parse(text);
|
|
@@ -1341,7 +1447,7 @@ async function cleanProjectScopedEntries() {
|
|
|
1341
1447
|
cleaned.push(".cursor/mcp.json (project entry removed)");
|
|
1342
1448
|
}
|
|
1343
1449
|
const factoryProjectMcp = path5.join(cwd, ".factory/mcp.json");
|
|
1344
|
-
if (
|
|
1450
|
+
if (existsSync7(factoryProjectMcp)) {
|
|
1345
1451
|
try {
|
|
1346
1452
|
const text = await readFile2(factoryProjectMcp, "utf8");
|
|
1347
1453
|
const config = JSON.parse(text);
|
|
@@ -1407,17 +1513,6 @@ async function writeIdeConfigs(params) {
|
|
|
1407
1513
|
} catch (err) {
|
|
1408
1514
|
console.warn(` Warning: could not write .mcp.json: ${err.message}`);
|
|
1409
1515
|
}
|
|
1410
|
-
const claudeMdPath = path5.join(cwd, "CLAUDE.md");
|
|
1411
|
-
if (!existsSync6(claudeMdPath)) {
|
|
1412
|
-
try {
|
|
1413
|
-
await writeFile4(claudeMdPath, buildClaudeMd(params.agentId, params.ownerId, params.proxyUrl), "utf8");
|
|
1414
|
-
written.push("CLAUDE.md");
|
|
1415
|
-
} catch (err) {
|
|
1416
|
-
console.warn(` Warning: could not write CLAUDE.md: ${err.message}`);
|
|
1417
|
-
}
|
|
1418
|
-
} else {
|
|
1419
|
-
written.push("CLAUDE.md (already exists \u2014 skipped)");
|
|
1420
|
-
}
|
|
1421
1516
|
}
|
|
1422
1517
|
if (detected.cursor || detected.cursorCli) {
|
|
1423
1518
|
const cursorDir = path5.join(cwd, ".cursor");
|
|
@@ -1443,7 +1538,7 @@ async function writeIdeConfigs(params) {
|
|
|
1443
1538
|
}
|
|
1444
1539
|
async function mergeFactoryDroidMcpJson(filePath, key, value) {
|
|
1445
1540
|
let existing = {};
|
|
1446
|
-
if (
|
|
1541
|
+
if (existsSync7(filePath)) {
|
|
1447
1542
|
try {
|
|
1448
1543
|
const text = await readFile2(filePath, "utf8");
|
|
1449
1544
|
existing = JSON.parse(text);
|
|
@@ -1457,7 +1552,7 @@ async function mergeFactoryDroidMcpJson(filePath, key, value) {
|
|
|
1457
1552
|
}
|
|
1458
1553
|
async function updateGitignoreForFactoryDroid() {
|
|
1459
1554
|
const gitignorePath = path5.join(process.cwd(), ".gitignore");
|
|
1460
|
-
if (!
|
|
1555
|
+
if (!existsSync7(gitignorePath)) return;
|
|
1461
1556
|
const existing = await readFile2(gitignorePath, "utf8");
|
|
1462
1557
|
if (existing.includes(".factory/mcp.json")) return;
|
|
1463
1558
|
const additions = [
|
|
@@ -1676,6 +1771,7 @@ async function registerAgentFlow(apiKey, ownerId, scope = "user", presetName) {
|
|
|
1676
1771
|
detected
|
|
1677
1772
|
});
|
|
1678
1773
|
}
|
|
1774
|
+
await writeGovernanceInstructions(agent.agent_id, ownerId);
|
|
1679
1775
|
ensureMcpServer();
|
|
1680
1776
|
} else if (shouldSetup === false) {
|
|
1681
1777
|
console.log("");
|
|
@@ -1838,8 +1934,8 @@ import chalk10 from "chalk";
|
|
|
1838
1934
|
// src/commands/uninstall.ts
|
|
1839
1935
|
import { Command as Command2 } from "commander";
|
|
1840
1936
|
import chalk9 from "chalk";
|
|
1841
|
-
import { existsSync as
|
|
1842
|
-
import { resolve as resolve3, join } from "path";
|
|
1937
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync3, rmSync } from "fs";
|
|
1938
|
+
import { resolve as resolve3, join as join3 } from "path";
|
|
1843
1939
|
import { homedir } from "os";
|
|
1844
1940
|
var CLAUDE_START2 = "<!-- agentvalet:start -->";
|
|
1845
1941
|
var CLAUDE_END2 = "<!-- agentvalet:end -->";
|
|
@@ -1847,9 +1943,9 @@ var PERMISSIONS_START2 = "<!-- agentvalet:permissions:start -->";
|
|
|
1847
1943
|
var PERMISSIONS_END2 = "<!-- agentvalet:permissions:end -->";
|
|
1848
1944
|
var HOOK_MARKER2 = "agentvalet/register refresh";
|
|
1849
1945
|
function stripPermissionsBlock(filePath) {
|
|
1850
|
-
if (!
|
|
1946
|
+
if (!existsSync8(filePath)) return false;
|
|
1851
1947
|
try {
|
|
1852
|
-
const content =
|
|
1948
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
1853
1949
|
if (!content.includes(PERMISSIONS_START2)) return false;
|
|
1854
1950
|
const stripped = content.replace(new RegExp(`${PERMISSIONS_START2}[\\s\\S]*?${PERMISSIONS_END2}`, "m"), "").replace(/(\r?\n){3,}/g, "\n\n").trimEnd();
|
|
1855
1951
|
writeFileSync3(filePath, stripped + "\n", "utf-8");
|
|
@@ -1860,8 +1956,8 @@ function stripPermissionsBlock(filePath) {
|
|
|
1860
1956
|
}
|
|
1861
1957
|
function stripClaudeMd() {
|
|
1862
1958
|
const path8 = resolve3("CLAUDE.md");
|
|
1863
|
-
if (!
|
|
1864
|
-
let content =
|
|
1959
|
+
if (!existsSync8(path8)) return;
|
|
1960
|
+
let content = readFileSync5(path8, "utf-8");
|
|
1865
1961
|
content = content.replace(new RegExp(`${CLAUDE_START2}[\\s\\S]*?${CLAUDE_END2}`, "m"), "");
|
|
1866
1962
|
content = content.replace(/^@\.claude\/agentvalet-permissions\.md\s*$/m, "");
|
|
1867
1963
|
content = content.replace(/(\r?\n){3,}/g, "\n\n").trim();
|
|
@@ -1869,9 +1965,9 @@ function stripClaudeMd() {
|
|
|
1869
1965
|
}
|
|
1870
1966
|
function stripSettingsJson() {
|
|
1871
1967
|
const path8 = resolve3(".claude/settings.local.json");
|
|
1872
|
-
if (!
|
|
1968
|
+
if (!existsSync8(path8)) return;
|
|
1873
1969
|
try {
|
|
1874
|
-
const settings = JSON.parse(
|
|
1970
|
+
const settings = JSON.parse(readFileSync5(path8, "utf-8"));
|
|
1875
1971
|
const hooks = settings.hooks ?? {};
|
|
1876
1972
|
const ups = hooks.UserPromptSubmit ?? [];
|
|
1877
1973
|
hooks.UserPromptSubmit = ups.filter(
|
|
@@ -1887,9 +1983,9 @@ function stripSettingsJson() {
|
|
|
1887
1983
|
}
|
|
1888
1984
|
}
|
|
1889
1985
|
function stripMcpJson(filePath, options = {}) {
|
|
1890
|
-
if (!
|
|
1986
|
+
if (!existsSync8(filePath)) return false;
|
|
1891
1987
|
try {
|
|
1892
|
-
const config = JSON.parse(
|
|
1988
|
+
const config = JSON.parse(readFileSync5(filePath, "utf-8"));
|
|
1893
1989
|
let removed = false;
|
|
1894
1990
|
if (options.wrapped === false) {
|
|
1895
1991
|
if (config["agentvalet"] !== void 0) {
|
|
@@ -1913,9 +2009,9 @@ function stripMcpJson(filePath, options = {}) {
|
|
|
1913
2009
|
}
|
|
1914
2010
|
}
|
|
1915
2011
|
function stripCodexTomlAt(filePath) {
|
|
1916
|
-
if (!
|
|
2012
|
+
if (!existsSync8(filePath)) return false;
|
|
1917
2013
|
try {
|
|
1918
|
-
const content =
|
|
2014
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
1919
2015
|
if (!content.includes("[mcp_servers.agentvalet]")) return false;
|
|
1920
2016
|
const stripped = content.replace(
|
|
1921
2017
|
/\r?\n?\[mcp_servers\.agentvalet\][\s\S]*?(?=\r?\n\[|\r?\n*$)/,
|
|
@@ -1928,9 +2024,9 @@ function stripCodexTomlAt(filePath) {
|
|
|
1928
2024
|
}
|
|
1929
2025
|
}
|
|
1930
2026
|
function isAgentValetGeneratedDoc(filePath, markers) {
|
|
1931
|
-
if (!
|
|
2027
|
+
if (!existsSync8(filePath)) return false;
|
|
1932
2028
|
try {
|
|
1933
|
-
const content =
|
|
2029
|
+
const content = readFileSync5(filePath, "utf-8");
|
|
1934
2030
|
const firstLine = content.split(/\r?\n/).find((l) => l.trim().length > 0) ?? "";
|
|
1935
2031
|
return markers.some((m) => firstLine.startsWith(m));
|
|
1936
2032
|
} catch {
|
|
@@ -1942,13 +2038,13 @@ function cleanLocally() {
|
|
|
1942
2038
|
const stripped = [];
|
|
1943
2039
|
const r = (p) => {
|
|
1944
2040
|
const abs = resolve3(p);
|
|
1945
|
-
if (
|
|
2041
|
+
if (existsSync8(abs)) {
|
|
1946
2042
|
rmSync(abs, { recursive: true, force: true });
|
|
1947
2043
|
removed.push(abs);
|
|
1948
2044
|
}
|
|
1949
2045
|
};
|
|
1950
2046
|
const rAbs = (abs) => {
|
|
1951
|
-
if (
|
|
2047
|
+
if (existsSync8(abs)) {
|
|
1952
2048
|
rmSync(abs, { recursive: true, force: true });
|
|
1953
2049
|
removed.push(abs);
|
|
1954
2050
|
}
|
|
@@ -1971,12 +2067,12 @@ function cleanLocally() {
|
|
|
1971
2067
|
if (stripMcpJson(resolve3(".cursor/mcp.json"))) stripped.push(".cursor/mcp.json");
|
|
1972
2068
|
if (stripMcpJson(resolve3(".factory/mcp.json"), { wrapped: false })) stripped.push(".factory/mcp.json");
|
|
1973
2069
|
const home = homedir();
|
|
1974
|
-
if (stripMcpJson(
|
|
1975
|
-
const claudeDesktopConfig = process.platform === "darwin" ?
|
|
2070
|
+
if (stripMcpJson(join3(home, ".claude.json"))) stripped.push("~/.claude.json");
|
|
2071
|
+
const claudeDesktopConfig = process.platform === "darwin" ? join3(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : process.platform === "win32" ? join3(process.env.APPDATA ?? join3(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json") : join3(home, ".config", "Claude", "claude_desktop_config.json");
|
|
1976
2072
|
if (stripMcpJson(claudeDesktopConfig)) stripped.push("claude_desktop_config.json");
|
|
1977
|
-
if (stripMcpJson(
|
|
1978
|
-
if (stripMcpJson(
|
|
1979
|
-
if (stripCodexTomlAt(
|
|
2073
|
+
if (stripMcpJson(join3(home, ".cursor", "mcp.json"))) stripped.push("~/.cursor/mcp.json");
|
|
2074
|
+
if (stripMcpJson(join3(home, ".factory", "mcp.json"), { wrapped: false })) stripped.push("~/.factory/mcp.json");
|
|
2075
|
+
if (stripCodexTomlAt(join3(home, ".codex", "config.toml"))) stripped.push("~/.codex/config.toml");
|
|
1980
2076
|
if (stripCodexTomlAt(resolve3(".codex/config.toml"))) stripped.push(".codex/config.toml");
|
|
1981
2077
|
stripClaudeMd();
|
|
1982
2078
|
stripSettingsJson();
|
|
@@ -2081,7 +2177,7 @@ function uninstallCommand() {
|
|
|
2081
2177
|
}
|
|
2082
2178
|
let privateKeyPem;
|
|
2083
2179
|
try {
|
|
2084
|
-
privateKeyPem =
|
|
2180
|
+
privateKeyPem = readFileSync5(creds.keyPath, "utf-8").trim();
|
|
2085
2181
|
} catch {
|
|
2086
2182
|
}
|
|
2087
2183
|
if (!privateKeyPem) {
|
|
@@ -2198,13 +2294,13 @@ function revokeCommand() {
|
|
|
2198
2294
|
import { Command as Command4 } from "commander";
|
|
2199
2295
|
import chalk11 from "chalk";
|
|
2200
2296
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile8 } from "fs/promises";
|
|
2201
|
-
import { dirname as
|
|
2297
|
+
import { dirname as dirname3 } from "path";
|
|
2202
2298
|
|
|
2203
2299
|
// src/lib/claude-config.ts
|
|
2204
2300
|
import { homedir as homedir2 } from "os";
|
|
2205
|
-
import { join as
|
|
2301
|
+
import { join as join4 } from "path";
|
|
2206
2302
|
import { readFile as readFile3, writeFile as writeFile6, mkdir as mkdir4, access } from "fs/promises";
|
|
2207
|
-
var CLAUDE_CONFIG_PATH =
|
|
2303
|
+
var CLAUDE_CONFIG_PATH = join4(homedir2(), ".claude", "config");
|
|
2208
2304
|
async function writeKeyToClaudeConfig(agentId, privateKeyPem) {
|
|
2209
2305
|
let config = {};
|
|
2210
2306
|
try {
|
|
@@ -2215,7 +2311,7 @@ async function writeKeyToClaudeConfig(agentId, privateKeyPem) {
|
|
|
2215
2311
|
}
|
|
2216
2312
|
config.agent_keys = config.agent_keys ?? {};
|
|
2217
2313
|
config.agent_keys[agentId] = Buffer.from(privateKeyPem).toString("base64");
|
|
2218
|
-
await mkdir4(
|
|
2314
|
+
await mkdir4(join4(homedir2(), ".claude"), { recursive: true });
|
|
2219
2315
|
await writeFile6(CLAUDE_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
|
2220
2316
|
}
|
|
2221
2317
|
|
|
@@ -2250,7 +2346,7 @@ function injectCommand() {
|
|
|
2250
2346
|
"--target <target>",
|
|
2251
2347
|
"Where to write the key: agentvalet (default \u2014 modern store + MCP configs), env-local (.env.local), claude-legacy (~/.claude/config, deprecated)",
|
|
2252
2348
|
"agentvalet"
|
|
2253
|
-
).option("--no-frameworks", "Skip IDE/framework configuration prompts (only with --target agentvalet)").option("--project", "Write project-scoped framework configs instead of user-scoped").action(async (opts) => {
|
|
2349
|
+
).option("--no-frameworks", "Skip IDE/framework configuration prompts (only with --target agentvalet)").option("--project", "Write project-scoped framework configs instead of user-scoped").option("--force", "Replace an existing agent key (a timestamped backup is written first)").action(async (opts) => {
|
|
2254
2350
|
let privateKeyPem;
|
|
2255
2351
|
try {
|
|
2256
2352
|
privateKeyPem = await readFile5(opts.keyFile, "utf-8");
|
|
@@ -2270,7 +2366,8 @@ function injectCommand() {
|
|
|
2270
2366
|
console.error(chalk11.dim(" Find it at https://app.agentvalet.ai or in your existing ~/.agentvalet/config.json"));
|
|
2271
2367
|
process.exit(1);
|
|
2272
2368
|
}
|
|
2273
|
-
await mkdir5(
|
|
2369
|
+
await mkdir5(dirname3(AGENT_KEY_PATH), { recursive: true });
|
|
2370
|
+
assertSafeToWriteKey(AGENT_KEY_PATH, opts.agentId, { force: opts.force });
|
|
2274
2371
|
await writeFile8(AGENT_KEY_PATH, privateKeyPem, { mode: 384 });
|
|
2275
2372
|
saveConfig({
|
|
2276
2373
|
agentId: opts.agentId,
|
|
@@ -2325,7 +2422,7 @@ function injectCommand() {
|
|
|
2325
2422
|
process.exit(1);
|
|
2326
2423
|
}
|
|
2327
2424
|
} catch (err) {
|
|
2328
|
-
console.error(chalk11.red(String(err)));
|
|
2425
|
+
console.error(chalk11.red(err instanceof KeyClobberError ? err.message : String(err)));
|
|
2329
2426
|
process.exit(1);
|
|
2330
2427
|
}
|
|
2331
2428
|
console.log(chalk11.green("\n Done. Your agent is ready to use."));
|
|
@@ -2368,7 +2465,7 @@ async function bindInstallToken(proxyUrl, bootstrapToken) {
|
|
|
2368
2465
|
return { ...body, privateKeyPem: privateKey };
|
|
2369
2466
|
}
|
|
2370
2467
|
function installCommand() {
|
|
2371
|
-
return new Command5("install").description("Install an agent on this machine using a one-time install token (generates the keypair locally and binds it)").argument("<token>", "install token (itok_...) from the dashboard").option("--no-frameworks", "skip IDE/framework configuration prompts").option("--project", "write project-scoped configs (.mcp.json, .cursor/mcp.json) instead of user-scoped (~/.claude.json, ~/.cursor/mcp.json)").action(async (token, opts) => {
|
|
2468
|
+
return new Command5("install").description("Install an agent on this machine using a one-time install token (generates the keypair locally and binds it)").argument("<token>", "install token (itok_...) from the dashboard").option("--no-frameworks", "skip IDE/framework configuration prompts").option("--project", "write project-scoped configs (.mcp.json, .cursor/mcp.json) instead of user-scoped (~/.claude.json, ~/.cursor/mcp.json)").option("--force", "replace an existing agent key (a timestamped backup is written first)").action(async (token, opts) => {
|
|
2372
2469
|
const scope = opts.project ? "project" : "user";
|
|
2373
2470
|
if (!token.startsWith("itok_")) {
|
|
2374
2471
|
console.error(chalk12.red('Invalid install token. Tokens start with "itok_".'));
|
|
@@ -2394,8 +2491,14 @@ function installCommand() {
|
|
|
2394
2491
|
const agent_name = claim.agent_id;
|
|
2395
2492
|
try {
|
|
2396
2493
|
await mkdir6(AGENT_DIR, { recursive: true });
|
|
2494
|
+
assertSafeToWriteKey(AGENT_KEY_PATH, agent_id, { force: opts.force });
|
|
2397
2495
|
await writeFile9(AGENT_KEY_PATH, private_key_pem, { mode: 384 });
|
|
2398
2496
|
} catch (err) {
|
|
2497
|
+
if (err instanceof KeyClobberError) {
|
|
2498
|
+
console.error(chalk12.red(`
|
|
2499
|
+
\u2717 ${err.message}`));
|
|
2500
|
+
process.exit(3);
|
|
2501
|
+
}
|
|
2399
2502
|
console.error(chalk12.red(`
|
|
2400
2503
|
\u2717 Failed to write key: ${err instanceof Error ? err.message : err}`));
|
|
2401
2504
|
process.exit(3);
|
|
@@ -2460,6 +2563,7 @@ function installCommand() {
|
|
|
2460
2563
|
detected
|
|
2461
2564
|
});
|
|
2462
2565
|
}
|
|
2566
|
+
await writeGovernanceInstructions(agent_id, owner_id);
|
|
2463
2567
|
ensureMcpServer();
|
|
2464
2568
|
}
|
|
2465
2569
|
}
|
|
@@ -2530,14 +2634,14 @@ function installCommand() {
|
|
|
2530
2634
|
// src/commands/claim.ts
|
|
2531
2635
|
import { Command as Command6 } from "commander";
|
|
2532
2636
|
import { generateKeyPairSync as generateKeyPairSync2 } from "crypto";
|
|
2533
|
-
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as
|
|
2637
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, existsSync as existsSync9 } from "fs";
|
|
2534
2638
|
import { homedir as homedir3 } from "os";
|
|
2535
|
-
import { join as
|
|
2639
|
+
import { join as join5 } from "path";
|
|
2536
2640
|
import chalk13 from "chalk";
|
|
2537
2641
|
var DEFAULT_PROXY_URL = "https://api.agentvalet.ai";
|
|
2538
2642
|
function resolveAgentDir(label) {
|
|
2539
|
-
const root =
|
|
2540
|
-
return label ?
|
|
2643
|
+
const root = join5(homedir3(), ".agentvalet");
|
|
2644
|
+
return label ? join5(root, label) : root;
|
|
2541
2645
|
}
|
|
2542
2646
|
function sanitiseLabel(label) {
|
|
2543
2647
|
return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -2581,9 +2685,9 @@ function claimCommand() {
|
|
|
2581
2685
|
process.exit(3);
|
|
2582
2686
|
}
|
|
2583
2687
|
const agentDir = resolveAgentDir(label);
|
|
2584
|
-
const keyPath =
|
|
2585
|
-
const identityPath =
|
|
2586
|
-
if (
|
|
2688
|
+
const keyPath = join5(agentDir, "agent.key");
|
|
2689
|
+
const identityPath = join5(agentDir, "agent.json");
|
|
2690
|
+
if (existsSync9(keyPath)) {
|
|
2587
2691
|
const msg = label ? `An agent already exists at ${keyPath}. Pick a different --label or remove the directory first.` : `A default agent already exists at ${keyPath}. Pass --label <name> to claim alongside it without overwriting.`;
|
|
2588
2692
|
console.error(isJson ? JSON.stringify({ error: msg }) : chalk13.red(msg));
|
|
2589
2693
|
process.exit(3);
|
|
@@ -2675,7 +2779,7 @@ function collectScope(value, previous) {
|
|
|
2675
2779
|
return [...previous, value];
|
|
2676
2780
|
}
|
|
2677
2781
|
var program = new Command7();
|
|
2678
|
-
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version(version).option("--owner <uuid>", "Owner ID (or set AGENTVALET_OWNER env var)").option("--name <name>", "Agent name").option("--description <desc>", "Agent description").option("--scope <platform:scope>", "Requested scope, repeatable", collectScope, []).option("--api-url <url>", "AgentValet API base URL", "https://api.agentvalet.ai").option("--json", "Machine-readable JSON output").option("--no-wait", "Register only, do not wait for approval").option("--timeout <seconds>", "Approval wait timeout in seconds", "300").option("--project", "Write project-scoped MCP configs (.mcp.json, .cursor/mcp.json) instead of user-scoped (~/.claude.json, ~/.cursor/mcp.json)").action(async (opts) => {
|
|
2782
|
+
program.name("agentvalet-register").description("Self-register an AI agent with AgentValet").version(version).option("--owner <uuid>", "Owner ID (or set AGENTVALET_OWNER env var)").option("--name <name>", "Agent name").option("--description <desc>", "Agent description").option("--scope <platform:scope>", "Requested scope, repeatable", collectScope, []).option("--api-url <url>", "AgentValet API base URL", "https://api.agentvalet.ai").option("--json", "Machine-readable JSON output").option("--no-wait", "Register only, do not wait for approval").option("--timeout <seconds>", "Approval wait timeout in seconds", "300").option("--project", "Write project-scoped MCP configs (.mcp.json, .cursor/mcp.json) instead of user-scoped (~/.claude.json, ~/.cursor/mcp.json)").option("--force", "Replace an existing agent's key (a timestamped backup is written first)").action(async (opts) => {
|
|
2679
2783
|
const isJson = !!opts.json;
|
|
2680
2784
|
let ownerId = opts.owner ?? process.env.AGENTVALET_OWNER ?? "";
|
|
2681
2785
|
let agentName = opts.name ?? "";
|
|
@@ -2791,10 +2895,15 @@ Approve at: https://app.agentvalet.ai/agents
|
|
|
2791
2895
|
agentId,
|
|
2792
2896
|
ownerId: resolvedOwnerId,
|
|
2793
2897
|
privateKey,
|
|
2794
|
-
apiUrl: opts.apiUrl
|
|
2898
|
+
apiUrl: opts.apiUrl,
|
|
2899
|
+
force: !!opts.force
|
|
2795
2900
|
}));
|
|
2796
2901
|
} catch (err) {
|
|
2797
2902
|
const msg = err instanceof Error ? err.message : String(err);
|
|
2903
|
+
if (err instanceof KeyClobberError) {
|
|
2904
|
+
console.error(isJson ? JSON.stringify({ error: msg, existing_agent_id: err.existingAgentId }) : chalk14.red(msg));
|
|
2905
|
+
process.exit(3);
|
|
2906
|
+
}
|
|
2798
2907
|
console.error(isJson ? JSON.stringify({ error: msg }) : chalk14.red(`Failed to save output: ${msg}`));
|
|
2799
2908
|
process.exit(3);
|
|
2800
2909
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentvalet/register",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Self-register AI agents with AgentValet",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,13 @@
|
|
|
10
10
|
"dist",
|
|
11
11
|
"README.md"
|
|
12
12
|
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/index.ts --format esm --dts --clean --shims",
|
|
15
|
+
"dev": "tsx src/index.ts",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"prepublishOnly": "node ../../scripts/no-secrets.mjs && pnpm build && node ../../scripts/no-workspace-protocol.mjs"
|
|
19
|
+
},
|
|
13
20
|
"dependencies": {
|
|
14
21
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
15
22
|
"@octokit/auth-oauth-device": "^7.0.0",
|
|
@@ -22,22 +29,23 @@
|
|
|
22
29
|
"undici": "^6.0.0"
|
|
23
30
|
},
|
|
24
31
|
"devDependencies": {
|
|
32
|
+
"@agentvalet/mcp-server": "workspace:^",
|
|
25
33
|
"@types/node": "^20.0.0",
|
|
26
34
|
"@types/prompts": "^2.4.0",
|
|
27
35
|
"tsup": "^8.0.0",
|
|
28
36
|
"tsx": "^4.0.0",
|
|
29
37
|
"typescript": "^5.0.0",
|
|
30
|
-
"vitest": "^1.5.0"
|
|
31
|
-
"@agentvalet/mcp-server": "^1.4.1"
|
|
38
|
+
"vitest": "^1.5.0"
|
|
32
39
|
},
|
|
33
40
|
"engines": {
|
|
34
41
|
"node": ">=18"
|
|
35
42
|
},
|
|
36
43
|
"repository": {
|
|
37
44
|
"type": "git",
|
|
38
|
-
"url": "git+https://github.com/
|
|
45
|
+
"url": "git+https://github.com/AgentValet/AgentValet.git",
|
|
46
|
+
"directory": "packages/cli"
|
|
39
47
|
},
|
|
40
|
-
"homepage": "https://
|
|
48
|
+
"homepage": "https://github.com/AgentValet/AgentValet#readme",
|
|
41
49
|
"bugs": {
|
|
42
50
|
"url": "https://github.com/agentvalet/agentvalet/issues"
|
|
43
51
|
},
|
|
@@ -53,11 +61,5 @@
|
|
|
53
61
|
"valet",
|
|
54
62
|
"agentvalet"
|
|
55
63
|
],
|
|
56
|
-
"license": "MIT"
|
|
57
|
-
|
|
58
|
-
"build": "tsup src/index.ts --format esm --dts --clean --shims",
|
|
59
|
-
"dev": "tsx src/index.ts",
|
|
60
|
-
"test": "vitest run",
|
|
61
|
-
"typecheck": "tsc --noEmit"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
+
"license": "MIT"
|
|
65
|
+
}
|