@frockbot/plugin-settings 0.0.0 → 0.1.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.
Files changed (36) hide show
  1. package/frockbot.json +55 -0
  2. package/package.json +43 -6
  3. package/src/backend.test.ts +397 -0
  4. package/src/backend.ts +262 -0
  5. package/src/client/BotPanel.vue +57 -0
  6. package/src/client/BotSettingsSurface.vue +1076 -0
  7. package/src/client/BotSettingsTrigger.vue +26 -0
  8. package/src/client/ConnectionsSurface.vue +813 -0
  9. package/src/client/ModelsSurface.vue +419 -0
  10. package/src/client/PackageAccounts.vue +330 -0
  11. package/src/client/PackageCatalogSurface.vue +584 -0
  12. package/src/client/PackageSettingsForm.vue +150 -0
  13. package/src/client/PackageSettingsSection.vue +66 -0
  14. package/src/client/PluginsSurface.vue +412 -0
  15. package/src/client/PluginsTrigger.vue +62 -0
  16. package/src/client/UserProfileTrigger.vue +223 -0
  17. package/src/client/UserSettingsSurface.vue +242 -0
  18. package/src/client/assignment-operations.ts +22 -0
  19. package/src/client/bot-settings.test.ts +218 -0
  20. package/src/client/bot-settings.ts +150 -0
  21. package/src/client/index.test.ts +113 -0
  22. package/src/client/index.ts +78 -0
  23. package/src/client/package-settings.test.ts +63 -0
  24. package/src/client/package-settings.ts +77 -0
  25. package/src/client/package-surfaces.test.ts +147 -0
  26. package/src/client/package-surfaces.ts +93 -0
  27. package/src/client/user-display-name.test.ts +44 -0
  28. package/src/client/user-display-name.ts +16 -0
  29. package/src/env.d.ts +6 -0
  30. package/src/index.ts +1 -0
  31. package/src/manifest.ts +3 -0
  32. package/src/user.test.ts +1277 -0
  33. package/src/user.ts +1221 -0
  34. package/tsconfig.json +15 -0
  35. package/vite.config.ts +30 -0
  36. package/README.md +0 -3
