@burdenoff/microfe-vibecontrols 2026.602.5 → 2026.602.6

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.
@@ -6,64 +6,64 @@ import { useCallback as i, useEffect as a, useRef as o, useState as s } from "re
6
6
  import { Check as c, CheckCircle2 as l, Download as u, Loader2 as d, Puzzle as f, Trash2 as p } from "lucide-react";
7
7
  import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
8
8
  //#region src/components/ai/PluginHarnessPicker.tsx
9
- function _({ packages: _, agentId: v, title: y, description: b, onChange: x }) {
10
- let { installed: S, installing: C, install: w, refetch: T, loading: E, error: D } = n(_, v), [O] = e(), [k, A] = s(null), [j, M] = s({}), [N, P] = s({}), F = o(/* @__PURE__ */ new Map());
9
+ function _({ packages: _, agentId: v, title: y, description: b, onChange: x, renderInstalledAction: S }) {
10
+ let { installed: C, installing: w, install: T, refetch: E, loading: D, error: O } = n(_, v), [k] = e(), [A, j] = s(null), [M, N] = s({}), [P, F] = s({}), I = o(/* @__PURE__ */ new Map());
11
11
  a(() => {
12
- let e = F.current;
12
+ let e = I.current;
13
13
  return () => {
14
14
  for (let t of e.values()) clearTimeout(t);
15
15
  e.clear();
16
16
  };
17
17
  }, []);
18
- let I = i(async (e) => {
19
- if (await w(e)) {
20
- P((t) => ({
18
+ let L = i(async (e) => {
19
+ if (await T(e)) {
20
+ F((t) => ({
21
21
  ...t,
22
22
  [e]: !0
23
23
  }));
24
- let t = F.current.get(e);
24
+ let t = I.current.get(e);
25
25
  t && clearTimeout(t);
26
26
  let n = setTimeout(() => {
27
- P((t) => {
27
+ F((t) => {
28
28
  if (!t[e]) return t;
29
29
  let n = { ...t };
30
30
  return delete n[e], n;
31
- }), F.current.delete(e);
31
+ }), I.current.delete(e);
32
32
  }, 1500);
33
- F.current.set(e, n), x?.();
33
+ I.current.set(e, n), x?.();
34
34
  }
35
- }, [w, x]), L = i(async (e) => {
35
+ }, [T, x]), R = i(async (e) => {
36
36
  if (v) {
37
- A(e), M((t) => ({
37
+ j(e), N((t) => ({
38
38
  ...t,
39
39
  [e]: ""
40
40
  }));
41
41
  try {
42
- let { data: t } = await O({ variables: {
42
+ let { data: t } = await k({ variables: {
43
43
  agentId: v,
44
44
  packageName: e
45
45
  } });
46
46
  if (!t?.removeAgentPlugin.success) {
47
- M((n) => ({
47
+ N((n) => ({
48
48
  ...n,
49
49
  [e]: t?.removeAgentPlugin.error || "Remove failed"
50
50
  }));
51
51
  return;
52
52
  }
53
- await T(), x?.();
53
+ await E(), x?.();
54
54
  } catch (t) {
55
- M((n) => ({
55
+ N((n) => ({
56
56
  ...n,
57
57
  [e]: t instanceof Error ? t.message : String(t)
58
58
  }));
59
59
  } finally {
60
- A(null);
60
+ j(null);
61
61
  }
62
62
  }
63
63
  }, [
64
64
  v,
65
- O,
66
- T,
65
+ k,
66
+ E,
67
67
  x
68
68
  ]);
69
69
  return _.length === 0 ? null : /* @__PURE__ */ g("section", {
@@ -77,15 +77,15 @@ function _({ packages: _, agentId: v, title: y, description: b, onChange: x }) {
77
77
  className: "text-sm text-text-secondary mt-1",
78
78
  children: b
79
79
  })] }),
80
- D && /* @__PURE__ */ h("div", {
80
+ O && /* @__PURE__ */ h("div", {
81
81
  role: "alert",
82
82
  className: "rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-xs text-status-error-text",
83
- children: D
83
+ children: O
84
84
  }),
85
85
  /* @__PURE__ */ h("div", {
86
86
  className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3",
87
87
  children: _.map((e) => {
88
- let n = r(e), i = !!S[e], a = C === e, o = k === e, s = a || o || E, _ = !!N[e], y = j[e];
88
+ let n = r(e), i = !!C[e], a = w === e, o = A === e, s = a || o || D, _ = !!P[e], y = M[e];
89
89
  return /* @__PURE__ */ g(t, {
90
90
  padding: "md",
91
91
  className: "flex flex-col gap-3",
@@ -120,31 +120,35 @@ function _({ packages: _, agentId: v, title: y, description: b, onChange: x }) {
120
120
  ]
121
121
  })]
122
122
  }),
123
- /* @__PURE__ */ h("div", {
123
+ /* @__PURE__ */ g("div", {
124
124
  className: "flex items-center gap-2",
125
- children: i && _ ? /* @__PURE__ */ g("button", {
126
- type: "button",
127
- disabled: !0,
128
- className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-status-success-bg text-status-success-text border border-status-success-border cursor-default",
129
- "data-testid": `plugin-installed-${e}`,
130
- "aria-live": "polite",
131
- children: [/* @__PURE__ */ h(l, { className: "size-3.5" }), "Installed"]
132
- }) : i ? /* @__PURE__ */ g("button", {
133
- type: "button",
134
- disabled: s || !v,
135
- onClick: () => L(e),
136
- className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md border border-border-default text-text-secondary hover:border-status-error-border hover:text-status-error-text transition disabled:opacity-60 disabled:cursor-not-allowed",
137
- "data-testid": `plugin-remove-${e}`,
138
- children: [o ? /* @__PURE__ */ h(d, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ h(p, { className: "size-3.5" }), "Remove"]
139
- }) : /* @__PURE__ */ h("button", {
140
- type: "button",
141
- disabled: s || !v,
142
- onClick: () => I(e),
143
- className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition disabled:opacity-60 disabled:cursor-not-allowed",
144
- "data-testid": `plugin-install-${e}`,
145
- "aria-busy": a,
146
- children: a ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(d, { className: "size-3.5 animate-spin" }), "Installing…"] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(u, { className: "size-3.5" }), "Install"] })
147
- })
125
+ children: [
126
+ i && _ ? /* @__PURE__ */ g("button", {
127
+ type: "button",
128
+ disabled: !0,
129
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-status-success-bg text-status-success-text border border-status-success-border cursor-default",
130
+ "data-testid": `plugin-installed-${e}`,
131
+ "aria-live": "polite",
132
+ children: [/* @__PURE__ */ h(l, { className: "size-3.5" }), "Installed"]
133
+ }) : i ? /* @__PURE__ */ g("button", {
134
+ type: "button",
135
+ disabled: s || !v,
136
+ onClick: () => R(e),
137
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md border border-border-default text-text-secondary hover:border-status-error-border hover:text-status-error-text transition disabled:opacity-60 disabled:cursor-not-allowed",
138
+ "data-testid": `plugin-remove-${e}`,
139
+ children: [o ? /* @__PURE__ */ h(d, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ h(p, { className: "size-3.5" }), "Remove"]
140
+ }) : null,
141
+ i && !_ && S?.(e),
142
+ !i && /* @__PURE__ */ h("button", {
143
+ type: "button",
144
+ disabled: s || !v,
145
+ onClick: () => L(e),
146
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition disabled:opacity-60 disabled:cursor-not-allowed",
147
+ "data-testid": `plugin-install-${e}`,
148
+ "aria-busy": a,
149
+ children: a ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(d, { className: "size-3.5 animate-spin" }), "Installing…"] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(u, { className: "size-3.5" }), "Install"] })
150
+ })
151
+ ]
148
152
  }),
149
153
  y && /* @__PURE__ */ h("p", {
150
154
  className: "text-xs text-status-error-text",
@@ -1 +1 @@
1
- {"version":3,"file":"PluginHarnessPicker.js","names":[],"sources":["../../../src/components/ai/PluginHarnessPicker.tsx"],"sourcesContent":["/**\n * <PluginHarnessPicker />\n *\n * Grid of installable VibeControls agent plugins with per-card\n * Install / Installed / Remove state. Driven by the existing\n * `usePluginAvailability` hook (same code path as `<PluginGate>`), so\n * the Plugins tab on the Agent details page and this picker stay in\n * sync automatically.\n *\n * The default use-case is the AI workbench: once the base\n * `@vibecontrols/vibe-plugin-ai` plugin is installed, this picker lists\n * every AI provider harness (claude, codex, copilot, gemini, …) so the\n * user can add / remove harnesses without leaving the AI page.\n *\n * The component is feature-neutral — pass any `packages` array (e.g.\n * session providers, tunnel providers) to reuse the same UI.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Check, CheckCircle2, Download, Loader2, Puzzle, Trash2 } from 'lucide-react';\nimport { useRemoveAgentPluginMutation } from '@/generated/wspace-operations';\nimport { usePluginAvailability } from '@/hooks/usePluginAvailability';\nimport { getPluginMeta } from '@/constants/pluginCatalog';\nimport { Card } from '../shared/Card';\n\nexport interface PluginHarnessPickerProps {\n /** Package names to offer. Metadata is resolved via `getPluginMeta`. */\n packages: readonly string[];\n /** Active agent id. When null, the picker renders in a disabled state. */\n agentId: string | null;\n /** Optional section heading (rendered above the grid). */\n title?: string;\n /** Optional section description. */\n description?: string;\n /** Fired after a successful install or remove so parents can refetch. */\n onChange?: () => void;\n}\n\nexport function PluginHarnessPicker({\n packages,\n agentId,\n title,\n description,\n onChange,\n}: PluginHarnessPickerProps) {\n // Plugins are agent-wide (BOFF-2612); no profile threading needed.\n const { installed, installing, install, refetch, loading, error } = usePluginAvailability(\n packages,\n agentId\n );\n const [removePlugin] = useRemoveAgentPluginMutation();\n const [removingPkg, setRemovingPkg] = useState<string | null>(null);\n const [removeError, setRemoveError] = useState<Record<string, string>>({});\n // Per-package \"just installed\" pulse — flips on for ~1.5s after a\n // successful install so the button shows a clear success affordance\n // (checkmark + \"Installed\") before the card transitions to its\n // installed/Remove state. Without this the button silently flips from\n // spinner to Remove and users miss the success signal.\n const [justInstalled, setJustInstalled] = useState<Record<string, boolean>>({});\n const justInstalledTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n const timers = justInstalledTimers.current;\n return () => {\n for (const t of timers.values()) clearTimeout(t);\n timers.clear();\n };\n }, []);\n\n const handleInstall = useCallback(\n async (pkg: string) => {\n const ok = await install(pkg);\n if (ok) {\n setJustInstalled((prev) => ({ ...prev, [pkg]: true }));\n const existing = justInstalledTimers.current.get(pkg);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n setJustInstalled((prev) => {\n if (!prev[pkg]) return prev;\n const next = { ...prev };\n delete next[pkg];\n return next;\n });\n justInstalledTimers.current.delete(pkg);\n }, 1500);\n justInstalledTimers.current.set(pkg, timer);\n onChange?.();\n }\n },\n [install, onChange]\n );\n\n const handleRemove = useCallback(\n async (pkg: string) => {\n if (!agentId) return;\n setRemovingPkg(pkg);\n setRemoveError((e) => ({ ...e, [pkg]: '' }));\n try {\n const { data } = await removePlugin({\n variables: { agentId, packageName: pkg },\n });\n if (!data?.removeAgentPlugin.success) {\n setRemoveError((e) => ({\n ...e,\n [pkg]: data?.removeAgentPlugin.error || 'Remove failed',\n }));\n return;\n }\n await refetch();\n onChange?.();\n } catch (e) {\n setRemoveError((err) => ({\n ...err,\n [pkg]: e instanceof Error ? e.message : String(e),\n }));\n } finally {\n setRemovingPkg(null);\n }\n },\n [agentId, removePlugin, refetch, onChange]\n );\n\n if (packages.length === 0) return null;\n\n return (\n <section className=\"flex flex-col gap-3\" data-testid=\"plugin-harness-picker\">\n {(title || description) && (\n <div>\n {title && <h3 className=\"text-base font-semibold text-text-primary\">{title}</h3>}\n {description && <p className=\"text-sm text-text-secondary mt-1\">{description}</p>}\n </div>\n )}\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-xs text-status-error-text\"\n >\n {error}\n </div>\n )}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {packages.map((pkg) => {\n const meta = getPluginMeta(pkg);\n const isInstalled = !!installed[pkg];\n const isInstalling = installing === pkg;\n const isRemoving = removingPkg === pkg;\n const isBusy = isInstalling || isRemoving || loading;\n const showJustInstalled = !!justInstalled[pkg];\n const err = removeError[pkg];\n return (\n <Card key={pkg} padding=\"md\" className=\"flex flex-col gap-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-shrink-0 size-9 rounded-md bg-bg-sunken flex items-center justify-center\">\n <Puzzle className=\"size-4 text-text-secondary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start gap-2 flex-wrap\">\n {/*\n Plugin display name must wrap freely up to a\n reasonable hard cap so the column never blows up\n the modal layout. break-words allows wrapping on\n arbitrary characters when a name has no spaces;\n max-w bound corresponds to ~100 char-cells (a\n generous upper bound on real-world display names).\n */}\n <h4 className=\"font-medium text-text-primary break-words max-w-[100ch]\">\n {meta.displayName}\n </h4>\n {isInstalled && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded bg-status-success-bg text-status-success-text shrink-0\">\n <Check className=\"size-3\" /> installed\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary mt-0.5\">{meta.description}</p>\n <p\n className=\"text-[10px] font-mono text-text-placeholder mt-1 break-all\"\n title={pkg}\n >\n {pkg}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {isInstalled && showJustInstalled ? (\n <button\n type=\"button\"\n disabled\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-status-success-bg text-status-success-text border border-status-success-border cursor-default\"\n data-testid={`plugin-installed-${pkg}`}\n aria-live=\"polite\"\n >\n <CheckCircle2 className=\"size-3.5\" />\n Installed\n </button>\n ) : isInstalled ? (\n <button\n type=\"button\"\n disabled={isBusy || !agentId}\n onClick={() => handleRemove(pkg)}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md border border-border-default text-text-secondary hover:border-status-error-border hover:text-status-error-text transition disabled:opacity-60 disabled:cursor-not-allowed\"\n data-testid={`plugin-remove-${pkg}`}\n >\n {isRemoving ? (\n <Loader2 className=\"size-3.5 animate-spin\" />\n ) : (\n <Trash2 className=\"size-3.5\" />\n )}\n Remove\n </button>\n ) : (\n <button\n type=\"button\"\n disabled={isBusy || !agentId}\n onClick={() => handleInstall(pkg)}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition disabled:opacity-60 disabled:cursor-not-allowed\"\n data-testid={`plugin-install-${pkg}`}\n aria-busy={isInstalling}\n >\n {isInstalling ? (\n <>\n <Loader2 className=\"size-3.5 animate-spin\" />\n Installing…\n </>\n ) : (\n <>\n <Download className=\"size-3.5\" />\n Install\n </>\n )}\n </button>\n )}\n </div>\n {err && <p className=\"text-xs text-status-error-text\">{err}</p>}\n </Card>\n );\n })}\n </div>\n {!agentId && <p className=\"text-xs text-text-muted\">Select an agent to manage plugins.</p>}\n </section>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PluginHarnessPicker.js","names":[],"sources":["../../../src/components/ai/PluginHarnessPicker.tsx"],"sourcesContent":["/**\n * <PluginHarnessPicker />\n *\n * Grid of installable VibeControls agent plugins with per-card\n * Install / Installed / Remove state. Driven by the existing\n * `usePluginAvailability` hook (same code path as `<PluginGate>`), so\n * the Plugins tab on the Agent details page and this picker stay in\n * sync automatically.\n *\n * The default use-case is the AI workbench: once the base\n * `@vibecontrols/vibe-plugin-ai` plugin is installed, this picker lists\n * every AI provider harness (claude, codex, copilot, gemini, …) so the\n * user can add / remove harnesses without leaving the AI page.\n *\n * The component is feature-neutral — pass any `packages` array (e.g.\n * session providers, tunnel providers) to reuse the same UI.\n */\n\nimport { useCallback, useEffect, useRef, useState, type ReactNode } from 'react';\nimport { Check, CheckCircle2, Download, Loader2, Puzzle, Trash2 } from 'lucide-react';\nimport { useRemoveAgentPluginMutation } from '@/generated/wspace-operations';\nimport { usePluginAvailability } from '@/hooks/usePluginAvailability';\nimport { getPluginMeta } from '@/constants/pluginCatalog';\nimport { Card } from '../shared/Card';\n\nexport interface PluginHarnessPickerProps {\n /** Package names to offer. Metadata is resolved via `getPluginMeta`. */\n packages: readonly string[];\n /** Active agent id. When null, the picker renders in a disabled state. */\n agentId: string | null;\n /** Optional section heading (rendered above the grid). */\n title?: string;\n /** Optional section description. */\n description?: string;\n /** Fired after a successful install or remove so parents can refetch. */\n onChange?: () => void;\n /**\n * Optional per-card action slot, rendered alongside the Remove button when\n * a package is installed. Lets a feature (e.g. the Security tab) attach a\n * contextual action — like \"Run scan\" — without coupling this generic\n * picker to that feature. Receives the installed package name.\n */\n renderInstalledAction?: (pkg: string) => ReactNode;\n}\n\nexport function PluginHarnessPicker({\n packages,\n agentId,\n title,\n description,\n onChange,\n renderInstalledAction,\n}: PluginHarnessPickerProps) {\n // Plugins are agent-wide (BOFF-2612); no profile threading needed.\n const { installed, installing, install, refetch, loading, error } = usePluginAvailability(\n packages,\n agentId\n );\n const [removePlugin] = useRemoveAgentPluginMutation();\n const [removingPkg, setRemovingPkg] = useState<string | null>(null);\n const [removeError, setRemoveError] = useState<Record<string, string>>({});\n // Per-package \"just installed\" pulse — flips on for ~1.5s after a\n // successful install so the button shows a clear success affordance\n // (checkmark + \"Installed\") before the card transitions to its\n // installed/Remove state. Without this the button silently flips from\n // spinner to Remove and users miss the success signal.\n const [justInstalled, setJustInstalled] = useState<Record<string, boolean>>({});\n const justInstalledTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n const timers = justInstalledTimers.current;\n return () => {\n for (const t of timers.values()) clearTimeout(t);\n timers.clear();\n };\n }, []);\n\n const handleInstall = useCallback(\n async (pkg: string) => {\n const ok = await install(pkg);\n if (ok) {\n setJustInstalled((prev) => ({ ...prev, [pkg]: true }));\n const existing = justInstalledTimers.current.get(pkg);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n setJustInstalled((prev) => {\n if (!prev[pkg]) return prev;\n const next = { ...prev };\n delete next[pkg];\n return next;\n });\n justInstalledTimers.current.delete(pkg);\n }, 1500);\n justInstalledTimers.current.set(pkg, timer);\n onChange?.();\n }\n },\n [install, onChange]\n );\n\n const handleRemove = useCallback(\n async (pkg: string) => {\n if (!agentId) return;\n setRemovingPkg(pkg);\n setRemoveError((e) => ({ ...e, [pkg]: '' }));\n try {\n const { data } = await removePlugin({\n variables: { agentId, packageName: pkg },\n });\n if (!data?.removeAgentPlugin.success) {\n setRemoveError((e) => ({\n ...e,\n [pkg]: data?.removeAgentPlugin.error || 'Remove failed',\n }));\n return;\n }\n await refetch();\n onChange?.();\n } catch (e) {\n setRemoveError((err) => ({\n ...err,\n [pkg]: e instanceof Error ? e.message : String(e),\n }));\n } finally {\n setRemovingPkg(null);\n }\n },\n [agentId, removePlugin, refetch, onChange]\n );\n\n if (packages.length === 0) return null;\n\n return (\n <section className=\"flex flex-col gap-3\" data-testid=\"plugin-harness-picker\">\n {(title || description) && (\n <div>\n {title && <h3 className=\"text-base font-semibold text-text-primary\">{title}</h3>}\n {description && <p className=\"text-sm text-text-secondary mt-1\">{description}</p>}\n </div>\n )}\n {error && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-xs text-status-error-text\"\n >\n {error}\n </div>\n )}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n {packages.map((pkg) => {\n const meta = getPluginMeta(pkg);\n const isInstalled = !!installed[pkg];\n const isInstalling = installing === pkg;\n const isRemoving = removingPkg === pkg;\n const isBusy = isInstalling || isRemoving || loading;\n const showJustInstalled = !!justInstalled[pkg];\n const err = removeError[pkg];\n return (\n <Card key={pkg} padding=\"md\" className=\"flex flex-col gap-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex-shrink-0 size-9 rounded-md bg-bg-sunken flex items-center justify-center\">\n <Puzzle className=\"size-4 text-text-secondary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start gap-2 flex-wrap\">\n {/*\n Plugin display name must wrap freely up to a\n reasonable hard cap so the column never blows up\n the modal layout. break-words allows wrapping on\n arbitrary characters when a name has no spaces;\n max-w bound corresponds to ~100 char-cells (a\n generous upper bound on real-world display names).\n */}\n <h4 className=\"font-medium text-text-primary break-words max-w-[100ch]\">\n {meta.displayName}\n </h4>\n {isInstalled && (\n <span className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs rounded bg-status-success-bg text-status-success-text shrink-0\">\n <Check className=\"size-3\" /> installed\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary mt-0.5\">{meta.description}</p>\n <p\n className=\"text-[10px] font-mono text-text-placeholder mt-1 break-all\"\n title={pkg}\n >\n {pkg}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n {isInstalled && showJustInstalled ? (\n <button\n type=\"button\"\n disabled\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-status-success-bg text-status-success-text border border-status-success-border cursor-default\"\n data-testid={`plugin-installed-${pkg}`}\n aria-live=\"polite\"\n >\n <CheckCircle2 className=\"size-3.5\" />\n Installed\n </button>\n ) : isInstalled ? (\n <button\n type=\"button\"\n disabled={isBusy || !agentId}\n onClick={() => handleRemove(pkg)}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md border border-border-default text-text-secondary hover:border-status-error-border hover:text-status-error-text transition disabled:opacity-60 disabled:cursor-not-allowed\"\n data-testid={`plugin-remove-${pkg}`}\n >\n {isRemoving ? (\n <Loader2 className=\"size-3.5 animate-spin\" />\n ) : (\n <Trash2 className=\"size-3.5\" />\n )}\n Remove\n </button>\n ) : null}\n {isInstalled && !showJustInstalled && renderInstalledAction?.(pkg)}\n {!isInstalled && (\n <button\n type=\"button\"\n disabled={isBusy || !agentId}\n onClick={() => handleInstall(pkg)}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition disabled:opacity-60 disabled:cursor-not-allowed\"\n data-testid={`plugin-install-${pkg}`}\n aria-busy={isInstalling}\n >\n {isInstalling ? (\n <>\n <Loader2 className=\"size-3.5 animate-spin\" />\n Installing…\n </>\n ) : (\n <>\n <Download className=\"size-3.5\" />\n Install\n </>\n )}\n </button>\n )}\n </div>\n {err && <p className=\"text-xs text-status-error-text\">{err}</p>}\n </Card>\n );\n })}\n </div>\n {!agentId && <p className=\"text-xs text-text-muted\">Select an agent to manage plugins.</p>}\n </section>\n );\n}\n"],"mappings":";;;;;;;;AA6CA,SAAgB,EAAoB,EAClC,aACA,YACA,UACA,gBACA,aACA,4BAC2B;CAE3B,IAAM,EAAE,cAAW,eAAY,YAAS,YAAS,YAAS,aAAU,EAClE,GACA,EACD,EACK,CAAC,KAAgB,GAA8B,EAC/C,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAa,KAAkB,EAAiC,EAAE,CAAC,EAMpE,CAAC,GAAe,KAAoB,EAAkC,EAAE,CAAC,EACzE,IAAsB,kBAAmD,IAAI,KAAK,CAAC;AAEzF,SAAgB;EACd,IAAM,IAAS,EAAoB;AACnC,eAAa;AACX,QAAK,IAAM,KAAK,EAAO,QAAQ,CAAE,cAAa,EAAE;AAChD,KAAO,OAAO;;IAEf,EAAE,CAAC;CAEN,IAAM,IAAgB,EACpB,OAAO,MAAgB;AAErB,MADW,MAAM,EAAQ,EAAI,EACrB;AACN,MAAkB,OAAU;IAAE,GAAG;KAAO,IAAM;IAAM,EAAE;GACtD,IAAM,IAAW,EAAoB,QAAQ,IAAI,EAAI;AACrD,GAAI,KAAU,aAAa,EAAS;GACpC,IAAM,IAAQ,iBAAiB;AAO7B,IANA,GAAkB,MAAS;AACzB,SAAI,CAAC,EAAK,GAAM,QAAO;KACvB,IAAM,IAAO,EAAE,GAAG,GAAM;AAExB,YADA,OAAO,EAAK,IACL;MACP,EACF,EAAoB,QAAQ,OAAO,EAAI;MACtC,KAAK;AAER,GADA,EAAoB,QAAQ,IAAI,GAAK,EAAM,EAC3C,KAAY;;IAGhB,CAAC,GAAS,EAAS,CACpB,EAEK,IAAe,EACnB,OAAO,MAAgB;AAChB,SAEL;GADA,EAAe,EAAI,EACnB,GAAgB,OAAO;IAAE,GAAG;KAAI,IAAM;IAAI,EAAE;AAC5C,OAAI;IACF,IAAM,EAAE,YAAS,MAAM,EAAa,EAClC,WAAW;KAAE;KAAS,aAAa;KAAK,EACzC,CAAC;AACF,QAAI,CAAC,GAAM,kBAAkB,SAAS;AACpC,QAAgB,OAAO;MACrB,GAAG;OACF,IAAM,GAAM,kBAAkB,SAAS;MACzC,EAAE;AACH;;AAGF,IADA,MAAM,GAAS,EACf,KAAY;YACL,GAAG;AACV,OAAgB,OAAS;KACvB,GAAG;MACF,IAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;KAClD,EAAE;aACK;AACR,MAAe,KAAK;;;IAGxB;EAAC;EAAS;EAAc;EAAS;EAAS,CAC3C;AAID,QAFI,EAAS,WAAW,IAAU,OAGhC,kBAAC,WAAD;EAAS,WAAU;EAAsB,eAAY;YAArD;IACI,KAAS,MACT,kBAAC,OAAD,EAAA,UAAA,CACG,KAAS,kBAAC,MAAD;IAAI,WAAU;cAA6C;IAAW,CAAA,EAC/E,KAAe,kBAAC,KAAD;IAAG,WAAU;cAAoC;IAAgB,CAAA,CAC7E,EAAA,CAAA;GAEP,KACC,kBAAC,OAAD;IACE,MAAK;IACL,WAAU;cAET;IACG,CAAA;GAER,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MAAQ;KACrB,IAAM,IAAO,EAAc,EAAI,EACzB,IAAc,CAAC,CAAC,EAAU,IAC1B,IAAe,MAAe,GAC9B,IAAa,MAAgB,GAC7B,IAAS,KAAgB,KAAc,GACvC,IAAoB,CAAC,CAAC,EAAc,IACpC,IAAM,EAAY;AACxB,YACE,kBAAC,GAAD;MAAgB,SAAQ;MAAK,WAAU;gBAAvC;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,GAAD,EAAQ,WAAU,8BAA+B,CAAA;SAC7C,CAAA,EACN,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CASE,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAK;YACH,CAAA,EACJ,KACC,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CACE,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA,EAAA,aACvB;cAEL;;UACN,kBAAC,KAAD;WAAG,WAAU;qBAAsC,EAAK;WAAgB,CAAA;UACxE,kBAAC,KAAD;WACE,WAAU;WACV,OAAO;qBAEN;WACC,CAAA;UACA;WACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACG,KAAe,IACd,kBAAC,UAAD;UACE,MAAK;UACL,UAAA;UACA,WAAU;UACV,eAAa,oBAAoB;UACjC,aAAU;oBALZ,CAOE,kBAAC,GAAD,EAAc,WAAU,YAAa,CAAA,EAAA,YAE9B;cACP,IACF,kBAAC,UAAD;UACE,MAAK;UACL,UAAU,KAAU,CAAC;UACrB,eAAe,EAAa,EAAI;UAChC,WAAU;UACV,eAAa,iBAAiB;oBALhC,CAOG,IACC,kBAAC,GAAD,EAAS,WAAU,yBAA0B,CAAA,GAE7C,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA,EAC/B,SAEK;cACP;SACH,KAAe,CAAC,KAAqB,IAAwB,EAAI;SACjE,CAAC,KACA,kBAAC,UAAD;UACE,MAAK;UACL,UAAU,KAAU,CAAC;UACrB,eAAe,EAAc,EAAI;UACjC,WAAU;UACV,eAAa,kBAAkB;UAC/B,aAAW;oBAEV,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAS,WAAU,yBAA0B,CAAA,EAAA,cAE5C,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EAAA,UAEhC,EAAA,CAAA;UAEE,CAAA;SAEP;;OACL,KAAO,kBAAC,KAAD;QAAG,WAAU;kBAAkC;QAAQ,CAAA;OAC1D;QAtFI,EAsFJ;MAET;IACE,CAAA;GACL,CAAC,KAAW,kBAAC,KAAD;IAAG,WAAU;cAA0B;IAAsC,CAAA;GAClF"}
@@ -0,0 +1,60 @@
1
+ import { SECURITY_STAGE_BY_PACKAGE as e } from "../../constants/pluginCatalog.js";
2
+ import { SecurityAgentError as t } from "./agentClient.js";
3
+ import { useStartSecurityScanMutation as n } from "./hooks.js";
4
+ import { useCallback as r, useState as i } from "react";
5
+ import { AlertCircle as a, Loader2 as o, Play as s } from "lucide-react";
6
+ import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
7
+ //#region src/components/security/SecurityRunButton.tsx
8
+ function d({ pkg: d, vibeId: f, workspaceId: p, repoUrl: m, repoLocalPath: h, commit: g, agentId: _, profile: v }) {
9
+ let y = e[d], { mutateAsync: b, isPending: x } = n({
10
+ agentId: _,
11
+ profile: v
12
+ }), [S, C] = i(null), w = r(async () => {
13
+ if (!(!y || !_)) {
14
+ C(null);
15
+ try {
16
+ await b({
17
+ vibeId: f,
18
+ workspaceId: p,
19
+ repoUrl: m,
20
+ repoLocalPath: h,
21
+ commit: g,
22
+ stage: y
23
+ });
24
+ } catch (e) {
25
+ C(e instanceof t || e instanceof Error ? e.message : "Failed to start scan");
26
+ }
27
+ }
28
+ }, [
29
+ y,
30
+ _,
31
+ b,
32
+ f,
33
+ p,
34
+ m,
35
+ h,
36
+ g
37
+ ]);
38
+ return y ? /* @__PURE__ */ u("div", {
39
+ className: "flex flex-col gap-1",
40
+ children: [/* @__PURE__ */ l("button", {
41
+ type: "button",
42
+ disabled: x || !_,
43
+ onClick: () => void w(),
44
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition disabled:opacity-60 disabled:cursor-not-allowed",
45
+ "data-testid": `security-run-${d}`,
46
+ "aria-busy": x,
47
+ children: x ? /* @__PURE__ */ u(c, { children: [/* @__PURE__ */ l(o, { className: "size-3.5 animate-spin" }), "Running…"] }) : /* @__PURE__ */ u(c, { children: [/* @__PURE__ */ l(s, { className: "size-3.5" }), "Run scan"] })
48
+ }), S && /* @__PURE__ */ u("p", {
49
+ className: "inline-flex items-start gap-1 text-xs text-status-error-text",
50
+ children: [/* @__PURE__ */ l(a, {
51
+ className: "size-3.5 mt-px shrink-0",
52
+ "aria-hidden": "true"
53
+ }), /* @__PURE__ */ l("span", { children: S })]
54
+ })]
55
+ }) : null;
56
+ }
57
+ //#endregion
58
+ export { d as SecurityRunButton };
59
+
60
+ //# sourceMappingURL=SecurityRunButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurityRunButton.js","names":[],"sources":["../../../src/components/security/SecurityRunButton.tsx"],"sourcesContent":["/**\n * Per-stage \"Run scan\" control for an installed security provider plugin.\n *\n * Mounted as the `renderInstalledAction` slot of `<PluginHarnessPicker>` on\n * the Security tab: each installed provider card gets a Run button that\n * kicks off a scan for that provider's lifecycle stage against the current\n * vibe. The scan runs on the agent (over the svc GraphQL proxy); on success\n * the start mutation invalidates the `['security', agentId, profile, …]`\n * query family — which includes `useSecurityRecentScansQuery` — so the new\n * run surfaces in `<SecurityScanList>` with its conclusion + severity counts.\n *\n * Errors are surfaced inline (a small chip under the button), matching how\n * `<PluginHarnessPicker>` and `<SecurityScanList>` render their failures —\n * never a raw error toast.\n */\nimport { useCallback, useState, type ReactElement } from 'react';\nimport { AlertCircle, Loader2, Play } from 'lucide-react';\n\nimport { SECURITY_STAGE_BY_PACKAGE } from '@/constants/pluginCatalog';\nimport { useStartSecurityScanMutation, type UseSecurityAgentContext } from './hooks';\nimport { SecurityAgentError, type AgentStage } from './agentClient';\n\nexport interface SecurityRunButtonProps extends UseSecurityAgentContext {\n /** The installed security provider package this button runs. */\n pkg: string;\n /** Current vibe id. */\n vibeId: string;\n /** Workspace the vibe belongs to (required by the agent scan contract). */\n workspaceId: string;\n /** Git remote → recorded as `repoUrl` on the run. */\n repoUrl: string;\n /** Local checkout path the provider tooling runs against. */\n repoLocalPath: string;\n /** Best-effort commit ref (the vibe's git branch). */\n commit: string;\n}\n\nexport function SecurityRunButton({\n pkg,\n vibeId,\n workspaceId,\n repoUrl,\n repoLocalPath,\n commit,\n agentId,\n profile,\n}: SecurityRunButtonProps): ReactElement | null {\n const stage = SECURITY_STAGE_BY_PACKAGE[pkg] as AgentStage | undefined;\n const { mutateAsync, isPending } = useStartSecurityScanMutation({ agentId, profile });\n const [error, setError] = useState<string | null>(null);\n\n const handleRun = useCallback(async () => {\n if (!stage || !agentId) return;\n setError(null);\n try {\n await mutateAsync({\n vibeId,\n workspaceId,\n repoUrl,\n repoLocalPath,\n commit,\n stage,\n });\n // On success the mutation invalidates the security query family, which\n // refetches the recent-scans list — no manual refetch needed here.\n } catch (err) {\n const message =\n err instanceof SecurityAgentError || err instanceof Error\n ? err.message\n : 'Failed to start scan';\n setError(message);\n }\n }, [stage, agentId, mutateAsync, vibeId, workspaceId, repoUrl, repoLocalPath, commit]);\n\n // Provider package isn't mapped to a known stage — can't run it.\n if (!stage) return null;\n\n const disabled = isPending || !agentId;\n\n return (\n <div className=\"flex flex-col gap-1\">\n <button\n type=\"button\"\n disabled={disabled}\n onClick={() => void handleRun()}\n className=\"inline-flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition disabled:opacity-60 disabled:cursor-not-allowed\"\n data-testid={`security-run-${pkg}`}\n aria-busy={isPending}\n >\n {isPending ? (\n <>\n <Loader2 className=\"size-3.5 animate-spin\" />\n Running…\n </>\n ) : (\n <>\n <Play className=\"size-3.5\" />\n Run scan\n </>\n )}\n </button>\n {error && (\n <p className=\"inline-flex items-start gap-1 text-xs text-status-error-text\">\n <AlertCircle className=\"size-3.5 mt-px shrink-0\" aria-hidden=\"true\" />\n <span>{error}</span>\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAqCA,SAAgB,EAAkB,EAChC,QACA,WACA,gBACA,YACA,kBACA,WACA,YACA,cAC8C;CAC9C,IAAM,IAAQ,EAA0B,IAClC,EAAE,gBAAa,iBAAc,EAA6B;EAAE;EAAS;EAAS,CAAC,EAC/E,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAY,EAAY,YAAY;AACpC,SAAC,KAAS,CAAC,IACf;KAAS,KAAK;AACd,OAAI;AACF,UAAM,EAAY;KAChB;KACA;KACA;KACA;KACA;KACA;KACD,CAAC;YAGK,GAAK;AAKZ,MAHE,aAAe,KAAsB,aAAe,QAChD,EAAI,UACJ,uBACW;;;IAElB;EAAC;EAAO;EAAS;EAAa;EAAQ;EAAa;EAAS;EAAe;EAAO,CAAC;AAOtF,QAJK,IAKH,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GACE,MAAK;GACK,UANC,KAAa,CAAC;GAOzB,eAAe,KAAK,GAAW;GAC/B,WAAU;GACV,eAAa,gBAAgB;GAC7B,aAAW;aAEV,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAS,WAAU,yBAA0B,CAAA,EAAA,WAE5C,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAM,WAAU,YAAa,CAAA,EAAA,WAE5B,EAAA,CAAA;GAEE,CAAA,EACR,KACC,kBAAC,KAAD;GAAG,WAAU;aAAb,CACE,kBAAC,GAAD;IAAa,WAAU;IAA0B,eAAY;IAAS,CAAA,EACtE,kBAAC,QAAD,EAAA,UAAO,GAAa,CAAA,CAClB;KAEF;MAhCW"}
@@ -1,50 +1,66 @@
1
- import { SECURITY_META_PACKAGE as e, SECURITY_PROVIDER_PACKAGES as t } from "../../constants/pluginCatalog.js";
2
- import { PluginGate as n } from "../shared/PluginGate.js";
3
- import { PluginHarnessPicker as r } from "../ai/PluginHarnessPicker.js";
4
- import { SecurityScanList as i } from "./SecurityScanList.js";
5
- import { Shield as a } from "lucide-react";
6
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
1
+ import { useGetVibeQuery as e } from "../../generated/wspace-operations.js";
2
+ import { SECURITY_META_PACKAGE as t, SECURITY_PROVIDER_PACKAGES as n } from "../../constants/pluginCatalog.js";
3
+ import { PluginGate as r } from "../shared/PluginGate.js";
4
+ import { PluginHarnessPicker as i } from "../ai/PluginHarnessPicker.js";
5
+ import { SecurityScanList as a } from "./SecurityScanList.js";
6
+ import { SecurityRunButton as o } from "./SecurityRunButton.js";
7
+ import { Shield as s } from "lucide-react";
8
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
9
  //#region src/components/security/SecurityTabPanel.tsx
8
- function c({ vibeId: c, agentId: l, profile: u = "default" }) {
9
- return /* @__PURE__ */ s("div", {
10
+ function u({ vibeId: u, agentId: d, profile: f = "default" }) {
11
+ let { data: p } = e({
12
+ variables: { id: u },
13
+ skip: !u
14
+ }), m = p?.vibe, h = m?.workspaceId ?? "", g = m?.gitRemote ?? "", _ = m?.path ?? "", v = m?.gitBranch ?? "";
15
+ return /* @__PURE__ */ l("div", {
10
16
  "data-testid": "security-tab-panel",
11
17
  className: "space-y-4",
12
- children: [/* @__PURE__ */ s("header", {
18
+ children: [/* @__PURE__ */ l("header", {
13
19
  className: "flex items-start gap-3",
14
- children: [/* @__PURE__ */ o("div", {
20
+ children: [/* @__PURE__ */ c("div", {
15
21
  className: "size-9 rounded-md bg-bg-sunken flex items-center justify-center shrink-0",
16
- children: /* @__PURE__ */ o(a, { className: "size-4 text-text-secondary" })
17
- }), /* @__PURE__ */ s("div", {
22
+ children: /* @__PURE__ */ c(s, { className: "size-4 text-text-secondary" })
23
+ }), /* @__PURE__ */ l("div", {
18
24
  className: "min-w-0",
19
- children: [/* @__PURE__ */ o("h2", {
25
+ children: [/* @__PURE__ */ c("h2", {
20
26
  className: "text-base font-semibold text-text-primary",
21
27
  children: "Security"
22
- }), /* @__PURE__ */ o("p", {
28
+ }), /* @__PURE__ */ c("p", {
23
29
  className: "text-sm text-text-secondary mt-0.5",
24
30
  children: "Install + run security scans across the 14-stage lifecycle. Plugins run on the agent; findings live in its local SQLite cache."
25
31
  })]
26
32
  })]
27
- }), /* @__PURE__ */ s(n, {
28
- agentId: l,
29
- required: [e],
33
+ }), /* @__PURE__ */ l(r, {
34
+ agentId: d,
35
+ required: [t],
30
36
  mode: "all",
31
37
  eyebrow: "Security plugin required",
32
38
  title: "Install the Security Orchestrator",
33
39
  description: "@vibecontrols/vibe-plugin-security routes scans across per-stage providers. Required before installing individual stage providers.",
34
- children: [/* @__PURE__ */ o(r, {
35
- packages: t,
36
- agentId: l,
40
+ children: [/* @__PURE__ */ c(i, {
41
+ packages: n,
42
+ agentId: d,
37
43
  title: "Security Providers",
38
- description: "One plugin per stage in the security lifecycle. Install the providers you want to use; uninstalled stages stay skipped."
39
- }), /* @__PURE__ */ o(i, {
40
- vibeId: c,
41
- agentId: l,
42
- profile: u
44
+ description: "One plugin per stage in the security lifecycle. Install the providers you want to use; uninstalled stages stay skipped. Run a stage's scan from its card once installed.",
45
+ renderInstalledAction: (e) => /* @__PURE__ */ c(o, {
46
+ pkg: e,
47
+ vibeId: u,
48
+ workspaceId: h,
49
+ repoUrl: g,
50
+ repoLocalPath: _,
51
+ commit: v,
52
+ agentId: d,
53
+ profile: f
54
+ })
55
+ }), /* @__PURE__ */ c(a, {
56
+ vibeId: u,
57
+ agentId: d,
58
+ profile: f
43
59
  })]
44
60
  })]
45
61
  });
46
62
  }
47
63
  //#endregion
48
- export { c as SecurityTabPanel };
64
+ export { u as SecurityTabPanel };
49
65
 
50
66
  //# sourceMappingURL=SecurityTabPanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityTabPanel.js","names":[],"sources":["../../../src/components/security/SecurityTabPanel.tsx"],"sourcesContent":["/**\n * Security tab on Vibe detail.\n *\n * Wave 1: surface the security plugins so the user can find +\n * install them from the UI (same pattern as the AI page).\n *\n * Wave 2 (this commit): once the meta plugin is installed, mount\n * `SecurityScanList` which reads recent scan runs straight from the\n * agent over the tunnel (`/api/profiles/<profile>/security/*`). No\n * backend GraphQL involvement — all per-vibe scan history lives in\n * the agent's local SQLite cache.\n */\n\nimport { Shield } from 'lucide-react';\nimport { PluginGate } from '../shared/PluginGate';\nimport { PluginHarnessPicker } from '../ai/PluginHarnessPicker';\nimport { SECURITY_META_PACKAGE, SECURITY_PROVIDER_PACKAGES } from '@/constants/pluginCatalog';\nimport { SecurityScanList } from './SecurityScanList';\n\ninterface PanelProps {\n vibeId: string;\n agentId: string | null;\n /**\n * Canonical agent profile name. Threaded through from VibeDetailsPage's\n * `useActiveAgentProfile` so the tab targets the same profile the rest\n * of the page is talking to.\n */\n profile?: string;\n}\n\nexport function SecurityTabPanel({\n vibeId,\n agentId,\n profile = 'default',\n}: PanelProps): React.ReactElement {\n return (\n <div data-testid=\"security-tab-panel\" className=\"space-y-4\">\n <header className=\"flex items-start gap-3\">\n <div className=\"size-9 rounded-md bg-bg-sunken flex items-center justify-center shrink-0\">\n <Shield className=\"size-4 text-text-secondary\" />\n </div>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">Security</h2>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n Install + run security scans across the 14-stage lifecycle. Plugins run on the agent;\n findings live in its local SQLite cache.\n </p>\n </div>\n </header>\n\n <PluginGate\n agentId={agentId}\n required={[SECURITY_META_PACKAGE]}\n mode=\"all\"\n eyebrow=\"Security plugin required\"\n title=\"Install the Security Orchestrator\"\n description=\"@vibecontrols/vibe-plugin-security routes scans across per-stage providers. Required before installing individual stage providers.\"\n >\n <PluginHarnessPicker\n packages={SECURITY_PROVIDER_PACKAGES}\n agentId={agentId}\n title=\"Security Providers\"\n description=\"One plugin per stage in the security lifecycle. Install the providers you want to use; uninstalled stages stay skipped.\"\n />\n <SecurityScanList vibeId={vibeId} agentId={agentId} profile={profile} />\n </PluginGate>\n </div>\n );\n}\n"],"mappings":";;;;;;;AA8BA,SAAgB,EAAiB,EAC/B,WACA,YACA,aAAU,aACuB;AACjC,QACE,kBAAC,OAAD;EAAK,eAAY;EAAqB,WAAU;YAAhD,CACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAQ,WAAU,8BAA+B,CAAA;IAC7C,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAA4C;KAAa,CAAA,EACvE,kBAAC,KAAD;KAAG,WAAU;eAAqC;KAG9C,CAAA,CACA;MACC;MAET,kBAAC,GAAD;GACW;GACT,UAAU,CAAC,EAAsB;GACjC,MAAK;GACL,SAAQ;GACR,OAAM;GACN,aAAY;aANd,CAQE,kBAAC,GAAD;IACE,UAAU;IACD;IACT,OAAM;IACN,aAAY;IACZ,CAAA,EACF,kBAAC,GAAD;IAA0B;IAAiB;IAAkB;IAAW,CAAA,CAC7D;KACT"}
1
+ {"version":3,"file":"SecurityTabPanel.js","names":[],"sources":["../../../src/components/security/SecurityTabPanel.tsx"],"sourcesContent":["/**\n * Security tab on Vibe detail.\n *\n * Wave 1: surface the security plugins so the user can find +\n * install them from the UI (same pattern as the AI page).\n *\n * Wave 2 (this commit): once the meta plugin is installed, mount\n * `SecurityScanList` which reads recent scan runs straight from the\n * agent over the tunnel (`/api/profiles/<profile>/security/*`). No\n * backend GraphQL involvement — all per-vibe scan history lives in\n * the agent's local SQLite cache.\n */\n\nimport { Shield } from 'lucide-react';\nimport { useGetVibeQuery } from '@/generated/wspace-operations';\nimport { PluginGate } from '../shared/PluginGate';\nimport { PluginHarnessPicker } from '../ai/PluginHarnessPicker';\nimport { SECURITY_META_PACKAGE, SECURITY_PROVIDER_PACKAGES } from '@/constants/pluginCatalog';\nimport { SecurityScanList } from './SecurityScanList';\nimport { SecurityRunButton } from './SecurityRunButton';\n\ninterface PanelProps {\n vibeId: string;\n agentId: string | null;\n /**\n * Canonical agent profile name. Threaded through from VibeDetailsPage's\n * `useActiveAgentProfile` so the tab targets the same profile the rest\n * of the page is talking to.\n */\n profile?: string;\n}\n\nexport function SecurityTabPanel({\n vibeId,\n agentId,\n profile = 'default',\n}: PanelProps): React.ReactElement {\n // Repo metadata the agent scan contract needs. Shares the Apollo cache\n // entry the details page already primed via its own `useGetVibeQuery`, so\n // this is a cache read in practice — no extra network round-trip.\n const { data: vibeData } = useGetVibeQuery({\n variables: { id: vibeId },\n skip: !vibeId,\n });\n const vibe = vibeData?.vibe;\n const workspaceId = vibe?.workspaceId ?? '';\n const repoUrl = vibe?.gitRemote ?? '';\n const repoLocalPath = vibe?.path ?? '';\n const commit = vibe?.gitBranch ?? '';\n\n return (\n <div data-testid=\"security-tab-panel\" className=\"space-y-4\">\n <header className=\"flex items-start gap-3\">\n <div className=\"size-9 rounded-md bg-bg-sunken flex items-center justify-center shrink-0\">\n <Shield className=\"size-4 text-text-secondary\" />\n </div>\n <div className=\"min-w-0\">\n <h2 className=\"text-base font-semibold text-text-primary\">Security</h2>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n Install + run security scans across the 14-stage lifecycle. Plugins run on the agent;\n findings live in its local SQLite cache.\n </p>\n </div>\n </header>\n\n <PluginGate\n agentId={agentId}\n required={[SECURITY_META_PACKAGE]}\n mode=\"all\"\n eyebrow=\"Security plugin required\"\n title=\"Install the Security Orchestrator\"\n description=\"@vibecontrols/vibe-plugin-security routes scans across per-stage providers. Required before installing individual stage providers.\"\n >\n <PluginHarnessPicker\n packages={SECURITY_PROVIDER_PACKAGES}\n agentId={agentId}\n title=\"Security Providers\"\n description=\"One plugin per stage in the security lifecycle. Install the providers you want to use; uninstalled stages stay skipped. Run a stage's scan from its card once installed.\"\n renderInstalledAction={(pkg) => (\n <SecurityRunButton\n pkg={pkg}\n vibeId={vibeId}\n workspaceId={workspaceId}\n repoUrl={repoUrl}\n repoLocalPath={repoLocalPath}\n commit={commit}\n agentId={agentId}\n profile={profile}\n />\n )}\n />\n <SecurityScanList vibeId={vibeId} agentId={agentId} profile={profile} />\n </PluginGate>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAgCA,SAAgB,EAAiB,EAC/B,WACA,YACA,aAAU,aACuB;CAIjC,IAAM,EAAE,MAAM,MAAa,EAAgB;EACzC,WAAW,EAAE,IAAI,GAAQ;EACzB,MAAM,CAAC;EACR,CAAC,EACI,IAAO,GAAU,MACjB,IAAc,GAAM,eAAe,IACnC,IAAU,GAAM,aAAa,IAC7B,IAAgB,GAAM,QAAQ,IAC9B,IAAS,GAAM,aAAa;AAElC,QACE,kBAAC,OAAD;EAAK,eAAY;EAAqB,WAAU;YAAhD,CACE,kBAAC,UAAD;GAAQ,WAAU;aAAlB,CACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAAQ,WAAU,8BAA+B,CAAA;IAC7C,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAA4C;KAAa,CAAA,EACvE,kBAAC,KAAD;KAAG,WAAU;eAAqC;KAG9C,CAAA,CACA;MACC;MAET,kBAAC,GAAD;GACW;GACT,UAAU,CAAC,EAAsB;GACjC,MAAK;GACL,SAAQ;GACR,OAAM;GACN,aAAY;aANd,CAQE,kBAAC,GAAD;IACE,UAAU;IACD;IACT,OAAM;IACN,aAAY;IACZ,wBAAwB,MACtB,kBAAC,GAAD;KACO;KACG;KACK;KACJ;KACM;KACP;KACC;KACA;KACT,CAAA;IAEJ,CAAA,EACF,kBAAC,GAAD;IAA0B;IAAiB;IAAkB;IAAW,CAAA,CAC7D;KACT"}
@@ -1,8 +1,8 @@
1
1
  import { SecurityAgentError as e, securityAgent as t } from "./agentClient.js";
2
2
  import { useApolloClient as n } from "@apollo/client/react";
3
- import { useQuery as r } from "@tanstack/react-query";
3
+ import { useMutation as r, useQuery as i, useQueryClient as a } from "@tanstack/react-query";
4
4
  //#region src/components/security/hooks.ts
5
- function i(e, ...t) {
5
+ function o(e, ...t) {
6
6
  return [
7
7
  "security",
8
8
  e.agentId ?? "_",
@@ -10,23 +10,40 @@ function i(e, ...t) {
10
10
  ...t
11
11
  ];
12
12
  }
13
- function a(a, o, s = 20) {
13
+ function s(r, a, s = 20) {
14
14
  let c = n();
15
- return r({
16
- queryKey: i(a, "recent-scans", o, s),
17
- enabled: !!a.agentId && !!o,
15
+ return i({
16
+ queryKey: o(r, "recent-scans", a, s),
17
+ enabled: !!r.agentId && !!a,
18
18
  queryFn: async () => {
19
- if (!a.agentId) throw new e("INVALID", 0, "no agent opts");
19
+ if (!r.agentId) throw new e("INVALID", 0, "no agent opts");
20
20
  let n = {
21
- agentId: a.agentId,
22
- profile: a.profile,
21
+ agentId: r.agentId,
22
+ profile: r.profile,
23
+ apolloClient: c
24
+ };
25
+ return t.listRecentScanRuns(n, a, s);
26
+ }
27
+ });
28
+ }
29
+ function c(i) {
30
+ let s = a(), c = n();
31
+ return r({
32
+ mutationFn: async (n) => {
33
+ if (!i.agentId) throw new e("INVALID", 0, "no agent opts");
34
+ let r = {
35
+ agentId: i.agentId,
36
+ profile: i.profile,
23
37
  apolloClient: c
24
38
  };
25
- return t.listRecentScanRuns(n, o, s);
39
+ return t.startScan(r, n);
40
+ },
41
+ onSuccess: () => {
42
+ s.invalidateQueries({ queryKey: o(i) });
26
43
  }
27
44
  });
28
45
  }
29
46
  //#endregion
30
- export { a as useSecurityRecentScansQuery };
47
+ export { s as useSecurityRecentScansQuery, c as useStartSecurityScanMutation };
31
48
 
32
49
  //# sourceMappingURL=hooks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","names":[],"sources":["../../../src/components/security/hooks.ts"],"sourcesContent":["/**\n * React Query hooks over the security agent GraphQL proxy.\n *\n * F4 Wave C: rewired off the direct browser→agent tunnel onto the svc\n * GraphQL proxy (`agentSecurityScanProxy` / `agentSecurityScanMutate`).\n * Cache keys still include the agent identity (agentId + profile) so\n * two simultaneously-active vibes against different agents stay\n * isolated. Mirrors the layout of `src/hooks/useGitops.ts`.\n */\nimport {\n useMutation,\n useQuery,\n useQueryClient,\n type UseMutationResult,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useApolloClient } from '@apollo/client/react';\n\nimport {\n securityAgent,\n SecurityAgentError,\n type FindingsFilter,\n type FindingsPage,\n type SecurityAgentOpts,\n type SecurityProvidersByStage,\n type SecurityScanRun,\n type StartScanInput,\n type StartScanResult,\n} from './agentClient';\n\nexport interface UseSecurityAgentContext {\n /** Required: canonical profile name. */\n profile: string;\n /** Required: agent id — scopes cache + passes through to svc proxy. */\n agentId: string | null;\n}\n\nfunction key(ctx: UseSecurityAgentContext, ...rest: unknown[]): unknown[] {\n return ['security', ctx.agentId ?? '_', ctx.profile, ...rest];\n}\n\nexport function useSecurityProvidersQuery(\n ctx: UseSecurityAgentContext\n): UseQueryResult<SecurityProvidersByStage, SecurityAgentError> {\n const apolloClient = useApolloClient();\n return useQuery({\n queryKey: key(ctx, 'providers'),\n enabled: !!ctx.agentId,\n queryFn: async () => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.listProviders(opts);\n },\n });\n}\n\nexport function useSecurityFindingsQuery(\n ctx: UseSecurityAgentContext,\n filter: FindingsFilter\n): UseQueryResult<FindingsPage, SecurityAgentError> {\n const apolloClient = useApolloClient();\n return useQuery({\n queryKey: key(ctx, 'findings', filter.vibeId, filter.severity, filter.status, filter.limit),\n enabled: !!ctx.agentId,\n queryFn: async () => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.listFindings(opts, filter);\n },\n });\n}\n\nexport function useSecurityRecentScansQuery(\n ctx: UseSecurityAgentContext,\n vibeId: string,\n limit = 20\n): UseQueryResult<SecurityScanRun[], SecurityAgentError> {\n const apolloClient = useApolloClient();\n return useQuery({\n queryKey: key(ctx, 'recent-scans', vibeId, limit),\n enabled: !!ctx.agentId && !!vibeId,\n queryFn: async () => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.listRecentScanRuns(opts, vibeId, limit);\n },\n });\n}\n\nexport function useStartSecurityScanMutation(\n ctx: UseSecurityAgentContext\n): UseMutationResult<StartScanResult, SecurityAgentError, StartScanInput> {\n const qc = useQueryClient();\n const apolloClient = useApolloClient();\n return useMutation({\n mutationFn: async (input: StartScanInput) => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.startScan(opts, input);\n },\n onSuccess: () => {\n void qc.invalidateQueries({ queryKey: key(ctx) });\n },\n });\n}\n"],"mappings":";;;;AAqCA,SAAS,EAAI,GAA8B,GAAG,GAA4B;AACxE,QAAO;EAAC;EAAY,EAAI,WAAW;EAAK,EAAI;EAAS,GAAG;EAAK;;AAkC/D,SAAgB,EACd,GACA,GACA,IAAQ,IAC+C;CACvD,IAAM,IAAe,GAAiB;AACtC,QAAO,EAAS;EACd,UAAU,EAAI,GAAK,gBAAgB,GAAQ,EAAM;EACjD,SAAS,CAAC,CAAC,EAAI,WAAW,CAAC,CAAC;EAC5B,SAAS,YAAY;AACnB,OAAI,CAAC,EAAI,QAAS,OAAM,IAAI,EAAmB,WAAW,GAAG,gBAAgB;GAC7E,IAAM,IAA0B;IAAE,SAAS,EAAI;IAAS,SAAS,EAAI;IAAS;IAAc;AAC5F,UAAO,EAAc,mBAAmB,GAAM,GAAQ,EAAM;;EAE/D,CAAC"}
1
+ {"version":3,"file":"hooks.js","names":[],"sources":["../../../src/components/security/hooks.ts"],"sourcesContent":["/**\n * React Query hooks over the security agent GraphQL proxy.\n *\n * F4 Wave C: rewired off the direct browser→agent tunnel onto the svc\n * GraphQL proxy (`agentSecurityScanProxy` / `agentSecurityScanMutate`).\n * Cache keys still include the agent identity (agentId + profile) so\n * two simultaneously-active vibes against different agents stay\n * isolated. Mirrors the layout of `src/hooks/useGitops.ts`.\n */\nimport {\n useMutation,\n useQuery,\n useQueryClient,\n type UseMutationResult,\n type UseQueryResult,\n} from '@tanstack/react-query';\nimport { useApolloClient } from '@apollo/client/react';\n\nimport {\n securityAgent,\n SecurityAgentError,\n type FindingsFilter,\n type FindingsPage,\n type SecurityAgentOpts,\n type SecurityProvidersByStage,\n type SecurityScanRun,\n type StartScanInput,\n type StartScanResult,\n} from './agentClient';\n\nexport interface UseSecurityAgentContext {\n /** Required: canonical profile name. */\n profile: string;\n /** Required: agent id — scopes cache + passes through to svc proxy. */\n agentId: string | null;\n}\n\nfunction key(ctx: UseSecurityAgentContext, ...rest: unknown[]): unknown[] {\n return ['security', ctx.agentId ?? '_', ctx.profile, ...rest];\n}\n\nexport function useSecurityProvidersQuery(\n ctx: UseSecurityAgentContext\n): UseQueryResult<SecurityProvidersByStage, SecurityAgentError> {\n const apolloClient = useApolloClient();\n return useQuery({\n queryKey: key(ctx, 'providers'),\n enabled: !!ctx.agentId,\n queryFn: async () => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.listProviders(opts);\n },\n });\n}\n\nexport function useSecurityFindingsQuery(\n ctx: UseSecurityAgentContext,\n filter: FindingsFilter\n): UseQueryResult<FindingsPage, SecurityAgentError> {\n const apolloClient = useApolloClient();\n return useQuery({\n queryKey: key(ctx, 'findings', filter.vibeId, filter.severity, filter.status, filter.limit),\n enabled: !!ctx.agentId,\n queryFn: async () => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.listFindings(opts, filter);\n },\n });\n}\n\nexport function useSecurityRecentScansQuery(\n ctx: UseSecurityAgentContext,\n vibeId: string,\n limit = 20\n): UseQueryResult<SecurityScanRun[], SecurityAgentError> {\n const apolloClient = useApolloClient();\n return useQuery({\n queryKey: key(ctx, 'recent-scans', vibeId, limit),\n enabled: !!ctx.agentId && !!vibeId,\n queryFn: async () => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.listRecentScanRuns(opts, vibeId, limit);\n },\n });\n}\n\nexport function useStartSecurityScanMutation(\n ctx: UseSecurityAgentContext\n): UseMutationResult<StartScanResult, SecurityAgentError, StartScanInput> {\n const qc = useQueryClient();\n const apolloClient = useApolloClient();\n return useMutation({\n mutationFn: async (input: StartScanInput) => {\n if (!ctx.agentId) throw new SecurityAgentError('INVALID', 0, 'no agent opts');\n const opts: SecurityAgentOpts = { agentId: ctx.agentId, profile: ctx.profile, apolloClient };\n return securityAgent.startScan(opts, input);\n },\n onSuccess: () => {\n void qc.invalidateQueries({ queryKey: key(ctx) });\n },\n });\n}\n"],"mappings":";;;;AAqCA,SAAS,EAAI,GAA8B,GAAG,GAA4B;AACxE,QAAO;EAAC;EAAY,EAAI,WAAW;EAAK,EAAI;EAAS,GAAG;EAAK;;AAkC/D,SAAgB,EACd,GACA,GACA,IAAQ,IAC+C;CACvD,IAAM,IAAe,GAAiB;AACtC,QAAO,EAAS;EACd,UAAU,EAAI,GAAK,gBAAgB,GAAQ,EAAM;EACjD,SAAS,CAAC,CAAC,EAAI,WAAW,CAAC,CAAC;EAC5B,SAAS,YAAY;AACnB,OAAI,CAAC,EAAI,QAAS,OAAM,IAAI,EAAmB,WAAW,GAAG,gBAAgB;GAC7E,IAAM,IAA0B;IAAE,SAAS,EAAI;IAAS,SAAS,EAAI;IAAS;IAAc;AAC5F,UAAO,EAAc,mBAAmB,GAAM,GAAQ,EAAM;;EAE/D,CAAC;;AAGJ,SAAgB,EACd,GACwE;CACxE,IAAM,IAAK,GAAgB,EACrB,IAAe,GAAiB;AACtC,QAAO,EAAY;EACjB,YAAY,OAAO,MAA0B;AAC3C,OAAI,CAAC,EAAI,QAAS,OAAM,IAAI,EAAmB,WAAW,GAAG,gBAAgB;GAC7E,IAAM,IAA0B;IAAE,SAAS,EAAI;IAAS,SAAS,EAAI;IAAS;IAAc;AAC5F,UAAO,EAAc,UAAU,GAAM,EAAM;;EAE7C,iBAAiB;AACV,KAAG,kBAAkB,EAAE,UAAU,EAAI,EAAI,EAAE,CAAC;;EAEpD,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import "./agentClient.js";
2
2
  import "./hooks.js";
3
3
  import "./SecurityScanList.js";
4
+ import "./SecurityRunButton.js";
4
5
  import "./SecurityTabPanel.js";
5
6
  import "./SecurityEmptyState.js";
6
7
  import "./types.js";
@@ -30,6 +30,21 @@ var n = "@vibecontrols/vibe-plugin-session-manager", r = [
30
30
  "@vibecontrols/vibe-plugin-security-incident",
31
31
  "@vibecontrols/vibe-plugin-security-archive"
32
32
  ], d = {
33
+ "@vibecontrols/vibe-plugin-security-onboard": "repo.onboard",
34
+ "@vibecontrols/vibe-plugin-security-developer-local": "developer.local",
35
+ "@vibecontrols/vibe-plugin-security-secrets-pr": "pull_request.fast",
36
+ "@vibecontrols/vibe-plugin-security-sast-deep": "pull_request.deep",
37
+ "@vibecontrols/vibe-plugin-security-scorecard": "main.merge",
38
+ "@vibecontrols/vibe-plugin-security-sbom-build": "build",
39
+ "@vibecontrols/vibe-plugin-security-package-publish": "package.publish",
40
+ "@vibecontrols/vibe-plugin-security-dast-preview": "deploy.preview",
41
+ "@vibecontrols/vibe-plugin-security-deploy-alpha": "deploy.alpha",
42
+ "@vibecontrols/vibe-plugin-security-release-gate": "promote.prod",
43
+ "@vibecontrols/vibe-plugin-security-runtime": "runtime.continuous",
44
+ "@vibecontrols/vibe-plugin-security-rescan": "scheduled.rescan",
45
+ "@vibecontrols/vibe-plugin-security-incident": "incident.response",
46
+ "@vibecontrols/vibe-plugin-security-archive": "archive.offboard"
47
+ }, f = {
33
48
  [e]: {
34
49
  packageName: e,
35
50
  displayName: "AI Orchestrator",
@@ -301,8 +316,8 @@ var n = "@vibecontrols/vibe-plugin-session-manager", r = [
301
316
  category: "security-provider"
302
317
  }
303
318
  };
304
- function f(e) {
305
- return d[e] ?? {
319
+ function p(e) {
320
+ return f[e] ?? {
306
321
  packageName: e,
307
322
  displayName: e.replace("@vibecontrols/vibe-plugin-", ""),
308
323
  description: "VibeControls agent plugin.",
@@ -310,6 +325,6 @@ function f(e) {
310
325
  };
311
326
  }
312
327
  //#endregion
313
- export { e as AI_CORE_PACKAGE, t as AI_PROVIDER_PACKAGES, o as GIT_PACKAGE, s as GRAPHQL_PLAYGROUND_PACKAGE, i as PLAN_META_PACKAGE, a as PLAN_PLANNOTATOR_PACKAGE, d as PLUGIN_CATALOG, l as SECURITY_META_PACKAGE, u as SECURITY_PROVIDER_PACKAGES, n as SESSION_MANAGER_PACKAGE, r as SESSION_PROVIDER_PACKAGES, f as getPluginMeta };
328
+ export { e as AI_CORE_PACKAGE, t as AI_PROVIDER_PACKAGES, o as GIT_PACKAGE, s as GRAPHQL_PLAYGROUND_PACKAGE, i as PLAN_META_PACKAGE, a as PLAN_PLANNOTATOR_PACKAGE, f as PLUGIN_CATALOG, l as SECURITY_META_PACKAGE, u as SECURITY_PROVIDER_PACKAGES, d as SECURITY_STAGE_BY_PACKAGE, n as SESSION_MANAGER_PACKAGE, r as SESSION_PROVIDER_PACKAGES, p as getPluginMeta };
314
329
 
315
330
  //# sourceMappingURL=pluginCatalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pluginCatalog.js","names":[],"sources":["../../src/constants/pluginCatalog.ts"],"sourcesContent":["/**\n * Plugin catalog — UI-facing metadata for vibecontrols-agent plugins.\n *\n * Source of truth for install state is the agent's profile-prefixed\n * `/api/profiles/<profile>/plugins/available` endpoint (proxied via\n * GraphQL `agentPlugins`). This module only mirrors the display\n * metadata the UI needs when prompting a user to install.\n */\n\nexport interface PluginMeta {\n packageName: string;\n displayName: string;\n description: string;\n category:\n | 'ai-core'\n | 'ai-provider'\n | 'plan-core'\n | 'plan-provider'\n | 'session-core'\n | 'session-provider'\n | 'tunnel'\n | 'vcs'\n | 'api-playground'\n | 'gitops-core'\n | 'gitops-provider'\n | 'security-core'\n | 'security-provider'\n | 'tool';\n}\n\n// ── AI ─────────────────────────────────────────────────────────────────────\n\nexport const AI_CORE_PACKAGE = '@vibecontrols/vibe-plugin-ai';\n\n/**\n * Supported AI provider harnesses. Eight orchestrator-backed providers we\n * ship + validate end-to-end (claude, codex, gemini, opencode + cursor,\n * openrouter, minimax, ollama added 2026.507). The wider set in\n * `PLUGIN_CATALOG` below is retained for `getPluginMeta` lookups so legacy\n * installs still resolve display metadata, but the picker + gate only\n * offer the supported eight. See ~/products/dev/platform/context/ai-plugins/\n * PROVIDERS.md for the full status matrix.\n */\nexport const AI_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-ai-claude',\n '@vibecontrols/vibe-plugin-ai-codex',\n '@vibecontrols/vibe-plugin-ai-gemini',\n '@vibecontrols/vibe-plugin-ai-opencode',\n '@vibecontrols/vibe-plugin-ai-cursor',\n '@vibecontrols/vibe-plugin-ai-openrouter',\n '@vibecontrols/vibe-plugin-ai-minimax',\n '@vibecontrols/vibe-plugin-ai-ollama',\n] as const;\n\n/**\n * Full set of supported AI packages including the orchestrator. Useful for\n * server-side allow-listing or detection scans that need to recognise an\n * installed plugin even if the UI doesn't currently offer it.\n */\nexport const SUPPORTED_AI_PACKAGES = [AI_CORE_PACKAGE, ...AI_PROVIDER_PACKAGES] as const;\n\n// ── Sessions ───────────────────────────────────────────────────────────────\n\nexport const SESSION_MANAGER_PACKAGE = '@vibecontrols/vibe-plugin-session-manager';\n\nexport const SESSION_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-session-tmux',\n '@vibecontrols/vibe-plugin-session-wezterm',\n '@vibecontrols/vibe-plugin-session-zellij',\n] as const;\n\n// ── Plan ──────────────────────────────────────────────────────────────────\n\nexport const PLAN_META_PACKAGE = '@vibecontrols/vibe-plugin-plan';\nexport const PLAN_PLANNOTATOR_PACKAGE = '@vibecontrols/vibe-plugin-plan-plannotator';\n\nexport const PLAN_PROVIDER_PACKAGES = [PLAN_PLANNOTATOR_PACKAGE] as const;\n\n// ── VCS & API Playground ───────────────────────────────────────────────────\n\nexport const GIT_PACKAGE = '@vibecontrols/vibe-plugin-tool-git';\nexport const GRAPHQL_PLAYGROUND_PACKAGE = '@vibecontrols/vibe-plugin-tool-graphiql';\n\n// ── GitOps ─────────────────────────────────────────────────────────────────\n\nexport const GITOPS_META_PACKAGE = '@vibecontrols/vibe-plugin-gitops';\n\nexport const GITOPS_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-gitops-github',\n '@vibecontrols/vibe-plugin-gitops-gitlab',\n '@vibecontrols/vibe-plugin-gitops-bitbucket',\n '@vibecontrols/vibe-plugin-gitops-azdevops',\n] as const;\n\n// ── Security ───────────────────────────────────────────────────────────────\n\nexport const SECURITY_META_PACKAGE = '@vibecontrols/vibe-plugin-security';\n\n/**\n * Per-stage security provider plugins. Each entry maps a stage from\n * the 14-stage security lifecycle (see vibecontrols-specs/security/)\n * to its provider package. Three are published today (secrets-pr,\n * sbom-build, release-gate); the other 11 are placeholders that will\n * be created in upcoming waves of the security plugin rollout.\n */\nexport const SECURITY_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-security-onboard',\n '@vibecontrols/vibe-plugin-security-developer-local',\n '@vibecontrols/vibe-plugin-security-secrets-pr',\n '@vibecontrols/vibe-plugin-security-sast-deep',\n '@vibecontrols/vibe-plugin-security-scorecard',\n '@vibecontrols/vibe-plugin-security-sbom-build',\n '@vibecontrols/vibe-plugin-security-package-publish',\n '@vibecontrols/vibe-plugin-security-dast-preview',\n '@vibecontrols/vibe-plugin-security-deploy-alpha',\n '@vibecontrols/vibe-plugin-security-release-gate',\n '@vibecontrols/vibe-plugin-security-runtime',\n '@vibecontrols/vibe-plugin-security-rescan',\n '@vibecontrols/vibe-plugin-security-incident',\n '@vibecontrols/vibe-plugin-security-archive',\n] as const;\n\n/**\n * Maps each security provider package to the lifecycle stage it\n * registers against. The stage strings match the SecurityStage enum\n * in @vibecontrols/vibe-plugin-security/types.\n */\nexport const SECURITY_STAGE_BY_PACKAGE: Record<string, string> = {\n '@vibecontrols/vibe-plugin-security-onboard': 'repo.onboard',\n '@vibecontrols/vibe-plugin-security-developer-local': 'developer.local',\n '@vibecontrols/vibe-plugin-security-secrets-pr': 'pull_request.fast',\n '@vibecontrols/vibe-plugin-security-sast-deep': 'pull_request.deep',\n '@vibecontrols/vibe-plugin-security-scorecard': 'main.merge',\n '@vibecontrols/vibe-plugin-security-sbom-build': 'build',\n '@vibecontrols/vibe-plugin-security-package-publish': 'package.publish',\n '@vibecontrols/vibe-plugin-security-dast-preview': 'deploy.preview',\n '@vibecontrols/vibe-plugin-security-deploy-alpha': 'deploy.alpha',\n '@vibecontrols/vibe-plugin-security-release-gate': 'promote.prod',\n '@vibecontrols/vibe-plugin-security-runtime': 'runtime.continuous',\n '@vibecontrols/vibe-plugin-security-rescan': 'scheduled.rescan',\n '@vibecontrols/vibe-plugin-security-incident': 'incident.response',\n '@vibecontrols/vibe-plugin-security-archive': 'archive.offboard',\n};\n\n// ── Metadata map ───────────────────────────────────────────────────────────\n\nexport const PLUGIN_CATALOG: Record<string, PluginMeta> = {\n [AI_CORE_PACKAGE]: {\n packageName: AI_CORE_PACKAGE,\n displayName: 'AI Orchestrator',\n description: 'Routes prompts and sessions across installed AI provider plugins.',\n category: 'ai-core',\n },\n '@vibecontrols/vibe-plugin-ai-claude': {\n packageName: '@vibecontrols/vibe-plugin-ai-claude',\n displayName: 'Claude Code',\n description: 'Anthropic Claude Code agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-codex': {\n packageName: '@vibecontrols/vibe-plugin-ai-codex',\n displayName: 'OpenAI Codex',\n description: 'OpenAI Codex CLI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-copilot': {\n packageName: '@vibecontrols/vibe-plugin-ai-copilot',\n displayName: 'GitHub Copilot',\n description: 'GitHub Copilot agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-gemini': {\n packageName: '@vibecontrols/vibe-plugin-ai-gemini',\n displayName: 'Google Gemini',\n description: 'Google Gemini / Vertex AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-opencode': {\n packageName: '@vibecontrols/vibe-plugin-ai-opencode',\n displayName: 'OpenCode',\n description: 'OpenCode agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-cursor': {\n packageName: '@vibecontrols/vibe-plugin-ai-cursor',\n displayName: 'Cursor',\n description: 'Cursor agent provider (CLI + SDK).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-openrouter': {\n packageName: '@vibecontrols/vibe-plugin-ai-openrouter',\n displayName: 'OpenRouter',\n description: 'OpenRouter aggregator (300+ models, SDK only).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-minimax': {\n packageName: '@vibecontrols/vibe-plugin-ai-minimax',\n displayName: 'Minimax',\n description: 'Minimax provider (CLI + Anthropic-compatible SDK).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-ollama': {\n packageName: '@vibecontrols/vibe-plugin-ai-ollama',\n displayName: 'Ollama',\n description: 'Ollama Cloud + self-hosted (CLI + SDK).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-aider': {\n packageName: '@vibecontrols/vibe-plugin-ai-aider',\n displayName: 'Aider',\n description: 'Aider AI pair-programmer provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-crush': {\n packageName: '@vibecontrols/vibe-plugin-ai-crush',\n displayName: 'Crush',\n description: 'Crush AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-goose': {\n packageName: '@vibecontrols/vibe-plugin-ai-goose',\n displayName: 'Goose',\n description: 'Block Goose AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-pi': {\n packageName: '@vibecontrols/vibe-plugin-ai-pi',\n displayName: 'Pi',\n description: 'Pi AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-plandex': {\n packageName: '@vibecontrols/vibe-plugin-ai-plandex',\n displayName: 'Plandex',\n description: 'Plandex AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-amp': {\n packageName: '@vibecontrols/vibe-plugin-ai-amp',\n displayName: 'Amp',\n description: 'Sourcegraph Amp AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-openai-compat': {\n packageName: '@vibecontrols/vibe-plugin-ai-openai-compat',\n displayName: 'OpenAI-compatible',\n description: 'Bring-your-own OpenAI-compatible endpoint provider.',\n category: 'ai-provider',\n },\n [SESSION_MANAGER_PACKAGE]: {\n packageName: SESSION_MANAGER_PACKAGE,\n displayName: 'Session Manager',\n description: 'Unified session manager that routes across tmux / WezTerm / Zellij.',\n category: 'session-core',\n },\n '@vibecontrols/vibe-plugin-session-tmux': {\n packageName: '@vibecontrols/vibe-plugin-session-tmux',\n displayName: 'tmux',\n description: 'tmux terminal multiplexer provider (lightweight, universal).',\n category: 'session-provider',\n },\n '@vibecontrols/vibe-plugin-session-wezterm': {\n packageName: '@vibecontrols/vibe-plugin-session-wezterm',\n displayName: 'WezTerm',\n description: 'WezTerm multiplexer provider with rich rendering.',\n category: 'session-provider',\n },\n '@vibecontrols/vibe-plugin-session-zellij': {\n packageName: '@vibecontrols/vibe-plugin-session-zellij',\n displayName: 'Zellij',\n description: 'Zellij multiplexer provider with workspace layouts.',\n category: 'session-provider',\n },\n [GIT_PACKAGE]: {\n packageName: GIT_PACKAGE,\n displayName: 'Visual Git (Ungit)',\n description: 'Ungit visual git client. Required for the Git UI sub-tab.',\n category: 'vcs',\n },\n [GRAPHQL_PLAYGROUND_PACKAGE]: {\n packageName: GRAPHQL_PLAYGROUND_PACKAGE,\n displayName: 'GraphQL Playground',\n description: 'GraphiQL-powered GraphQL playground.',\n category: 'api-playground',\n },\n [PLAN_META_PACKAGE]: {\n packageName: PLAN_META_PACKAGE,\n displayName: 'Plan Orchestrator',\n description: 'Routes plan sessions to a registered provider (Plannotator etc.).',\n category: 'plan-core',\n },\n [PLAN_PLANNOTATOR_PACKAGE]: {\n packageName: PLAN_PLANNOTATOR_PACKAGE,\n displayName: 'Plannotator',\n description: 'Wraps the upstream plannotator CLI for plan review inside vibecontrols.',\n category: 'plan-provider',\n },\n [GITOPS_META_PACKAGE]: {\n packageName: GITOPS_META_PACKAGE,\n displayName: 'GitOps Orchestrator',\n description:\n 'Routes repo / PR / CI / security queries to a registered provider (GitHub, GitLab, Bitbucket, Azure DevOps).',\n category: 'gitops-core',\n },\n '@vibecontrols/vibe-plugin-gitops-github': {\n packageName: '@vibecontrols/vibe-plugin-gitops-github',\n displayName: 'GitHub',\n description: 'GitHub provider for GitOps (REST v3 + GraphQL v4).',\n category: 'gitops-provider',\n },\n '@vibecontrols/vibe-plugin-gitops-gitlab': {\n packageName: '@vibecontrols/vibe-plugin-gitops-gitlab',\n displayName: 'GitLab',\n description: 'GitLab provider for GitOps (REST v4, supports self-hosted).',\n category: 'gitops-provider',\n },\n '@vibecontrols/vibe-plugin-gitops-bitbucket': {\n packageName: '@vibecontrols/vibe-plugin-gitops-bitbucket',\n displayName: 'Bitbucket Cloud',\n description: 'Bitbucket Cloud provider for GitOps (REST v2).',\n category: 'gitops-provider',\n },\n '@vibecontrols/vibe-plugin-gitops-azdevops': {\n packageName: '@vibecontrols/vibe-plugin-gitops-azdevops',\n displayName: 'Azure DevOps',\n description: 'Azure DevOps Services provider for GitOps (REST 7.1).',\n category: 'gitops-provider',\n },\n [SECURITY_META_PACKAGE]: {\n packageName: SECURITY_META_PACKAGE,\n displayName: 'Security Orchestrator',\n description: 'Routes security scans across installed per-stage security provider plugins.',\n category: 'security-core',\n },\n '@vibecontrols/vibe-plugin-security-onboard': {\n packageName: '@vibecontrols/vibe-plugin-security-onboard',\n displayName: 'Repo Onboard',\n description:\n 'Detects repo profile (frontend/backend/cli/mcp/...) and sets default security policy.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-developer-local': {\n packageName: '@vibecontrols/vibe-plugin-security-developer-local',\n displayName: 'Developer Local',\n description: 'Pre-commit Gitleaks + Semgrep --quick on the developer machine.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-secrets-pr': {\n packageName: '@vibecontrols/vibe-plugin-security-secrets-pr',\n displayName: 'Gitleaks (PR Secrets)',\n description: 'Gitleaks-backed secret scanner for the pull_request.fast lifecycle stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-sast-deep': {\n packageName: '@vibecontrols/vibe-plugin-security-sast-deep',\n displayName: 'Semgrep + OSV (Deep PR)',\n description: 'Full Semgrep + osv-scanner sweep for the pull_request.deep lifecycle stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-scorecard': {\n packageName: '@vibecontrols/vibe-plugin-security-scorecard',\n displayName: 'OpenSSF Scorecard',\n description:\n 'OpenSSF Scorecard checks at main.merge — branch protection, signed commits, dep update tools.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-sbom-build': {\n packageName: '@vibecontrols/vibe-plugin-security-sbom-build',\n displayName: 'Syft + Grype (SBOM Build)',\n description: 'Generates CycloneDX SBOM with Syft, scans it with Grype at the build stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-package-publish': {\n packageName: '@vibecontrols/vibe-plugin-security-package-publish',\n displayName: 'Cosign + SLSA (Publish)',\n description: 'Cosign signing + SLSA provenance generator for the package.publish stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-dast-preview': {\n packageName: '@vibecontrols/vibe-plugin-security-dast-preview',\n displayName: 'OWASP ZAP (DAST Preview)',\n description: 'OWASP ZAP baseline scan against preview deploy URL.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-deploy-alpha': {\n packageName: '@vibecontrols/vibe-plugin-security-deploy-alpha',\n displayName: 'Alpha Deploy Smoke',\n description: 'TLS + security-header smoke checks against the alpha environment.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-release-gate': {\n packageName: '@vibecontrols/vibe-plugin-security-release-gate',\n displayName: 'OPA Release Gate',\n description:\n 'Agent-local policy decision for the promote.prod stage — blocks releases that violate the gate.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-runtime': {\n packageName: '@vibecontrols/vibe-plugin-security-runtime',\n displayName: 'Runtime (Trivy + kube-bench)',\n description: 'Continuous runtime checks — image drift, K8s misconfig.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-rescan': {\n packageName: '@vibecontrols/vibe-plugin-security-rescan',\n displayName: 'Scheduled Rescan',\n description: 'Nightly Grype rescan with EPSS enrichment against the latest SBOM.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-incident': {\n packageName: '@vibecontrols/vibe-plugin-security-incident',\n displayName: 'Incident Response',\n description: 'Targeted CVE + secret blast-radius scan for active incidents.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-archive': {\n packageName: '@vibecontrols/vibe-plugin-security-archive',\n displayName: 'Archive / Offboard',\n description:\n 'Writes a retention tombstone and cleans up local security cache when a vibe is archived.',\n category: 'security-provider',\n },\n};\n\nexport function getPluginMeta(packageName: string): PluginMeta {\n return (\n PLUGIN_CATALOG[packageName] ?? {\n packageName,\n displayName: packageName.replace('@vibecontrols/vibe-plugin-', ''),\n description: 'VibeControls agent plugin.',\n category: 'tool',\n }\n );\n}\n"],"mappings":";AAgCA,IAAa,IAAkB,gCAWlB,IAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAOoC,CAAkB,GAAG,EAAqB;AAI/E,IAAa,IAA0B,6CAE1B,IAA4B;CACvC;CACA;CACA;CACD,EAIY,IAAoB,kCACpB,IAA2B,8CAM3B,IAAc,sCACd,IAA6B,2CAI7B,IAAsB,oCAWtB,IAAwB,sCASxB,IAA6B;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EA0BY,IAA6C;EACvD,IAAkB;EACjB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,wCAAwC;EACtC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,yCAAyC;EACvC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,2CAA2C;EACzC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,wCAAwC;EACtC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mCAAmC;EACjC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,wCAAwC;EACtC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,oCAAoC;EAClC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAA0B;EACzB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,0CAA0C;EACxC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,6CAA6C;EAC3C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,4CAA4C;EAC1C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAc;EACb,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAA6B;EAC5B,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAoB;EACnB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAA2B;EAC1B,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAsB;EACrB,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,2CAA2C;EACzC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,2CAA2C;EACzC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,6CAA6C;EAC3C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAwB;EACvB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,sDAAsD;EACpD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,iDAAiD;EAC/C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,gDAAgD;EAC9C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,gDAAgD;EAC9C,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,iDAAiD;EAC/C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sDAAsD;EACpD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mDAAmD;EACjD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mDAAmD;EACjD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mDAAmD;EACjD,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,6CAA6C;EAC3C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,+CAA+C;EAC7C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACF;AAED,SAAgB,EAAc,GAAiC;AAC7D,QACE,EAAe,MAAgB;EAC7B;EACA,aAAa,EAAY,QAAQ,8BAA8B,GAAG;EAClE,aAAa;EACb,UAAU;EACX"}
1
+ {"version":3,"file":"pluginCatalog.js","names":[],"sources":["../../src/constants/pluginCatalog.ts"],"sourcesContent":["/**\n * Plugin catalog — UI-facing metadata for vibecontrols-agent plugins.\n *\n * Source of truth for install state is the agent's profile-prefixed\n * `/api/profiles/<profile>/plugins/available` endpoint (proxied via\n * GraphQL `agentPlugins`). This module only mirrors the display\n * metadata the UI needs when prompting a user to install.\n */\n\nexport interface PluginMeta {\n packageName: string;\n displayName: string;\n description: string;\n category:\n | 'ai-core'\n | 'ai-provider'\n | 'plan-core'\n | 'plan-provider'\n | 'session-core'\n | 'session-provider'\n | 'tunnel'\n | 'vcs'\n | 'api-playground'\n | 'gitops-core'\n | 'gitops-provider'\n | 'security-core'\n | 'security-provider'\n | 'tool';\n}\n\n// ── AI ─────────────────────────────────────────────────────────────────────\n\nexport const AI_CORE_PACKAGE = '@vibecontrols/vibe-plugin-ai';\n\n/**\n * Supported AI provider harnesses. Eight orchestrator-backed providers we\n * ship + validate end-to-end (claude, codex, gemini, opencode + cursor,\n * openrouter, minimax, ollama added 2026.507). The wider set in\n * `PLUGIN_CATALOG` below is retained for `getPluginMeta` lookups so legacy\n * installs still resolve display metadata, but the picker + gate only\n * offer the supported eight. See ~/products/dev/platform/context/ai-plugins/\n * PROVIDERS.md for the full status matrix.\n */\nexport const AI_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-ai-claude',\n '@vibecontrols/vibe-plugin-ai-codex',\n '@vibecontrols/vibe-plugin-ai-gemini',\n '@vibecontrols/vibe-plugin-ai-opencode',\n '@vibecontrols/vibe-plugin-ai-cursor',\n '@vibecontrols/vibe-plugin-ai-openrouter',\n '@vibecontrols/vibe-plugin-ai-minimax',\n '@vibecontrols/vibe-plugin-ai-ollama',\n] as const;\n\n/**\n * Full set of supported AI packages including the orchestrator. Useful for\n * server-side allow-listing or detection scans that need to recognise an\n * installed plugin even if the UI doesn't currently offer it.\n */\nexport const SUPPORTED_AI_PACKAGES = [AI_CORE_PACKAGE, ...AI_PROVIDER_PACKAGES] as const;\n\n// ── Sessions ───────────────────────────────────────────────────────────────\n\nexport const SESSION_MANAGER_PACKAGE = '@vibecontrols/vibe-plugin-session-manager';\n\nexport const SESSION_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-session-tmux',\n '@vibecontrols/vibe-plugin-session-wezterm',\n '@vibecontrols/vibe-plugin-session-zellij',\n] as const;\n\n// ── Plan ──────────────────────────────────────────────────────────────────\n\nexport const PLAN_META_PACKAGE = '@vibecontrols/vibe-plugin-plan';\nexport const PLAN_PLANNOTATOR_PACKAGE = '@vibecontrols/vibe-plugin-plan-plannotator';\n\nexport const PLAN_PROVIDER_PACKAGES = [PLAN_PLANNOTATOR_PACKAGE] as const;\n\n// ── VCS & API Playground ───────────────────────────────────────────────────\n\nexport const GIT_PACKAGE = '@vibecontrols/vibe-plugin-tool-git';\nexport const GRAPHQL_PLAYGROUND_PACKAGE = '@vibecontrols/vibe-plugin-tool-graphiql';\n\n// ── GitOps ─────────────────────────────────────────────────────────────────\n\nexport const GITOPS_META_PACKAGE = '@vibecontrols/vibe-plugin-gitops';\n\nexport const GITOPS_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-gitops-github',\n '@vibecontrols/vibe-plugin-gitops-gitlab',\n '@vibecontrols/vibe-plugin-gitops-bitbucket',\n '@vibecontrols/vibe-plugin-gitops-azdevops',\n] as const;\n\n// ── Security ───────────────────────────────────────────────────────────────\n\nexport const SECURITY_META_PACKAGE = '@vibecontrols/vibe-plugin-security';\n\n/**\n * Per-stage security provider plugins. Each entry maps a stage from\n * the 14-stage security lifecycle (see vibecontrols-specs/security/)\n * to its provider package. Three are published today (secrets-pr,\n * sbom-build, release-gate); the other 11 are placeholders that will\n * be created in upcoming waves of the security plugin rollout.\n */\nexport const SECURITY_PROVIDER_PACKAGES = [\n '@vibecontrols/vibe-plugin-security-onboard',\n '@vibecontrols/vibe-plugin-security-developer-local',\n '@vibecontrols/vibe-plugin-security-secrets-pr',\n '@vibecontrols/vibe-plugin-security-sast-deep',\n '@vibecontrols/vibe-plugin-security-scorecard',\n '@vibecontrols/vibe-plugin-security-sbom-build',\n '@vibecontrols/vibe-plugin-security-package-publish',\n '@vibecontrols/vibe-plugin-security-dast-preview',\n '@vibecontrols/vibe-plugin-security-deploy-alpha',\n '@vibecontrols/vibe-plugin-security-release-gate',\n '@vibecontrols/vibe-plugin-security-runtime',\n '@vibecontrols/vibe-plugin-security-rescan',\n '@vibecontrols/vibe-plugin-security-incident',\n '@vibecontrols/vibe-plugin-security-archive',\n] as const;\n\n/**\n * Maps each security provider package to the lifecycle stage it\n * registers against. The stage strings match the SecurityStage enum\n * in @vibecontrols/vibe-plugin-security/types.\n */\nexport const SECURITY_STAGE_BY_PACKAGE: Record<string, string> = {\n '@vibecontrols/vibe-plugin-security-onboard': 'repo.onboard',\n '@vibecontrols/vibe-plugin-security-developer-local': 'developer.local',\n '@vibecontrols/vibe-plugin-security-secrets-pr': 'pull_request.fast',\n '@vibecontrols/vibe-plugin-security-sast-deep': 'pull_request.deep',\n '@vibecontrols/vibe-plugin-security-scorecard': 'main.merge',\n '@vibecontrols/vibe-plugin-security-sbom-build': 'build',\n '@vibecontrols/vibe-plugin-security-package-publish': 'package.publish',\n '@vibecontrols/vibe-plugin-security-dast-preview': 'deploy.preview',\n '@vibecontrols/vibe-plugin-security-deploy-alpha': 'deploy.alpha',\n '@vibecontrols/vibe-plugin-security-release-gate': 'promote.prod',\n '@vibecontrols/vibe-plugin-security-runtime': 'runtime.continuous',\n '@vibecontrols/vibe-plugin-security-rescan': 'scheduled.rescan',\n '@vibecontrols/vibe-plugin-security-incident': 'incident.response',\n '@vibecontrols/vibe-plugin-security-archive': 'archive.offboard',\n};\n\n// ── Metadata map ───────────────────────────────────────────────────────────\n\nexport const PLUGIN_CATALOG: Record<string, PluginMeta> = {\n [AI_CORE_PACKAGE]: {\n packageName: AI_CORE_PACKAGE,\n displayName: 'AI Orchestrator',\n description: 'Routes prompts and sessions across installed AI provider plugins.',\n category: 'ai-core',\n },\n '@vibecontrols/vibe-plugin-ai-claude': {\n packageName: '@vibecontrols/vibe-plugin-ai-claude',\n displayName: 'Claude Code',\n description: 'Anthropic Claude Code agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-codex': {\n packageName: '@vibecontrols/vibe-plugin-ai-codex',\n displayName: 'OpenAI Codex',\n description: 'OpenAI Codex CLI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-copilot': {\n packageName: '@vibecontrols/vibe-plugin-ai-copilot',\n displayName: 'GitHub Copilot',\n description: 'GitHub Copilot agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-gemini': {\n packageName: '@vibecontrols/vibe-plugin-ai-gemini',\n displayName: 'Google Gemini',\n description: 'Google Gemini / Vertex AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-opencode': {\n packageName: '@vibecontrols/vibe-plugin-ai-opencode',\n displayName: 'OpenCode',\n description: 'OpenCode agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-cursor': {\n packageName: '@vibecontrols/vibe-plugin-ai-cursor',\n displayName: 'Cursor',\n description: 'Cursor agent provider (CLI + SDK).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-openrouter': {\n packageName: '@vibecontrols/vibe-plugin-ai-openrouter',\n displayName: 'OpenRouter',\n description: 'OpenRouter aggregator (300+ models, SDK only).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-minimax': {\n packageName: '@vibecontrols/vibe-plugin-ai-minimax',\n displayName: 'Minimax',\n description: 'Minimax provider (CLI + Anthropic-compatible SDK).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-ollama': {\n packageName: '@vibecontrols/vibe-plugin-ai-ollama',\n displayName: 'Ollama',\n description: 'Ollama Cloud + self-hosted (CLI + SDK).',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-aider': {\n packageName: '@vibecontrols/vibe-plugin-ai-aider',\n displayName: 'Aider',\n description: 'Aider AI pair-programmer provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-crush': {\n packageName: '@vibecontrols/vibe-plugin-ai-crush',\n displayName: 'Crush',\n description: 'Crush AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-goose': {\n packageName: '@vibecontrols/vibe-plugin-ai-goose',\n displayName: 'Goose',\n description: 'Block Goose AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-pi': {\n packageName: '@vibecontrols/vibe-plugin-ai-pi',\n displayName: 'Pi',\n description: 'Pi AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-plandex': {\n packageName: '@vibecontrols/vibe-plugin-ai-plandex',\n displayName: 'Plandex',\n description: 'Plandex AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-amp': {\n packageName: '@vibecontrols/vibe-plugin-ai-amp',\n displayName: 'Amp',\n description: 'Sourcegraph Amp AI agent provider.',\n category: 'ai-provider',\n },\n '@vibecontrols/vibe-plugin-ai-openai-compat': {\n packageName: '@vibecontrols/vibe-plugin-ai-openai-compat',\n displayName: 'OpenAI-compatible',\n description: 'Bring-your-own OpenAI-compatible endpoint provider.',\n category: 'ai-provider',\n },\n [SESSION_MANAGER_PACKAGE]: {\n packageName: SESSION_MANAGER_PACKAGE,\n displayName: 'Session Manager',\n description: 'Unified session manager that routes across tmux / WezTerm / Zellij.',\n category: 'session-core',\n },\n '@vibecontrols/vibe-plugin-session-tmux': {\n packageName: '@vibecontrols/vibe-plugin-session-tmux',\n displayName: 'tmux',\n description: 'tmux terminal multiplexer provider (lightweight, universal).',\n category: 'session-provider',\n },\n '@vibecontrols/vibe-plugin-session-wezterm': {\n packageName: '@vibecontrols/vibe-plugin-session-wezterm',\n displayName: 'WezTerm',\n description: 'WezTerm multiplexer provider with rich rendering.',\n category: 'session-provider',\n },\n '@vibecontrols/vibe-plugin-session-zellij': {\n packageName: '@vibecontrols/vibe-plugin-session-zellij',\n displayName: 'Zellij',\n description: 'Zellij multiplexer provider with workspace layouts.',\n category: 'session-provider',\n },\n [GIT_PACKAGE]: {\n packageName: GIT_PACKAGE,\n displayName: 'Visual Git (Ungit)',\n description: 'Ungit visual git client. Required for the Git UI sub-tab.',\n category: 'vcs',\n },\n [GRAPHQL_PLAYGROUND_PACKAGE]: {\n packageName: GRAPHQL_PLAYGROUND_PACKAGE,\n displayName: 'GraphQL Playground',\n description: 'GraphiQL-powered GraphQL playground.',\n category: 'api-playground',\n },\n [PLAN_META_PACKAGE]: {\n packageName: PLAN_META_PACKAGE,\n displayName: 'Plan Orchestrator',\n description: 'Routes plan sessions to a registered provider (Plannotator etc.).',\n category: 'plan-core',\n },\n [PLAN_PLANNOTATOR_PACKAGE]: {\n packageName: PLAN_PLANNOTATOR_PACKAGE,\n displayName: 'Plannotator',\n description: 'Wraps the upstream plannotator CLI for plan review inside vibecontrols.',\n category: 'plan-provider',\n },\n [GITOPS_META_PACKAGE]: {\n packageName: GITOPS_META_PACKAGE,\n displayName: 'GitOps Orchestrator',\n description:\n 'Routes repo / PR / CI / security queries to a registered provider (GitHub, GitLab, Bitbucket, Azure DevOps).',\n category: 'gitops-core',\n },\n '@vibecontrols/vibe-plugin-gitops-github': {\n packageName: '@vibecontrols/vibe-plugin-gitops-github',\n displayName: 'GitHub',\n description: 'GitHub provider for GitOps (REST v3 + GraphQL v4).',\n category: 'gitops-provider',\n },\n '@vibecontrols/vibe-plugin-gitops-gitlab': {\n packageName: '@vibecontrols/vibe-plugin-gitops-gitlab',\n displayName: 'GitLab',\n description: 'GitLab provider for GitOps (REST v4, supports self-hosted).',\n category: 'gitops-provider',\n },\n '@vibecontrols/vibe-plugin-gitops-bitbucket': {\n packageName: '@vibecontrols/vibe-plugin-gitops-bitbucket',\n displayName: 'Bitbucket Cloud',\n description: 'Bitbucket Cloud provider for GitOps (REST v2).',\n category: 'gitops-provider',\n },\n '@vibecontrols/vibe-plugin-gitops-azdevops': {\n packageName: '@vibecontrols/vibe-plugin-gitops-azdevops',\n displayName: 'Azure DevOps',\n description: 'Azure DevOps Services provider for GitOps (REST 7.1).',\n category: 'gitops-provider',\n },\n [SECURITY_META_PACKAGE]: {\n packageName: SECURITY_META_PACKAGE,\n displayName: 'Security Orchestrator',\n description: 'Routes security scans across installed per-stage security provider plugins.',\n category: 'security-core',\n },\n '@vibecontrols/vibe-plugin-security-onboard': {\n packageName: '@vibecontrols/vibe-plugin-security-onboard',\n displayName: 'Repo Onboard',\n description:\n 'Detects repo profile (frontend/backend/cli/mcp/...) and sets default security policy.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-developer-local': {\n packageName: '@vibecontrols/vibe-plugin-security-developer-local',\n displayName: 'Developer Local',\n description: 'Pre-commit Gitleaks + Semgrep --quick on the developer machine.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-secrets-pr': {\n packageName: '@vibecontrols/vibe-plugin-security-secrets-pr',\n displayName: 'Gitleaks (PR Secrets)',\n description: 'Gitleaks-backed secret scanner for the pull_request.fast lifecycle stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-sast-deep': {\n packageName: '@vibecontrols/vibe-plugin-security-sast-deep',\n displayName: 'Semgrep + OSV (Deep PR)',\n description: 'Full Semgrep + osv-scanner sweep for the pull_request.deep lifecycle stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-scorecard': {\n packageName: '@vibecontrols/vibe-plugin-security-scorecard',\n displayName: 'OpenSSF Scorecard',\n description:\n 'OpenSSF Scorecard checks at main.merge — branch protection, signed commits, dep update tools.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-sbom-build': {\n packageName: '@vibecontrols/vibe-plugin-security-sbom-build',\n displayName: 'Syft + Grype (SBOM Build)',\n description: 'Generates CycloneDX SBOM with Syft, scans it with Grype at the build stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-package-publish': {\n packageName: '@vibecontrols/vibe-plugin-security-package-publish',\n displayName: 'Cosign + SLSA (Publish)',\n description: 'Cosign signing + SLSA provenance generator for the package.publish stage.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-dast-preview': {\n packageName: '@vibecontrols/vibe-plugin-security-dast-preview',\n displayName: 'OWASP ZAP (DAST Preview)',\n description: 'OWASP ZAP baseline scan against preview deploy URL.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-deploy-alpha': {\n packageName: '@vibecontrols/vibe-plugin-security-deploy-alpha',\n displayName: 'Alpha Deploy Smoke',\n description: 'TLS + security-header smoke checks against the alpha environment.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-release-gate': {\n packageName: '@vibecontrols/vibe-plugin-security-release-gate',\n displayName: 'OPA Release Gate',\n description:\n 'Agent-local policy decision for the promote.prod stage — blocks releases that violate the gate.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-runtime': {\n packageName: '@vibecontrols/vibe-plugin-security-runtime',\n displayName: 'Runtime (Trivy + kube-bench)',\n description: 'Continuous runtime checks — image drift, K8s misconfig.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-rescan': {\n packageName: '@vibecontrols/vibe-plugin-security-rescan',\n displayName: 'Scheduled Rescan',\n description: 'Nightly Grype rescan with EPSS enrichment against the latest SBOM.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-incident': {\n packageName: '@vibecontrols/vibe-plugin-security-incident',\n displayName: 'Incident Response',\n description: 'Targeted CVE + secret blast-radius scan for active incidents.',\n category: 'security-provider',\n },\n '@vibecontrols/vibe-plugin-security-archive': {\n packageName: '@vibecontrols/vibe-plugin-security-archive',\n displayName: 'Archive / Offboard',\n description:\n 'Writes a retention tombstone and cleans up local security cache when a vibe is archived.',\n category: 'security-provider',\n },\n};\n\nexport function getPluginMeta(packageName: string): PluginMeta {\n return (\n PLUGIN_CATALOG[packageName] ?? {\n packageName,\n displayName: packageName.replace('@vibecontrols/vibe-plugin-', ''),\n description: 'VibeControls agent plugin.',\n category: 'tool',\n }\n );\n}\n"],"mappings":";AAgCA,IAAa,IAAkB,gCAWlB,IAAuB;CAClC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAOoC,CAAkB,GAAG,EAAqB;AAI/E,IAAa,IAA0B,6CAE1B,IAA4B;CACvC;CACA;CACA;CACD,EAIY,IAAoB,kCACpB,IAA2B,8CAM3B,IAAc,sCACd,IAA6B,2CAI7B,IAAsB,oCAWtB,IAAwB,sCASxB,IAA6B;CACxC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAOY,IAAoD;CAC/D,8CAA8C;CAC9C,sDAAsD;CACtD,iDAAiD;CACjD,gDAAgD;CAChD,gDAAgD;CAChD,iDAAiD;CACjD,sDAAsD;CACtD,mDAAmD;CACnD,mDAAmD;CACnD,mDAAmD;CACnD,8CAA8C;CAC9C,6CAA6C;CAC7C,+CAA+C;CAC/C,8CAA8C;CAC/C,EAIY,IAA6C;EACvD,IAAkB;EACjB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,wCAAwC;EACtC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,yCAAyC;EACvC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,2CAA2C;EACzC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,wCAAwC;EACtC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,uCAAuC;EACrC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sCAAsC;EACpC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mCAAmC;EACjC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,wCAAwC;EACtC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,oCAAoC;EAClC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAA0B;EACzB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,0CAA0C;EACxC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,6CAA6C;EAC3C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,4CAA4C;EAC1C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAc;EACb,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAA6B;EAC5B,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAoB;EACnB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAA2B;EAC1B,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAsB;EACrB,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,2CAA2C;EACzC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,2CAA2C;EACzC,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,6CAA6C;EAC3C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;EACA,IAAwB;EACvB,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,sDAAsD;EACpD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,iDAAiD;EAC/C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,gDAAgD;EAC9C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,gDAAgD;EAC9C,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,iDAAiD;EAC/C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,sDAAsD;EACpD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mDAAmD;EACjD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mDAAmD;EACjD,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,mDAAmD;EACjD,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,6CAA6C;EAC3C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,+CAA+C;EAC7C,aAAa;EACb,aAAa;EACb,aAAa;EACb,UAAU;EACX;CACD,8CAA8C;EAC5C,aAAa;EACb,aAAa;EACb,aACE;EACF,UAAU;EACX;CACF;AAED,SAAgB,EAAc,GAAiC;AAC7D,QACE,EAAe,MAAgB;EAC7B;EACA,aAAa,EAAY,QAAQ,8BAA8B,GAAG;EAClE,aAAa;EACb,UAAU;EACX"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-vibecontrols",
3
- "version": "2026.602.5",
3
+ "version": "2026.602.6",
4
4
  "description": "VibeControls microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [