@agenticmail/enterprise 0.5.3 → 0.5.5
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/{chunk-ANW4OHXR.js → chunk-6CVIA5YL.js} +52 -8
- package/dist/{chunk-PQADDAC2.js → chunk-VRRCELRN.js} +43 -0
- package/dist/cli-build-skill-AE7QC5C5.js +235 -0
- package/dist/{cli-recover-SSGGSKZJ.js → cli-recover-5M74V7V4.js} +2 -2
- package/dist/cli-submit-skill-LDFJGSKO.js +162 -0
- package/dist/cli-validate-QTV6662P.js +148 -0
- package/dist/cli.js +12 -12
- package/dist/index.js +1 -1
- package/dist/{setup-RCYNX5NA.js → setup-HJ4PTUSA.js} +1 -1
- package/dist/{setup-5CVRQ5ES.js → setup-WUDZZ25K.js} +1 -1
- package/package.json +1 -1
- package/src/cli.ts +13 -13
- package/src/domain-lock/cli-recover.ts +4 -4
- package/src/domain-lock/cli-verify.ts +3 -3
- package/src/engine/cli-build-skill.ts +2 -2
- package/src/engine/cli-submit-skill.ts +3 -3
- package/src/engine/cli-validate.ts +3 -3
- package/src/setup/index.ts +47 -0
- package/src/setup/registration.ts +4 -4
- package/dist/chunk-E23VJ3QX.js +0 -9427
- package/dist/chunk-EOBN6RCA.js +0 -12652
- package/dist/chunk-HAUHDCUB.js +0 -764
- package/dist/chunk-HSF6OJ5Z.js +0 -154
- package/dist/chunk-SMUXH6FM.js +0 -1943
- package/dist/chunk-V2YIXYDJ.js +0 -1943
- package/dist/cli-verify-V3GPFMWU.js +0 -98
- package/dist/domain-lock-URIFILHB.js +0 -7
- package/dist/routes-NJK5OI5N.js +0 -5673
- package/dist/runtime-SMA6JUMP.js +0 -46
- package/dist/server-OGQWCOT6.js +0 -11
- package/dist/server-ZT5NWHT4.js +0 -11
- package/dist/setup-HCMMUEW6.js +0 -20
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
getSupportedDatabases
|
|
3
3
|
} from "./chunk-NTVN3JHS.js";
|
|
4
4
|
|
|
5
|
+
// src/setup/index.ts
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
|
|
5
8
|
// src/setup/company.ts
|
|
6
9
|
function toSlug(name) {
|
|
7
10
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 63);
|
|
@@ -310,7 +313,7 @@ async function promptDomain(inquirer, chalk, deployTarget) {
|
|
|
310
313
|
|
|
311
314
|
// src/setup/registration.ts
|
|
312
315
|
import { randomBytes } from "crypto";
|
|
313
|
-
var REGISTRY_BASE_URL = process.env.AGENTICMAIL_REGISTRY_URL || "https://
|
|
316
|
+
var REGISTRY_BASE_URL = process.env.AGENTICMAIL_REGISTRY_URL || "https://agenticmail.io/enterprise/v1";
|
|
314
317
|
async function promptRegistration(inquirer, chalk, ora, domain, companyName, adminEmail) {
|
|
315
318
|
if (!domain) {
|
|
316
319
|
return { registered: false, verificationStatus: "skipped" };
|
|
@@ -329,9 +332,9 @@ async function promptRegistration(inquirer, chalk, ora, domain, companyName, adm
|
|
|
329
332
|
return { registered: false, verificationStatus: "skipped" };
|
|
330
333
|
}
|
|
331
334
|
const spinner = ora("Generating deployment key...").start();
|
|
332
|
-
const {
|
|
335
|
+
const { createHash } = await import("crypto");
|
|
333
336
|
const plaintextKey = randomBytes(32).toString("hex");
|
|
334
|
-
const keyHash =
|
|
337
|
+
const keyHash = createHash("sha256").update(plaintextKey).digest("hex");
|
|
335
338
|
spinner.succeed("Deployment key generated");
|
|
336
339
|
spinner.start("Registering domain with AgenticMail registry...");
|
|
337
340
|
const registryUrl = REGISTRY_BASE_URL.replace(/\/$/, "");
|
|
@@ -344,6 +347,7 @@ async function promptRegistration(inquirer, chalk, ora, domain, companyName, adm
|
|
|
344
347
|
body: JSON.stringify({
|
|
345
348
|
domain: domain.toLowerCase().trim(),
|
|
346
349
|
keyHash,
|
|
350
|
+
sha256Hash: keyHash,
|
|
347
351
|
orgName: companyName,
|
|
348
352
|
contactEmail: adminEmail
|
|
349
353
|
}),
|
|
@@ -354,7 +358,7 @@ async function promptRegistration(inquirer, chalk, ora, domain, companyName, adm
|
|
|
354
358
|
spinner.fail("Domain already registered");
|
|
355
359
|
console.log("");
|
|
356
360
|
console.log(chalk.yellow(" This domain is already registered and verified."));
|
|
357
|
-
console.log(chalk.dim(" If this is your domain, use: agenticmail
|
|
361
|
+
console.log(chalk.dim(" If this is your domain, use: npx @agenticmail/enterprise recover"));
|
|
358
362
|
console.log("");
|
|
359
363
|
const { continueAnyway } = await inquirer.prompt([{
|
|
360
364
|
type: "confirm",
|
|
@@ -377,7 +381,7 @@ async function promptRegistration(inquirer, chalk, ora, domain, companyName, adm
|
|
|
377
381
|
spinner.warn("Registry unavailable");
|
|
378
382
|
console.log("");
|
|
379
383
|
console.log(chalk.yellow(` Could not reach registry: ${err.message}`));
|
|
380
|
-
console.log(chalk.dim(" You can register later with: agenticmail
|
|
384
|
+
console.log(chalk.dim(" You can register later with: npx @agenticmail/enterprise verify-domain"));
|
|
381
385
|
console.log("");
|
|
382
386
|
const { continueAnyway } = await inquirer.prompt([{
|
|
383
387
|
type: "confirm",
|
|
@@ -444,11 +448,11 @@ async function promptRegistration(inquirer, chalk, ora, domain, companyName, adm
|
|
|
444
448
|
await new Promise((r) => setTimeout(r, 1e4));
|
|
445
449
|
} else {
|
|
446
450
|
spinner.info("DNS record not found yet");
|
|
447
|
-
console.log(chalk.dim(" Run later: agenticmail
|
|
451
|
+
console.log(chalk.dim(" Run later: npx @agenticmail/enterprise verify-domain"));
|
|
448
452
|
}
|
|
449
453
|
}
|
|
450
454
|
} else {
|
|
451
|
-
console.log(chalk.dim(" Run when ready: agenticmail
|
|
455
|
+
console.log(chalk.dim(" Run when ready: npx @agenticmail/enterprise verify-domain"));
|
|
452
456
|
}
|
|
453
457
|
console.log("");
|
|
454
458
|
return {
|
|
@@ -636,7 +640,7 @@ async function deploy(config, db, jwtSecret, spinner, chalk) {
|
|
|
636
640
|
return {};
|
|
637
641
|
}
|
|
638
642
|
spinner.start("Starting local server...");
|
|
639
|
-
const { createServer } = await import("./server-
|
|
643
|
+
const { createServer } = await import("./server-6LWKND7R.js");
|
|
640
644
|
const server = createServer({ port: 3e3, db, jwtSecret });
|
|
641
645
|
const handle = await server.start();
|
|
642
646
|
spinner.succeed("Server running");
|
|
@@ -714,6 +718,45 @@ function printCustomDomainInstructions(chalk, domain, target, cnameTarget) {
|
|
|
714
718
|
}
|
|
715
719
|
|
|
716
720
|
// src/setup/index.ts
|
|
721
|
+
var DB_DRIVER_MAP = {
|
|
722
|
+
postgres: ["pg"],
|
|
723
|
+
supabase: ["pg"],
|
|
724
|
+
neon: ["pg"],
|
|
725
|
+
cockroachdb: ["pg"],
|
|
726
|
+
mysql: ["mysql2"],
|
|
727
|
+
planetscale: ["mysql2"],
|
|
728
|
+
mongodb: ["mongodb"],
|
|
729
|
+
sqlite: ["better-sqlite3"],
|
|
730
|
+
turso: ["@libsql/client"],
|
|
731
|
+
dynamodb: ["@aws-sdk/client-dynamodb", "@aws-sdk/lib-dynamodb"]
|
|
732
|
+
};
|
|
733
|
+
async function ensureDbDriver(dbType, ora, chalk) {
|
|
734
|
+
const packages = DB_DRIVER_MAP[dbType];
|
|
735
|
+
if (!packages?.length) return;
|
|
736
|
+
const missing = [];
|
|
737
|
+
for (const pkg of packages) {
|
|
738
|
+
try {
|
|
739
|
+
await import(pkg);
|
|
740
|
+
} catch {
|
|
741
|
+
missing.push(pkg);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (!missing.length) return;
|
|
745
|
+
const spinner = ora(`Installing database driver: ${missing.join(", ")}...`).start();
|
|
746
|
+
try {
|
|
747
|
+
execSync(`npm install --no-save ${missing.join(" ")}`, {
|
|
748
|
+
stdio: "pipe",
|
|
749
|
+
timeout: 12e4
|
|
750
|
+
});
|
|
751
|
+
spinner.succeed(`Database driver installed: ${missing.join(", ")}`);
|
|
752
|
+
} catch (err) {
|
|
753
|
+
spinner.fail(`Failed to install ${missing.join(", ")}`);
|
|
754
|
+
console.error(chalk.red(`
|
|
755
|
+
Run manually: npm install ${missing.join(" ")}
|
|
756
|
+
`));
|
|
757
|
+
process.exit(1);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
717
760
|
async function runSetupWizard() {
|
|
718
761
|
const { default: inquirer } = await import("inquirer");
|
|
719
762
|
const { default: ora } = await import("ora");
|
|
@@ -736,6 +779,7 @@ async function runSetupWizard() {
|
|
|
736
779
|
company.companyName,
|
|
737
780
|
company.adminEmail
|
|
738
781
|
);
|
|
782
|
+
await ensureDbDriver(database.type, ora, chalk);
|
|
739
783
|
console.log("");
|
|
740
784
|
console.log(chalk.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
741
785
|
console.log("");
|
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
getSupportedDatabases
|
|
3
3
|
} from "./chunk-NTVN3JHS.js";
|
|
4
4
|
|
|
5
|
+
// src/setup/index.ts
|
|
6
|
+
import { execSync } from "child_process";
|
|
7
|
+
|
|
5
8
|
// src/setup/company.ts
|
|
6
9
|
function toSlug(name) {
|
|
7
10
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 63);
|
|
@@ -715,6 +718,45 @@ function printCustomDomainInstructions(chalk, domain, target, cnameTarget) {
|
|
|
715
718
|
}
|
|
716
719
|
|
|
717
720
|
// src/setup/index.ts
|
|
721
|
+
var DB_DRIVER_MAP = {
|
|
722
|
+
postgres: ["pg"],
|
|
723
|
+
supabase: ["pg"],
|
|
724
|
+
neon: ["pg"],
|
|
725
|
+
cockroachdb: ["pg"],
|
|
726
|
+
mysql: ["mysql2"],
|
|
727
|
+
planetscale: ["mysql2"],
|
|
728
|
+
mongodb: ["mongodb"],
|
|
729
|
+
sqlite: ["better-sqlite3"],
|
|
730
|
+
turso: ["@libsql/client"],
|
|
731
|
+
dynamodb: ["@aws-sdk/client-dynamodb", "@aws-sdk/lib-dynamodb"]
|
|
732
|
+
};
|
|
733
|
+
async function ensureDbDriver(dbType, ora, chalk) {
|
|
734
|
+
const packages = DB_DRIVER_MAP[dbType];
|
|
735
|
+
if (!packages?.length) return;
|
|
736
|
+
const missing = [];
|
|
737
|
+
for (const pkg of packages) {
|
|
738
|
+
try {
|
|
739
|
+
await import(pkg);
|
|
740
|
+
} catch {
|
|
741
|
+
missing.push(pkg);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (!missing.length) return;
|
|
745
|
+
const spinner = ora(`Installing database driver: ${missing.join(", ")}...`).start();
|
|
746
|
+
try {
|
|
747
|
+
execSync(`npm install --no-save ${missing.join(" ")}`, {
|
|
748
|
+
stdio: "pipe",
|
|
749
|
+
timeout: 12e4
|
|
750
|
+
});
|
|
751
|
+
spinner.succeed(`Database driver installed: ${missing.join(", ")}`);
|
|
752
|
+
} catch (err) {
|
|
753
|
+
spinner.fail(`Failed to install ${missing.join(", ")}`);
|
|
754
|
+
console.error(chalk.red(`
|
|
755
|
+
Run manually: npm install ${missing.join(" ")}
|
|
756
|
+
`));
|
|
757
|
+
process.exit(1);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
718
760
|
async function runSetupWizard() {
|
|
719
761
|
const { default: inquirer } = await import("inquirer");
|
|
720
762
|
const { default: ora } = await import("ora");
|
|
@@ -737,6 +779,7 @@ async function runSetupWizard() {
|
|
|
737
779
|
company.companyName,
|
|
738
780
|
company.adminEmail
|
|
739
781
|
);
|
|
782
|
+
await ensureDbDriver(database.type, ora, chalk);
|
|
740
783
|
console.log("");
|
|
741
784
|
console.log(chalk.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
742
785
|
console.log("");
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VALID_CATEGORIES,
|
|
3
|
+
VALID_RISK_LEVELS,
|
|
4
|
+
validateSkillManifest
|
|
5
|
+
} from "./chunk-TY7NVD4U.js";
|
|
6
|
+
import "./chunk-KFQGP6VL.js";
|
|
7
|
+
|
|
8
|
+
// src/engine/cli-build-skill.ts
|
|
9
|
+
async function runBuildSkill(_args) {
|
|
10
|
+
const chalk = (await import("chalk")).default;
|
|
11
|
+
const ora = (await import("ora")).default;
|
|
12
|
+
const inquirer = (await import("inquirer")).default;
|
|
13
|
+
const fs = await import("fs/promises");
|
|
14
|
+
const path = await import("path");
|
|
15
|
+
console.log("");
|
|
16
|
+
console.log(chalk.bold("\u{1F6E0}\uFE0F AgenticMail Community Skill Builder"));
|
|
17
|
+
console.log(chalk.dim(" Generate a valid agenticmail-skill.json for any application"));
|
|
18
|
+
console.log("");
|
|
19
|
+
const answers = await inquirer.prompt([
|
|
20
|
+
{
|
|
21
|
+
type: "input",
|
|
22
|
+
name: "application",
|
|
23
|
+
message: "What application or service should this skill integrate with?",
|
|
24
|
+
validate: (v) => v.trim().length > 0 || "Application name is required"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: "input",
|
|
28
|
+
name: "operations",
|
|
29
|
+
message: "What operations should it support? (comma-separated)",
|
|
30
|
+
default: "read, create, update, delete, list"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: "list",
|
|
34
|
+
name: "category",
|
|
35
|
+
message: "Category:",
|
|
36
|
+
choices: [...VALID_CATEGORIES],
|
|
37
|
+
default: "productivity"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: "list",
|
|
41
|
+
name: "risk",
|
|
42
|
+
message: "Risk level:",
|
|
43
|
+
choices: [...VALID_RISK_LEVELS],
|
|
44
|
+
default: "medium"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
type: "input",
|
|
48
|
+
name: "author",
|
|
49
|
+
message: "Your GitHub username:",
|
|
50
|
+
validate: (v) => /^[a-zA-Z0-9_-]+$/.test(v.trim()) || "Must be a valid GitHub username"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: "input",
|
|
54
|
+
name: "outputDir",
|
|
55
|
+
message: "Output directory:",
|
|
56
|
+
default: (a) => `./community-skills/${a.application.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}`
|
|
57
|
+
}
|
|
58
|
+
]);
|
|
59
|
+
const appSlug = answers.application.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
60
|
+
const toolPrefix = appSlug.replace(/-/g, "_");
|
|
61
|
+
const operations = answers.operations.split(",").map((s) => s.trim()).filter(Boolean);
|
|
62
|
+
let manifest = null;
|
|
63
|
+
const spinner = ora("Generating skill manifest...").start();
|
|
64
|
+
try {
|
|
65
|
+
const res = await fetch("http://localhost:3000/health", { signal: AbortSignal.timeout(2e3) });
|
|
66
|
+
if (res.ok) {
|
|
67
|
+
spinner.text = "Agent runtime detected \u2014 using AI to generate manifest...";
|
|
68
|
+
const aiRes = await fetch("http://localhost:3000/api/chat", {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: { "Content-Type": "application/json" },
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
message: buildAIPrompt(answers.application, operations, answers.category, answers.risk, answers.author, appSlug, toolPrefix),
|
|
73
|
+
system: "You are a skill manifest generator. Respond with ONLY valid JSON, no markdown, no explanation."
|
|
74
|
+
}),
|
|
75
|
+
signal: AbortSignal.timeout(3e4)
|
|
76
|
+
});
|
|
77
|
+
if (aiRes.ok) {
|
|
78
|
+
const aiData = await aiRes.json();
|
|
79
|
+
const content = aiData.response || aiData.message || "";
|
|
80
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
81
|
+
if (jsonMatch) {
|
|
82
|
+
manifest = JSON.parse(jsonMatch[0]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
if (!manifest) {
|
|
89
|
+
spinner.text = "Generating from template...";
|
|
90
|
+
manifest = generateFromTemplate(answers.application, operations, answers.category, answers.risk, answers.author, appSlug, toolPrefix);
|
|
91
|
+
}
|
|
92
|
+
spinner.succeed("Manifest generated");
|
|
93
|
+
const validation = validateSkillManifest(manifest);
|
|
94
|
+
if (!validation.valid) {
|
|
95
|
+
console.log(chalk.yellow("\n Validation warnings (auto-fixing)..."));
|
|
96
|
+
if (!manifest.category) manifest.category = answers.category;
|
|
97
|
+
if (!manifest.risk) manifest.risk = answers.risk;
|
|
98
|
+
if (!manifest.license) manifest.license = "MIT";
|
|
99
|
+
if (!manifest.description || manifest.description.length < 20) {
|
|
100
|
+
manifest.description = `Integrates with ${answers.application} to ${operations.slice(0, 3).join(", ")} and more.`;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const outDir = path.resolve(answers.outputDir);
|
|
104
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
105
|
+
const manifestPath = path.join(outDir, "agenticmail-skill.json");
|
|
106
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
107
|
+
console.log(chalk.green(" \u2714") + ` Written: ${manifestPath}`);
|
|
108
|
+
const readmePath = path.join(outDir, "README.md");
|
|
109
|
+
await fs.writeFile(readmePath, generateReadme(manifest));
|
|
110
|
+
console.log(chalk.green(" \u2714") + ` Written: ${readmePath}`);
|
|
111
|
+
const finalCheck = validateSkillManifest(manifest);
|
|
112
|
+
if (finalCheck.valid) {
|
|
113
|
+
console.log(chalk.green("\n \u2714 Manifest is valid!"));
|
|
114
|
+
} else {
|
|
115
|
+
console.log(chalk.yellow("\n \u26A0 Manifest has issues:"));
|
|
116
|
+
for (const err of finalCheck.errors) console.log(chalk.red(" " + err));
|
|
117
|
+
}
|
|
118
|
+
for (const warn of finalCheck.warnings) console.log(chalk.yellow(" \u26A0 " + warn));
|
|
119
|
+
console.log("");
|
|
120
|
+
const { submit } = await inquirer.prompt([{
|
|
121
|
+
type: "confirm",
|
|
122
|
+
name: "submit",
|
|
123
|
+
message: "Submit this skill as a PR to agenticmail/enterprise?",
|
|
124
|
+
default: false
|
|
125
|
+
}]);
|
|
126
|
+
if (submit) {
|
|
127
|
+
const { runSubmitSkill } = await import("./cli-submit-skill-LDFJGSKO.js");
|
|
128
|
+
await runSubmitSkill([outDir]);
|
|
129
|
+
} else {
|
|
130
|
+
console.log(chalk.dim("\n To submit later: npx @agenticmail/enterprise submit-skill " + answers.outputDir));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function generateFromTemplate(app, operations, category, risk, author, slug, prefix) {
|
|
134
|
+
const tools = operations.map((op) => {
|
|
135
|
+
const opSlug = op.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
136
|
+
const isRead = ["read", "get", "list", "search", "fetch", "view", "query"].some((r) => opSlug.includes(r));
|
|
137
|
+
const isDelete = ["delete", "remove", "destroy"].some((r) => opSlug.includes(r));
|
|
138
|
+
const toolCategory = isDelete ? "destroy" : isRead ? "read" : "write";
|
|
139
|
+
const toolRisk = isDelete ? "high" : isRead ? "low" : "medium";
|
|
140
|
+
const sideEffects = [];
|
|
141
|
+
if (!isRead) sideEffects.push("network-request");
|
|
142
|
+
if (isDelete) sideEffects.push("deletes-data");
|
|
143
|
+
return {
|
|
144
|
+
id: `${prefix}_${opSlug}`,
|
|
145
|
+
name: op.charAt(0).toUpperCase() + op.slice(1),
|
|
146
|
+
description: `${op.charAt(0).toUpperCase() + op.slice(1)} in ${app}`,
|
|
147
|
+
category: toolCategory,
|
|
148
|
+
riskLevel: toolRisk,
|
|
149
|
+
sideEffects,
|
|
150
|
+
parameters: {}
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
id: slug,
|
|
155
|
+
name: app,
|
|
156
|
+
description: `Integrates with ${app} to ${operations.slice(0, 3).join(", ")}${operations.length > 3 ? " and more" : ""}. Community-contributed skill for AgenticMail agents.`,
|
|
157
|
+
version: "1.0.0",
|
|
158
|
+
author,
|
|
159
|
+
repository: `https://github.com/${author}/${slug}`,
|
|
160
|
+
license: "MIT",
|
|
161
|
+
category,
|
|
162
|
+
risk,
|
|
163
|
+
tags: [slug, category],
|
|
164
|
+
tools,
|
|
165
|
+
configSchema: {
|
|
166
|
+
apiKey: { type: "secret", label: "API Key", description: `Your ${app} API key`, required: true }
|
|
167
|
+
},
|
|
168
|
+
minEngineVersion: "0.3.0",
|
|
169
|
+
homepage: `https://github.com/${author}/${slug}`
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function buildAIPrompt(app, operations, category, risk, author, slug, prefix) {
|
|
173
|
+
return `Generate a valid agenticmail-skill.json manifest for "${app}".
|
|
174
|
+
|
|
175
|
+
Requirements:
|
|
176
|
+
- id: "${slug}"
|
|
177
|
+
- name: "${app}"
|
|
178
|
+
- Operations: ${operations.join(", ")}
|
|
179
|
+
- category: "${category}"
|
|
180
|
+
- risk: "${risk}"
|
|
181
|
+
- author: "${author}"
|
|
182
|
+
- repository: "https://github.com/${author}/${slug}"
|
|
183
|
+
- license: "MIT"
|
|
184
|
+
- Each tool needs: id (${prefix}_<action>), name, description, category (read/write/execute/communicate/destroy), riskLevel (low/medium/high/critical), sideEffects array
|
|
185
|
+
- Valid sideEffects: sends-email, sends-message, sends-sms, posts-social, runs-code, modifies-files, deletes-data, network-request, controls-device, accesses-secrets, financial
|
|
186
|
+
- Include a configSchema with any API keys or settings needed
|
|
187
|
+
- version: "1.0.0"
|
|
188
|
+
- minEngineVersion: "0.3.0"
|
|
189
|
+
- description must be 20-500 chars
|
|
190
|
+
|
|
191
|
+
Output ONLY the JSON object, no explanation.`;
|
|
192
|
+
}
|
|
193
|
+
function generateReadme(manifest) {
|
|
194
|
+
const tools = (manifest.tools || []).map(
|
|
195
|
+
(t) => `| \`${t.id}\` | ${t.name} | ${t.description} | ${t.riskLevel || "medium"} |`
|
|
196
|
+
).join("\n");
|
|
197
|
+
return `# ${manifest.name}
|
|
198
|
+
|
|
199
|
+
${manifest.description}
|
|
200
|
+
|
|
201
|
+
## Tools
|
|
202
|
+
|
|
203
|
+
| ID | Name | Description | Risk |
|
|
204
|
+
|----|------|-------------|------|
|
|
205
|
+
${tools}
|
|
206
|
+
|
|
207
|
+
## Configuration
|
|
208
|
+
|
|
209
|
+
${manifest.configSchema ? Object.entries(manifest.configSchema).map(
|
|
210
|
+
([k, v]) => `- **${k}** (${v.type || "string"}): ${v.description || k}${v.required ? " *(required)*" : ""}`
|
|
211
|
+
).join("\n") : "No configuration required."}
|
|
212
|
+
|
|
213
|
+
## Installation
|
|
214
|
+
|
|
215
|
+
Install this skill from the AgenticMail Enterprise dashboard:
|
|
216
|
+
|
|
217
|
+
1. Go to **Community Skills** in the sidebar
|
|
218
|
+
2. Search for "${manifest.name}"
|
|
219
|
+
3. Click **Install**
|
|
220
|
+
|
|
221
|
+
Or via the API:
|
|
222
|
+
\`\`\`bash
|
|
223
|
+
curl -X POST /api/engine/community/skills/${manifest.id}/install \\
|
|
224
|
+
-H "Content-Type: application/json" \\
|
|
225
|
+
-d '{"orgId": "your-org-id"}'
|
|
226
|
+
\`\`\`
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
${manifest.license || "MIT"}
|
|
231
|
+
`;
|
|
232
|
+
}
|
|
233
|
+
export {
|
|
234
|
+
runBuildSkill
|
|
235
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DomainLock
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UPU23ZRG.js";
|
|
4
4
|
import "./chunk-KFQGP6VL.js";
|
|
5
5
|
|
|
6
6
|
// src/domain-lock/cli-recover.ts
|
|
@@ -89,7 +89,7 @@ async function runRecover(args) {
|
|
|
89
89
|
console.log(` ${chalk.bold("Type:")} ${chalk.cyan("TXT")}`);
|
|
90
90
|
console.log(` ${chalk.bold("Value:")} ${chalk.cyan(result.dnsChallenge)}`);
|
|
91
91
|
console.log("");
|
|
92
|
-
console.log(chalk.dim(" Then run: agenticmail
|
|
92
|
+
console.log(chalk.dim(" Then run: npx @agenticmail/enterprise verify-domain"));
|
|
93
93
|
console.log("");
|
|
94
94
|
}
|
|
95
95
|
export {
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validateSkillManifest
|
|
3
|
+
} from "./chunk-TY7NVD4U.js";
|
|
4
|
+
import "./chunk-KFQGP6VL.js";
|
|
5
|
+
|
|
6
|
+
// src/engine/cli-submit-skill.ts
|
|
7
|
+
var UPSTREAM_REPO = "agenticmail/enterprise";
|
|
8
|
+
async function runSubmitSkill(args) {
|
|
9
|
+
const chalk = (await import("chalk")).default;
|
|
10
|
+
const ora = (await import("ora")).default;
|
|
11
|
+
const { execSync } = await import("child_process");
|
|
12
|
+
const fs = await import("fs/promises");
|
|
13
|
+
const path = await import("path");
|
|
14
|
+
const target = args.filter((a) => !a.startsWith("--"))[0];
|
|
15
|
+
if (!target) {
|
|
16
|
+
console.log(`${chalk.bold("Usage:")} npx @agenticmail/enterprise submit-skill <path-to-skill-dir>`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const skillDir = path.resolve(target);
|
|
21
|
+
console.log("");
|
|
22
|
+
console.log(chalk.bold("\u{1F680} Submit Community Skill"));
|
|
23
|
+
console.log("");
|
|
24
|
+
const spinner = ora("Checking prerequisites...").start();
|
|
25
|
+
try {
|
|
26
|
+
execSync("gh --version", { stdio: "pipe" });
|
|
27
|
+
} catch {
|
|
28
|
+
spinner.fail("GitHub CLI (gh) is not installed");
|
|
29
|
+
console.log("");
|
|
30
|
+
console.log(chalk.dim(" Install it from: https://cli.github.com/"));
|
|
31
|
+
console.log(chalk.dim(" Then run: gh auth login"));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
execSync("gh auth status", { stdio: "pipe" });
|
|
37
|
+
} catch {
|
|
38
|
+
spinner.fail("Not authenticated with GitHub CLI");
|
|
39
|
+
console.log(chalk.dim(" Run: gh auth login"));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
spinner.succeed("GitHub CLI authenticated");
|
|
44
|
+
const validateSpinner = ora("Validating skill manifest...").start();
|
|
45
|
+
const manifestPath = path.join(skillDir, "agenticmail-skill.json");
|
|
46
|
+
let manifest;
|
|
47
|
+
try {
|
|
48
|
+
const raw = await fs.readFile(manifestPath, "utf-8");
|
|
49
|
+
manifest = JSON.parse(raw);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
validateSpinner.fail(`Cannot read manifest: ${err.message}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const validation = validateSkillManifest(manifest);
|
|
56
|
+
if (!validation.valid) {
|
|
57
|
+
validateSpinner.fail("Manifest validation failed");
|
|
58
|
+
for (const err of validation.errors) {
|
|
59
|
+
console.log(chalk.red(" \u2502 " + err));
|
|
60
|
+
}
|
|
61
|
+
console.log(chalk.dim("\n Fix the errors above and try again."));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
validateSpinner.succeed(`Manifest valid: ${manifest.name} v${manifest.version}`);
|
|
66
|
+
const skillId = manifest.id;
|
|
67
|
+
const branchName = `community/add-${skillId}`;
|
|
68
|
+
const forkSpinner = ora("Forking repository...").start();
|
|
69
|
+
try {
|
|
70
|
+
execSync(`gh repo fork ${UPSTREAM_REPO} --clone=false 2>&1 || true`, { stdio: "pipe" });
|
|
71
|
+
forkSpinner.succeed("Repository forked (or already exists)");
|
|
72
|
+
} catch {
|
|
73
|
+
forkSpinner.succeed("Fork exists");
|
|
74
|
+
}
|
|
75
|
+
let forkUrl;
|
|
76
|
+
try {
|
|
77
|
+
const ghUser = execSync("gh api user --jq .login", { encoding: "utf-8" }).trim();
|
|
78
|
+
forkUrl = `https://github.com/${ghUser}/enterprise.git`;
|
|
79
|
+
} catch {
|
|
80
|
+
forkSpinner.fail("Cannot determine GitHub username");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const tmpDir = path.join(process.env.TMPDIR || "/tmp", `agenticmail-submit-${Date.now()}`);
|
|
85
|
+
const pushSpinner = ora("Cloning fork...").start();
|
|
86
|
+
try {
|
|
87
|
+
execSync(`git clone --depth 1 ${forkUrl} "${tmpDir}"`, { stdio: "pipe" });
|
|
88
|
+
pushSpinner.text = "Creating branch...";
|
|
89
|
+
const run = (cmd) => execSync(cmd, { cwd: tmpDir, stdio: "pipe", encoding: "utf-8" });
|
|
90
|
+
run(`git remote add upstream https://github.com/${UPSTREAM_REPO}.git`);
|
|
91
|
+
run("git fetch upstream main --depth 1");
|
|
92
|
+
run(`git checkout -b ${branchName} upstream/main`);
|
|
93
|
+
pushSpinner.text = "Copying skill files...";
|
|
94
|
+
const destDir = path.join(tmpDir, "community-skills", skillId);
|
|
95
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
96
|
+
const files = await fs.readdir(skillDir);
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
await fs.copyFile(path.join(skillDir, file), path.join(destDir, file));
|
|
99
|
+
}
|
|
100
|
+
pushSpinner.text = "Committing...";
|
|
101
|
+
run(`git add community-skills/${skillId}/`);
|
|
102
|
+
run(`git commit -m "Add community skill: ${manifest.name}"`);
|
|
103
|
+
pushSpinner.text = "Pushing to fork...";
|
|
104
|
+
run(`git push origin ${branchName} --force`);
|
|
105
|
+
pushSpinner.succeed("Pushed to fork");
|
|
106
|
+
} catch (err) {
|
|
107
|
+
pushSpinner.fail(`Git operation failed: ${err.message}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const prSpinner = ora("Opening pull request...").start();
|
|
112
|
+
const toolsList = (manifest.tools || []).map(
|
|
113
|
+
(t) => `- \`${t.id}\` \u2014 ${t.name}: ${t.description}`
|
|
114
|
+
).join("\n");
|
|
115
|
+
const prBody = `## Community Skill Submission
|
|
116
|
+
|
|
117
|
+
**Skill ID:** \`${manifest.id}\`
|
|
118
|
+
**Application:** ${manifest.name}
|
|
119
|
+
**Category:** ${manifest.category}
|
|
120
|
+
**Risk Level:** ${manifest.risk}
|
|
121
|
+
**Author:** @${manifest.author}
|
|
122
|
+
**License:** ${manifest.license}
|
|
123
|
+
|
|
124
|
+
### Description
|
|
125
|
+
|
|
126
|
+
${manifest.description}
|
|
127
|
+
|
|
128
|
+
### Tools Provided
|
|
129
|
+
|
|
130
|
+
${toolsList}
|
|
131
|
+
|
|
132
|
+
### Validation
|
|
133
|
+
|
|
134
|
+
- [x] Manifest passes \`npx @agenticmail/enterprise validate\`
|
|
135
|
+
- [x] All required fields present
|
|
136
|
+
- [x] No duplicate tool IDs
|
|
137
|
+
${manifest.tags ? `
|
|
138
|
+
**Tags:** ${manifest.tags.join(", ")}` : ""}`;
|
|
139
|
+
try {
|
|
140
|
+
const prUrl = execSync(
|
|
141
|
+
`gh pr create --repo ${UPSTREAM_REPO} --head ${branchName} --title "Add community skill: ${manifest.name}" --body "${prBody.replace(/"/g, '\\"')}"`,
|
|
142
|
+
{ cwd: tmpDir, encoding: "utf-8", stdio: "pipe" }
|
|
143
|
+
).trim();
|
|
144
|
+
prSpinner.succeed("Pull request opened!");
|
|
145
|
+
console.log(chalk.green(`
|
|
146
|
+
${prUrl}
|
|
147
|
+
`));
|
|
148
|
+
} catch (err) {
|
|
149
|
+
if (err.stderr?.includes("already exists")) {
|
|
150
|
+
prSpinner.warn("A PR for this skill already exists");
|
|
151
|
+
} else {
|
|
152
|
+
prSpinner.fail(`Could not open PR: ${err.message}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
157
|
+
} catch {
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
runSubmitSkill
|
|
162
|
+
};
|