@theholocron/cli 5.0.0-alpha.197 → 5.0.0-alpha.199
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/cli.mjs +65 -21
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/plugin/capabilities.d.mts +54 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -2960,11 +2960,6 @@ async function runNotificationsChannelAdd(input) {
|
|
|
2960
2960
|
*/
|
|
2961
2961
|
/** Features not built yet, in the order of the table in holocron#1098. Move an entry into a real check when it lands. */
|
|
2962
2962
|
const PLANNED_CHECKS = [
|
|
2963
|
-
{
|
|
2964
|
-
step: 13,
|
|
2965
|
-
id: "app-settings",
|
|
2966
|
-
title: "bot description, tags, install link and URLs set"
|
|
2967
|
-
},
|
|
2968
2963
|
{
|
|
2969
2964
|
step: 14,
|
|
2970
2965
|
id: "role-assignment",
|
|
@@ -2999,6 +2994,7 @@ const promptKey = (p) => JSON.stringify([
|
|
|
2999
2994
|
const accessText = (v) => v === "everyone" ? "everyone" : v.length === 0 ? "nobody (bots and webhooks only)" : v.join(", ");
|
|
3000
2995
|
const shown = (s) => sanitizeDetail(s);
|
|
3001
2996
|
const WELCOME_TITLE = "welcome screen and onboarding set";
|
|
2997
|
+
const APP_TITLE = "bot description, tags, install link and URLs set";
|
|
3002
2998
|
const AVATAR_TITLE = "webhook names and avatars set";
|
|
3003
2999
|
const SERVER_TITLE = "server verification, notifications and community set";
|
|
3004
3000
|
const ACCESS_TITLE = "channel and category access set";
|
|
@@ -3118,12 +3114,13 @@ async function runDoctorNotifications(input) {
|
|
|
3118
3114
|
["categories", "categories exist"],
|
|
3119
3115
|
["channels", "channels in their category, with topics"],
|
|
3120
3116
|
["webhooks", "webhooks on their channels"],
|
|
3117
|
+
["webhook-appearance", AVATAR_TITLE],
|
|
3121
3118
|
["roles", "roles exist and are mentionable"],
|
|
3122
3119
|
["role-appearance", ROLE_APPEARANCE_TITLE],
|
|
3123
3120
|
["access", ACCESS_TITLE],
|
|
3124
3121
|
["server-settings", SERVER_TITLE],
|
|
3125
3122
|
["welcome-onboarding", WELCOME_TITLE],
|
|
3126
|
-
["
|
|
3123
|
+
["app-settings", APP_TITLE]
|
|
3127
3124
|
]) failed(id, title, "not checked: could not read the server");
|
|
3128
3125
|
} else {
|
|
3129
3126
|
const inspected = found;
|
|
@@ -3154,6 +3151,17 @@ async function runDoctorNotifications(input) {
|
|
|
3154
3151
|
else if (!match.webhooks.some((w) => same(w, name))) webhookProblems.push(`#${shown(channel.name)}: no webhook named ${shown(name)}`);
|
|
3155
3152
|
}
|
|
3156
3153
|
add("webhooks", "webhooks on their channels", webhookProblems, withWebhook.length === 0 ? "none declared" : `${withWebhook.length} of ${withWebhook.length} exist`);
|
|
3154
|
+
const avatarOf = (webhook) => (typeof webhook === "object" && webhook ? webhook.avatar : void 0) ?? layout.webhookAvatar;
|
|
3155
|
+
const wantAvatar = declaredChannels.filter(({ channel }) => channel.webhook && avatarOf(channel.webhook));
|
|
3156
|
+
const avatarProblems = [];
|
|
3157
|
+
for (const { cat, channel } of wantAvatar) {
|
|
3158
|
+
const name = (channel.webhook === true ? {} : channel.webhook).name ?? channel.name;
|
|
3159
|
+
const { match } = pick(channel.name, cat);
|
|
3160
|
+
if (!match) avatarProblems.push(`#${shown(channel.name)}: no channel to hold the webhook`);
|
|
3161
|
+
else if (match.webhooksError) avatarProblems.push(`#${shown(channel.name)}: could not list its webhooks (${shown(match.webhooksError)})`);
|
|
3162
|
+
else if (match.webhookAvatars && !match.webhookAvatars.some((w) => same(w, name))) avatarProblems.push(`#${shown(channel.name)}: webhook ${shown(name)} has no avatar`);
|
|
3163
|
+
}
|
|
3164
|
+
add("webhook-appearance", AVATAR_TITLE, avatarProblems, wantAvatar.length === 0 ? "none declared" : `${wantAvatar.length} of ${wantAvatar.length} set`);
|
|
3157
3165
|
const roles = layout.roles ?? [];
|
|
3158
3166
|
const roleProblems = [];
|
|
3159
3167
|
if (inspected.rolesError) roleProblems.push(`could not read the roles (${shown(inspected.rolesError)})`);
|
|
@@ -3187,8 +3195,21 @@ async function runDoctorNotifications(input) {
|
|
|
3187
3195
|
}
|
|
3188
3196
|
}
|
|
3189
3197
|
}
|
|
3190
|
-
const
|
|
3191
|
-
|
|
3198
|
+
const everyone = layout.everyone;
|
|
3199
|
+
const everyoneProblems = [];
|
|
3200
|
+
if (everyone) {
|
|
3201
|
+
if (inspected.everyoneError) everyoneProblems.push(`@everyone: not checked, could not read its permissions (${shown(inspected.everyoneError)})`);
|
|
3202
|
+
else if (!inspected.everyone) everyoneProblems.push("@everyone: the provider did not report its permissions");
|
|
3203
|
+
else {
|
|
3204
|
+
const have = new Set(inspected.everyone.permissions.map((n) => n.toLowerCase()));
|
|
3205
|
+
const lacking = (everyone.allow ?? []).filter((n) => !have.has(n.toLowerCase()));
|
|
3206
|
+
const keeping = (everyone.deny ?? []).filter((n) => have.has(n.toLowerCase()));
|
|
3207
|
+
if (lacking.length > 0) everyoneProblems.push(`@everyone: missing permissions ${lacking.map(shown).join(", ")}`);
|
|
3208
|
+
if (keeping.length > 0) everyoneProblems.push(`@everyone: still has permissions the layout takes away: ${keeping.map(shown).join(", ")}`);
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
const styledCount = roles.filter((r) => r.color !== void 0 || r.hoist !== void 0 || r.permissions !== void 0).length + (everyone ? 1 : 0);
|
|
3212
|
+
add("role-appearance", ROLE_APPEARANCE_TITLE, inspected.rolesError ? [`not checked: could not read the roles`, ...everyoneProblems] : [...appearance, ...everyoneProblems], styledCount === 0 ? "none declared" : `${styledCount} of ${styledCount} as declared`);
|
|
3192
3213
|
const accessProblems = [];
|
|
3193
3214
|
const compare = (label, want, have) => {
|
|
3194
3215
|
if (!have) {
|
|
@@ -3305,19 +3326,35 @@ async function runDoctorNotifications(input) {
|
|
|
3305
3326
|
}
|
|
3306
3327
|
const welcomeParts = (wantWelcome ? 1 : 0) + (wantOnboarding ? 1 : 0);
|
|
3307
3328
|
add("welcome-onboarding", WELCOME_TITLE, [...welcomeProblems, ...onboardingProblems], welcomeParts === 0 ? "none declared" : `${welcomeParts} of ${welcomeParts} as declared`);
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3329
|
+
const wantApp = layout.application;
|
|
3330
|
+
const appProblems = [];
|
|
3331
|
+
if (wantApp) {
|
|
3332
|
+
if (inspected.applicationError) appProblems.push(`not checked: could not read the application (${shown(inspected.applicationError)})`);
|
|
3333
|
+
else if (!inspected.application) appProblems.push("the provider did not report the application");
|
|
3334
|
+
else {
|
|
3335
|
+
const have = inspected.application;
|
|
3336
|
+
const set = (list) => JSON.stringify([...new Set(list.map((n) => n.toLowerCase()))].sort());
|
|
3337
|
+
const exact = (list) => JSON.stringify([...new Set(list)].sort());
|
|
3338
|
+
if (wantApp.description !== void 0 && (have.description ?? "") !== wantApp.description) appProblems.push("description differs from the layout");
|
|
3339
|
+
if (wantApp.tags !== void 0 && set(have.tags ?? []) !== set(wantApp.tags)) appProblems.push(`tags are ${(have.tags ?? []).map(shown).join(", ") || "none"} but the layout says ${wantApp.tags.map(shown).join(", ") || "none"}`);
|
|
3340
|
+
if (wantApp.install !== void 0) {
|
|
3341
|
+
if (!have.install) appProblems.push("no install link is set");
|
|
3342
|
+
else {
|
|
3343
|
+
if (exact(have.install.scopes) !== exact(wantApp.install.scopes)) appProblems.push(`install scopes are ${have.install.scopes.map(shown).join(", ")} but the layout says ${wantApp.install.scopes.map(shown).join(", ")}`);
|
|
3344
|
+
if (set(have.install.permissions) !== set(wantApp.install.permissions)) appProblems.push("install permissions differ from the layout");
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
for (const [field, label] of [
|
|
3348
|
+
["termsUrl", "terms URL"],
|
|
3349
|
+
["privacyUrl", "privacy URL"],
|
|
3350
|
+
["roleConnectionsUrl", "role-connections URL"]
|
|
3351
|
+
]) {
|
|
3352
|
+
const wanted = wantApp[field];
|
|
3353
|
+
if (wanted !== void 0 && (have[field] ?? "") !== wanted) appProblems.push(`${label} is ${shown(have[field] || "not set")} but the layout says ${shown(wanted)}`);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3319
3356
|
}
|
|
3320
|
-
add("
|
|
3357
|
+
add("app-settings", APP_TITLE, appProblems, wantApp ? "1 of 1 as declared" : "none declared");
|
|
3321
3358
|
}
|
|
3322
3359
|
const wanted = [...declaredChannels.filter(({ channel }) => channel.webhook).map(({ channel }) => channel.webhook !== true && channel.webhook && channel.webhook.secret ? channel.webhook.secret : defaultSecretName(channel.name)), ...(layout.roles ?? []).flatMap((r) => r.secret ? [r.secret] : [])];
|
|
3323
3360
|
if (wanted.length === 0) checks.push({
|
|
@@ -4034,6 +4071,9 @@ function serverLayoutProblem(layout) {
|
|
|
4034
4071
|
if (count === 0) return `${where} names the channel \`${name}\`, which is not in the layout's channels`;
|
|
4035
4072
|
if (count > 1) return `${where} names \`${name}\`, but more than one channel in the layout has that name`;
|
|
4036
4073
|
};
|
|
4074
|
+
const everyone = layout.everyone;
|
|
4075
|
+
const both = (everyone?.allow ?? []).find((p) => (everyone?.deny ?? []).some((d) => d.toLowerCase() === p.toLowerCase()));
|
|
4076
|
+
if (both !== void 0) return `everyone: \`${both}\` is in both \`allow\` and \`deny\``;
|
|
4037
4077
|
const server = layout.server;
|
|
4038
4078
|
if (server) {
|
|
4039
4079
|
for (const field of [
|
|
@@ -4135,6 +4175,8 @@ async function runNotificationsSetup(input) {
|
|
|
4135
4175
|
if (layout.server && !notifications.ensureServer) return refuse(`the layout declares \`server\` settings, but the \`${notifications.providerName}\` provider cannot manage them`);
|
|
4136
4176
|
if (layout.welcome && !notifications.ensureWelcome) return refuse(`the layout declares a \`welcome\` screen, but the \`${notifications.providerName}\` provider cannot manage one`);
|
|
4137
4177
|
if (layout.onboarding && !notifications.ensureOnboarding) return refuse(`the layout declares \`onboarding\`, but the \`${notifications.providerName}\` provider cannot manage it`);
|
|
4178
|
+
if (layout.application && !notifications.ensureApplication) return refuse(`the layout declares \`application\` settings, but the \`${notifications.providerName}\` provider cannot manage them`);
|
|
4179
|
+
if (layout.everyone && !notifications.ensureEveryone) return refuse(`the layout declares \`everyone\` permissions, but the \`${notifications.providerName}\` provider cannot manage them`);
|
|
4138
4180
|
const needsCategories = (layout.categories ?? []).find((c) => c.access);
|
|
4139
4181
|
if (needsCategories && !notifications.ensureCategory) return refuse(`category \`${needsCategories.name}\` declares \`access\`, but the \`${notifications.providerName}\` provider cannot manage categories`);
|
|
4140
4182
|
const providerProblem = notifications.validateLayout?.(layout);
|
|
@@ -4252,7 +4294,7 @@ async function runNotificationsSetup(input) {
|
|
|
4252
4294
|
});
|
|
4253
4295
|
});
|
|
4254
4296
|
}
|
|
4255
|
-
if (layout.server || layout.welcome || layout.onboarding) {
|
|
4297
|
+
if (layout.server || layout.welcome || layout.onboarding || layout.application || layout.everyone) {
|
|
4256
4298
|
print(`\n${style.header("Server")}`);
|
|
4257
4299
|
const apply = async (label, declared, run) => {
|
|
4258
4300
|
if (!declared) return;
|
|
@@ -4268,9 +4310,11 @@ async function runNotificationsSetup(input) {
|
|
|
4268
4310
|
made(changed);
|
|
4269
4311
|
});
|
|
4270
4312
|
};
|
|
4313
|
+
await apply("@everyone permissions", !!layout.everyone, () => notifications.ensureEveryone(layout.everyone));
|
|
4271
4314
|
await apply("server settings", !!layout.server, () => notifications.ensureServer(layout.server));
|
|
4272
4315
|
await apply("welcome screen", !!layout.welcome, () => notifications.ensureWelcome(layout.welcome));
|
|
4273
4316
|
await apply("onboarding", !!layout.onboarding, () => notifications.ensureOnboarding(layout.onboarding));
|
|
4317
|
+
await apply("bot application", !!layout.application, () => notifications.ensureApplication(layout.application));
|
|
4274
4318
|
}
|
|
4275
4319
|
if (report.failures.length > 0) report.status = "fail";
|
|
4276
4320
|
else if (dryRun) report.status = "dry-run";
|