@@ -0,0 +1,93 @@
1
+ import type { PackageInstallationView } from "@frockbot/configuration-core";
2
+ import type { PluginCatalogItem } from "@frockbot/plugin-shell/shared";
3
+
4
+ /**
5
+ * Where a Package's configuration lives.
6
+ *
7
+ * Enablement and configuration are separate surfaces: Plugins turns a Package
8
+ * on and off, and whatever the Package declares — provider accounts, external
9
+ * accounts, plain settings — is edited on the surface that owns what it
10
+ * configures. This function is the whole routing table, so a Package that adds
11
+ * a Connection Type or a setting lands somewhere without an edit to a surface.
12
+ */
13
+ export type PackageConfigurationHome =
14
+ "models" | "connections" | "user-settings" | "none";
15
+
16
+ /** A Package that provides a model, whose accounts and catalogs are Models'. */
17
+ export function isModelProviderPackage(item: PluginCatalogItem): boolean {
18
+ return item.capabilities.some((capability) => capability.kind === "model");
19
+ }
20
+
21
+ /** A Package a User authorizes an external account against. */
22
+ export function declaresConnections(item: PluginCatalogItem): boolean {
23
+ return item.connectionTypes.length > 0;
24
+ }
25
+
26
+ export function packageConfigurationHome(
27
+ item: PluginCatalogItem,
28
+ ): PackageConfigurationHome {
29
+ if (isModelProviderPackage(item)) return "models";
30
+ if (declaresConnections(item)) return "connections";
31
+ if ((item.settings ?? []).length > 0) return "user-settings";
32
+ return "none";
33
+ }
34
+
35
+ /** The catalog entries one configuration surface is responsible for. */
36
+ export function packagesForHome(
37
+ catalog: readonly PluginCatalogItem[],
38
+ home: PackageConfigurationHome,
39
+ ): PluginCatalogItem[] {
40
+ return catalog.filter((item) => packageConfigurationHome(item) === home);
41
+ }
42
+
43
+ /**
44
+ * The installation row of one Package, whatever state it is in. Absent means
45
+ * the Package is available to this deployment but not installed for the User.
46
+ */
47
+ export function packageInstallation(
48
+ packages: readonly PackageInstallationView[],
49
+ packageId: string,
50
+ ): PackageInstallationView | undefined {
51
+ return packages.find((candidate) => candidate.packageId === packageId);
52
+ }
53
+
54
+ /** Installed and not disabled: the only state in which a Bot may be given it. */
55
+ export function isPackageEnabled(
56
+ packages: readonly PackageInstallationView[],
57
+ packageId: string,
58
+ ): boolean {
59
+ return packageInstallation(packages, packageId)?.state === "installed";
60
+ }
61
+
62
+ /** Installed at all, in any state — including `disabled` and `failed`. */
63
+ export function isPackageInstalled(
64
+ packages: readonly PackageInstallationView[],
65
+ packageId: string,
66
+ ): boolean {
67
+ return packageInstallation(packages, packageId) !== undefined;
68
+ }
69
+
70
+ /**
71
+ * What a configuration surface shows: the Packages it owns that the User has
72
+ * installed and enabled. A disabled Package configures nothing — its knobs are
73
+ * kept, and reappear when it is enabled again in Plugins.
74
+ */
75
+ export function configurablePackages(input: {
76
+ catalog: readonly PluginCatalogItem[];
77
+ packages: readonly PackageInstallationView[];
78
+ home: PackageConfigurationHome;
79
+ }): PluginCatalogItem[] {
80
+ return packagesForHome(input.catalog, input.home).filter((item) =>
81
+ isPackageEnabled(input.packages, item.packageId),
82
+ );
83
+ }
84
+
85
+ /** The surface name a Plugins row points at, or nothing to configure. */
86
+ export function configurationHomeLabel(
87
+ home: PackageConfigurationHome,
88
+ ): string | undefined {
89
+ if (home === "models") return "Models";
90
+ if (home === "connections") return "Connections";
91
+ if (home === "user-settings") return "Application settings";
92
+ return undefined;
93
+ }
@@ -0,0 +1,44 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { resolveUserDisplayName } from "./user-display-name.js";
3
+
4
+ describe("resolveUserDisplayName", () => {
5
+ test("prefers a saved name over the authenticated session", () => {
6
+ expect(
7
+ resolveUserDisplayName({
8
+ savedName: "Tim",
9
+ sessionName: "Local developer",
10
+ sessionEmail: "developer@example.com",
11
+ }),
12
+ ).toBe("Tim");
13
+ });
14
+
15
+ test("uses the session name when the saved name is the placeholder", () => {
16
+ expect(
17
+ resolveUserDisplayName({
18
+ savedName: "FrockBot user",
19
+ sessionName: "Local developer",
20
+ sessionEmail: "developer@example.com",
21
+ }),
22
+ ).toBe("Local developer");
23
+ });
24
+
25
+ test("uses the session email when its name is the placeholder", () => {
26
+ expect(
27
+ resolveUserDisplayName({
28
+ savedName: "FrockBot user",
29
+ sessionName: "FrockBot user",
30
+ sessionEmail: " developer@example.com ",
31
+ }),
32
+ ).toBe("developer@example.com");
33
+ });
34
+
35
+ test("uses the placeholder when every candidate is blank", () => {
36
+ expect(
37
+ resolveUserDisplayName({
38
+ savedName: " ",
39
+ sessionName: "",
40
+ sessionEmail: " ",
41
+ }),
42
+ ).toBe("FrockBot user");
43
+ });
44
+ });
@@ -0,0 +1,16 @@
1
+ import {
2
+ isChosenUserName,
3
+ USER_PROFILE_PLACEHOLDER_NAME_V1,
4
+ } from "@frockbot/configuration-core";
5
+
6
+ export function resolveUserDisplayName(input: {
7
+ savedName?: string;
8
+ sessionName?: string;
9
+ sessionEmail?: string;
10
+ }): string {
11
+ if (isChosenUserName(input.savedName)) return input.savedName.trim();
12
+ if (isChosenUserName(input.sessionName)) return input.sessionName.trim();
13
+
14
+ const sessionEmail = input.sessionEmail?.trim();
15
+ return sessionEmail || USER_PROFILE_PLACEHOLDER_NAME_V1;
16
+ }
package/src/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ declare module "*.vue" {
2
+ import type { DefineComponent } from "vue";
3
+
4
+ const component: DefineComponent;
5
+ export default component;
6
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default, default as manifest } from "./manifest.js";
@@ -0,0 +1,3 @@
1
+ import manifest from "../frockbot.json" with { type: "json" };
2
+
3
+ export default manifest;