@burdenoff/microfe-vibecontrols 2026.601.15 → 2026.601.16

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.
@@ -0,0 +1,140 @@
1
+ import { useUpdateAgentMutation as e } from "../../generated/wspace-operations.js";
2
+ import { useTr as t } from "../../shared/hooks/useTr.js";
3
+ import { useState as n } from "react";
4
+ import { AlertTriangle as r, Database as i, Loader2 as a, ShieldCheck as o } from "lucide-react";
5
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
6
+ //#region src/components/agents/AgentStorageConfig.tsx
7
+ var l = "rounded-lg border border-border-default bg-bg-surface p-4 sm:p-5", u = "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50", d = "w-full px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 font-mono";
8
+ function f(e) {
9
+ return e instanceof Error ? e.message : String(e);
10
+ }
11
+ function p({ agentId: p, storageAdapter: m, dbPath: h, hasStorageOptions: g, onUpdated: _ }) {
12
+ let v = t(), [y, b] = n(m ?? ""), [x, S] = n(""), [C, w] = n(h ?? ""), [T, E] = n(""), [D, O] = n(null), [k, { loading: A }] = e({ refetchQueries: ["GetAgent"] });
13
+ return /* @__PURE__ */ c("section", {
14
+ className: l,
15
+ children: [
16
+ /* @__PURE__ */ c("div", {
17
+ className: "flex items-center gap-2 mb-1",
18
+ children: [/* @__PURE__ */ s(i, { className: "size-5 text-text-secondary" }), /* @__PURE__ */ s("h3", {
19
+ className: "text-base font-semibold text-text-primary",
20
+ children: v("agentDetails.storage.title", "Storage / reuse an existing database")
21
+ })]
22
+ }),
23
+ /* @__PURE__ */ s("p", {
24
+ className: "text-xs text-text-muted mb-3",
25
+ children: v("agentDetails.storage.hint", "Point this agent at an existing same-workspace database so it reuses that data. Cross-workspace DBs won’t decrypt (per-workspace key), and two agents writing one DB concurrently can corrupt it — keep it single-writer.")
26
+ }),
27
+ /* @__PURE__ */ c("div", {
28
+ className: "grid grid-cols-2 gap-3 text-xs mb-3",
29
+ children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("span", {
30
+ className: "text-text-muted",
31
+ children: v("agentDetails.storage.currentAdapter", "Current adapter")
32
+ }), /* @__PURE__ */ s("div", {
33
+ className: "font-mono text-text-primary",
34
+ children: m || v("agentDetails.storage.default", "default")
35
+ })] }), /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("span", {
36
+ className: "text-text-muted",
37
+ children: v("agentDetails.storage.currentOptions", "Custom options")
38
+ }), /* @__PURE__ */ s("div", {
39
+ className: "font-mono text-text-primary",
40
+ children: g ? v("agentDetails.storage.set", "set") : v("agentDetails.storage.none", "none")
41
+ })] })]
42
+ }),
43
+ /* @__PURE__ */ c("div", {
44
+ className: "space-y-2",
45
+ children: [
46
+ /* @__PURE__ */ s("input", {
47
+ type: "text",
48
+ value: y,
49
+ onChange: (e) => b(e.target.value),
50
+ placeholder: v("agentDetails.storage.adapterPh", "Adapter (e.g. postgres, skalex)"),
51
+ className: d
52
+ }),
53
+ /* @__PURE__ */ s("input", {
54
+ type: "password",
55
+ autoComplete: "off",
56
+ value: x,
57
+ onChange: (e) => S(e.target.value),
58
+ placeholder: v("agentDetails.storage.connPh", "Connection string (e.g. postgres://…)"),
59
+ className: d
60
+ }),
61
+ /* @__PURE__ */ s("input", {
62
+ type: "text",
63
+ value: C,
64
+ onChange: (e) => w(e.target.value),
65
+ placeholder: v("agentDetails.storage.pathPh", "Data path (optional)"),
66
+ className: d
67
+ }),
68
+ /* @__PURE__ */ s("textarea", {
69
+ value: T,
70
+ onChange: (e) => E(e.target.value),
71
+ placeholder: v("agentDetails.storage.optionsPh", "Raw adapter options as JSON (optional, overrides connection string)"),
72
+ rows: 2,
73
+ className: `${d} resize-y`
74
+ })
75
+ ]
76
+ }),
77
+ /* @__PURE__ */ s("div", {
78
+ className: "mt-3",
79
+ children: /* @__PURE__ */ c("button", {
80
+ type: "button",
81
+ onClick: async () => {
82
+ O(null);
83
+ let e;
84
+ if (T.trim()) try {
85
+ let t = JSON.parse(T.trim());
86
+ if (!t || typeof t != "object" || Array.isArray(t)) {
87
+ O({
88
+ ok: !1,
89
+ msg: v("agentDetails.storage.optionsObject", "Options must be a JSON object.")
90
+ });
91
+ return;
92
+ }
93
+ e = t;
94
+ } catch {
95
+ O({
96
+ ok: !1,
97
+ msg: v("agentDetails.storage.optionsJson", "Options must be valid JSON.")
98
+ });
99
+ return;
100
+ }
101
+ else x.trim() && (e = { connectionString: x.trim() });
102
+ let t = {};
103
+ if (y.trim() && (t.storageAdapter = y.trim()), C.trim() && (t.dbPath = C.trim()), e && (t.storageOptions = e), Object.keys(t).length === 0) {
104
+ O({
105
+ ok: !1,
106
+ msg: v("agentDetails.storage.nothing", "Set an adapter, connection string, options, or path first.")
107
+ });
108
+ return;
109
+ }
110
+ try {
111
+ await k({ variables: {
112
+ id: p,
113
+ input: t
114
+ } }), S(""), E(""), O({
115
+ ok: !0,
116
+ msg: v("agentDetails.storage.saved", "Saved. The agent applies the new storage on its next setup/restart — re-pair or restart it to connect to the existing database.")
117
+ }), _?.();
118
+ } catch (e) {
119
+ O({
120
+ ok: !1,
121
+ msg: f(e)
122
+ });
123
+ }
124
+ },
125
+ disabled: A,
126
+ className: u,
127
+ children: [A ? /* @__PURE__ */ s(a, { className: "size-4 animate-spin" }) : /* @__PURE__ */ s(i, { className: "size-4" }), v("agentDetails.storage.save", "Save storage config")]
128
+ })
129
+ }),
130
+ D ? /* @__PURE__ */ c("p", {
131
+ className: `mt-2 flex items-start gap-2 text-xs ${D.ok ? "text-status-success-text" : "text-status-error-text"}`,
132
+ children: [D.ok ? /* @__PURE__ */ s(o, { className: "size-4 flex-shrink-0 mt-0.5" }) : /* @__PURE__ */ s(r, { className: "size-4 flex-shrink-0 mt-0.5" }), /* @__PURE__ */ s("span", { children: D.msg })]
133
+ }) : null
134
+ ]
135
+ });
136
+ }
137
+ //#endregion
138
+ export { p as AgentStorageConfig };
139
+
140
+ //# sourceMappingURL=AgentStorageConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentStorageConfig.js","names":[],"sources":["../../../src/components/agents/AgentStorageConfig.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Database, Loader2, ShieldCheck, AlertTriangle } from 'lucide-react';\n\nimport { useUpdateAgentMutation } from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentStorageConfigProps {\n agentId: string;\n storageAdapter?: string | null;\n dbPath?: string | null;\n hasStorageOptions?: boolean;\n onUpdated?: () => void;\n}\n\nconst CARD = 'rounded-lg border border-border-default bg-bg-surface p-4 sm:p-5';\nconst BTN =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50';\nconst INPUT =\n 'w-full px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 font-mono';\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Reuse an EXISTING database for this agent — point its storage adapter at\n * another (same-workspace) agent's data instead of a fresh store. Persists the\n * config on the agent record; the backend carries it to the agent on its next\n * gateway-auth push, and the agent applies it on restart.\n */\nexport function AgentStorageConfig({\n agentId,\n storageAdapter,\n dbPath,\n hasStorageOptions,\n onUpdated,\n}: AgentStorageConfigProps) {\n const tr = useTr();\n const [adapter, setAdapter] = useState(storageAdapter ?? '');\n const [connectionString, setConnectionString] = useState('');\n const [path, setPath] = useState(dbPath ?? '');\n const [optionsJson, setOptionsJson] = useState('');\n const [result, setResult] = useState<{ ok: boolean; msg: string } | null>(null);\n\n const [updateAgent, { loading }] = useUpdateAgentMutation({ refetchQueries: ['GetAgent'] });\n\n const handleSave = async () => {\n setResult(null);\n // Build storageOptions: raw JSON if provided, else { connectionString }.\n let storageOptions: Record<string, unknown> | undefined;\n if (optionsJson.trim()) {\n try {\n const parsed = JSON.parse(optionsJson.trim());\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n setResult({\n ok: false,\n msg: tr('agentDetails.storage.optionsObject', 'Options must be a JSON object.'),\n });\n return;\n }\n storageOptions = parsed as Record<string, unknown>;\n } catch {\n setResult({\n ok: false,\n msg: tr('agentDetails.storage.optionsJson', 'Options must be valid JSON.'),\n });\n return;\n }\n } else if (connectionString.trim()) {\n storageOptions = { connectionString: connectionString.trim() };\n }\n\n const input: Record<string, unknown> = {};\n if (adapter.trim()) input.storageAdapter = adapter.trim();\n if (path.trim()) input.dbPath = path.trim();\n if (storageOptions) input.storageOptions = storageOptions;\n\n if (Object.keys(input).length === 0) {\n setResult({\n ok: false,\n msg: tr(\n 'agentDetails.storage.nothing',\n 'Set an adapter, connection string, options, or path first.'\n ),\n });\n return;\n }\n\n try {\n await updateAgent({ variables: { id: agentId, input } });\n setConnectionString('');\n setOptionsJson('');\n setResult({\n ok: true,\n msg: tr(\n 'agentDetails.storage.saved',\n 'Saved. The agent applies the new storage on its next setup/restart — re-pair or restart it to connect to the existing database.'\n ),\n });\n onUpdated?.();\n } catch (e) {\n setResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n return (\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <Database className=\"size-5 text-text-secondary\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.storage.title', 'Storage / reuse an existing database')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.storage.hint',\n 'Point this agent at an existing same-workspace database so it reuses that data. Cross-workspace DBs won’t decrypt (per-workspace key), and two agents writing one DB concurrently can corrupt it — keep it single-writer.'\n )}\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 text-xs mb-3\">\n <div>\n <span className=\"text-text-muted\">\n {tr('agentDetails.storage.currentAdapter', 'Current adapter')}\n </span>\n <div className=\"font-mono text-text-primary\">\n {storageAdapter || tr('agentDetails.storage.default', 'default')}\n </div>\n </div>\n <div>\n <span className=\"text-text-muted\">\n {tr('agentDetails.storage.currentOptions', 'Custom options')}\n </span>\n <div className=\"font-mono text-text-primary\">\n {hasStorageOptions\n ? tr('agentDetails.storage.set', 'set')\n : tr('agentDetails.storage.none', 'none')}\n </div>\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <input\n type=\"text\"\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n placeholder={tr('agentDetails.storage.adapterPh', 'Adapter (e.g. postgres, skalex)')}\n className={INPUT}\n />\n <input\n type=\"password\"\n autoComplete=\"off\"\n value={connectionString}\n onChange={(e) => setConnectionString(e.target.value)}\n placeholder={tr('agentDetails.storage.connPh', 'Connection string (e.g. postgres://…)')}\n className={INPUT}\n />\n <input\n type=\"text\"\n value={path}\n onChange={(e) => setPath(e.target.value)}\n placeholder={tr('agentDetails.storage.pathPh', 'Data path (optional)')}\n className={INPUT}\n />\n <textarea\n value={optionsJson}\n onChange={(e) => setOptionsJson(e.target.value)}\n placeholder={tr(\n 'agentDetails.storage.optionsPh',\n 'Raw adapter options as JSON (optional, overrides connection string)'\n )}\n rows={2}\n className={`${INPUT} resize-y`}\n />\n </div>\n\n <div className=\"mt-3\">\n <button type=\"button\" onClick={handleSave} disabled={loading} className={BTN}>\n {loading ? <Loader2 className=\"size-4 animate-spin\" /> : <Database className=\"size-4\" />}\n {tr('agentDetails.storage.save', 'Save storage config')}\n </button>\n </div>\n\n {result ? (\n <p\n className={`mt-2 flex items-start gap-2 text-xs ${\n result.ok ? 'text-status-success-text' : 'text-status-error-text'\n }`}\n >\n {result.ok ? (\n <ShieldCheck className=\"size-4 flex-shrink-0 mt-0.5\" />\n ) : (\n <AlertTriangle className=\"size-4 flex-shrink-0 mt-0.5\" />\n )}\n <span>{result.msg}</span>\n </p>\n ) : null}\n </section>\n );\n}\n"],"mappings":"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"}
@@ -131,6 +131,9 @@ var n = {}, r = e`
131
131
  lastHeartbeat
132
132
  capabilities
133
133
  configuration
134
+ storageAdapter
135
+ dbPath
136
+ hasStorageOptions
134
137
  tunnelUrl
135
138
  tunnelStatus
136
139
  appId