@burdenoff/microfe-vibecontrols 2026.827.1 → 2026.829.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/agent-manager/BridleConfigPanel.js +10 -10
- package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/FilePickerModal.js +71 -65
- package/dist/components/agent-manager/FilePickerModal.js.map +1 -1
- package/dist/components/graph/MeshAgentNode.js +39 -38
- package/dist/components/graph/MeshAgentNode.js.map +1 -1
- package/dist/components/vibes/VibeList.js +88 -93
- package/dist/components/vibes/VibeList.js.map +1 -1
- package/dist/translations/en.js +102 -2
- package/dist/translations/en.js.map +1 -1
- package/package.json +1 -1
|
@@ -179,11 +179,11 @@ function g({ agent: g }) {
|
|
|
179
179
|
/* @__PURE__ */ p("div", {
|
|
180
180
|
className: "flex gap-2",
|
|
181
181
|
children: /* @__PURE__ */ p("input", {
|
|
182
|
-
"aria-label": "
|
|
182
|
+
"aria-label": _("vibecontrols.agentManager.bridle.profileNameAriaLabel", "Profile name"),
|
|
183
183
|
type: "text",
|
|
184
184
|
value: S,
|
|
185
185
|
onChange: (e) => C(e.target.value),
|
|
186
|
-
placeholder: "e.g., work, personal, minimal",
|
|
186
|
+
placeholder: _("vibecontrols.agentManager.bridle.profileNamePlaceholder", "e.g., work, personal, minimal"),
|
|
187
187
|
className: "flex-1 px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
188
188
|
})
|
|
189
189
|
}),
|
|
@@ -237,11 +237,11 @@ function g({ agent: g }) {
|
|
|
237
237
|
/* @__PURE__ */ m("div", {
|
|
238
238
|
className: "flex gap-2",
|
|
239
239
|
children: [/* @__PURE__ */ p("input", {
|
|
240
|
-
"aria-label": "
|
|
240
|
+
"aria-label": _("vibecontrols.agentManager.bridle.installSourceAriaLabel", "GitHub repository or full URL"),
|
|
241
241
|
type: "text",
|
|
242
242
|
value: w,
|
|
243
243
|
onChange: (e) => T(e.target.value),
|
|
244
|
-
placeholder: "owner/repo or full GitHub URL",
|
|
244
|
+
placeholder: _("vibecontrols.agentManager.bridle.installSourcePlaceholder", "owner/repo or full GitHub URL"),
|
|
245
245
|
className: "flex-1 px-3 py-2 text-sm rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
246
246
|
}), /* @__PURE__ */ m("button", {
|
|
247
247
|
type: "button",
|
|
@@ -275,27 +275,27 @@ function g({ agent: g }) {
|
|
|
275
275
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
276
276
|
htmlFor: "bridleconfigpanel-4",
|
|
277
277
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
278
|
-
children: "Key"
|
|
278
|
+
children: _("vibecontrols.agentManager.bridle.configKeyLabel", "Key")
|
|
279
279
|
}), /* @__PURE__ */ p("input", {
|
|
280
280
|
id: "bridleconfigpanel-4",
|
|
281
|
-
"aria-label": "
|
|
281
|
+
"aria-label": _("vibecontrols.agentManager.bridle.configKeyAriaLabel", "Configuration key"),
|
|
282
282
|
type: "text",
|
|
283
283
|
value: E,
|
|
284
284
|
onChange: (e) => D(e.target.value),
|
|
285
|
-
placeholder: "e.g., editor, default_harness, profile_marker",
|
|
285
|
+
placeholder: _("vibecontrols.agentManager.bridle.configKeyPlaceholder", "e.g., editor, default_harness, profile_marker"),
|
|
286
286
|
className: "w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
287
287
|
})] }),
|
|
288
288
|
/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
289
289
|
htmlFor: "bridleconfigpanel-3",
|
|
290
290
|
className: "block text-xs font-medium text-text-secondary mb-1",
|
|
291
|
-
children: "Value"
|
|
291
|
+
children: _("vibecontrols.agentManager.bridle.configValueLabel", "Value")
|
|
292
292
|
}), /* @__PURE__ */ p("input", {
|
|
293
293
|
id: "bridleconfigpanel-3",
|
|
294
|
-
"aria-label": "value",
|
|
294
|
+
"aria-label": _("vibecontrols.agentManager.bridle.configValueAriaLabel", "Configuration value"),
|
|
295
295
|
type: "text",
|
|
296
296
|
value: O,
|
|
297
297
|
onChange: (e) => k(e.target.value),
|
|
298
|
-
placeholder: "value",
|
|
298
|
+
placeholder: _("vibecontrols.agentManager.bridle.configValuePlaceholder", "value"),
|
|
299
299
|
className: "w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong"
|
|
300
300
|
})] }),
|
|
301
301
|
/* @__PURE__ */ m("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BridleConfigPanel.js","names":[],"sources":["../../../src/components/agent-manager/BridleConfigPanel.tsx"],"sourcesContent":["/**\n * Bridle Configuration Manager Panel.\n *\n * Provides a full UI for managing cross-harness AI assistant configurations\n * via the Bridle CLI tool. Supports profile management, skill installation,\n * and config editing across Claude Code, OpenCode, Goose, Amp, Copilot, and Crush.\n */\n\nimport { useState, useCallback } from 'react';\nimport {\n Terminal,\n Copy,\n Check,\n Plus,\n ArrowLeftRight,\n Trash2,\n Download,\n Settings,\n RefreshCw,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface BridleConfigPanelProps {\n agent: { id: string; profile: string };\n}\n\nconst HARNESSES = [\n {\n name: 'Claude Code',\n id: 'claude',\n config: '~/.claude/',\n color: 'bg-accent-purple-subtle text-text-primary',\n },\n {\n name: 'OpenCode',\n id: 'opencode',\n config: '~/.config/opencode/',\n color: 'bg-status-info-bg-subtle text-status-info-text',\n },\n {\n name: 'Goose',\n id: 'goose',\n config: '~/.config/goose/',\n color: 'bg-status-success-bg-subtle text-status-success-text',\n },\n {\n name: 'Amp',\n id: 'amp',\n config: '~/.amp/',\n color: 'bg-status-warning-bg-subtle text-status-warning-text',\n },\n {\n name: 'Copilot',\n id: 'copilot',\n config: '~/.copilot/',\n color: 'bg-bg-sunken text-text-secondary',\n },\n {\n name: 'Crush',\n id: 'crush',\n config: '~/.config/crush/',\n color: 'bg-status-error-bg-subtle text-status-error-text',\n },\n];\n\ntype PanelView = 'overview' | 'profiles' | 'install' | 'settings';\n\nexport function BridleConfigPanel({ agent: _agent }: BridleConfigPanelProps) {\n const tr = useTr();\n const [view, setView] = useState<PanelView>('overview');\n const [selectedHarness, setSelectedHarness] = useState('claude');\n const [profileName, setProfileName] = useState('');\n const [installSource, setInstallSource] = useState('');\n const [configKey, setConfigKey] = useState('');\n const [configValue, setConfigValue] = useState('');\n const [output, setOutput] = useState('');\n const [copiedCmd, setCopiedCmd] = useState<string | null>(null);\n\n const copyToClipboard = useCallback((text: string) => {\n void navigator.clipboard.writeText(text);\n setCopiedCmd(text);\n setTimeout(() => setCopiedCmd(null), 2000);\n }, []);\n\n const showCommand = (cmd: string) => {\n setOutput(`$ ${cmd}\\n\\nRun this command in your terminal to execute.`);\n copyToClipboard(cmd);\n };\n\n const navItems: Array<{ key: PanelView; label: string; icon: typeof Settings }> = [\n { key: 'overview', label: 'Overview', icon: RefreshCw },\n { key: 'profiles', label: 'Profiles', icon: ArrowLeftRight },\n { key: 'install', label: 'Install', icon: Download },\n { key: 'settings', label: 'Settings', icon: Settings },\n ];\n\n return (\n <div className=\"flex flex-col h-full max-h-[65vh] overflow-hidden\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default flex-shrink-0\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"size-4\" />\n {tr('vibecontrols.agentManager.bridle.title', 'Bridle — Cross-Harness Config Manager')}\n </h3>\n <p className=\"text-[11px] text-text-secondary mt-0.5\">\n {tr(\n 'vibecontrols.agentManager.bridle.description',\n 'Manage profiles, skills, and configurations across all AI coding assistants'\n )}\n </p>\n </div>\n </div>\n\n {/* Sub-navigation */}\n <div className=\"flex gap-1 px-4 py-2 border-b border-border-default flex-shrink-0\">\n {navItems.map(({ key, label, icon: Icon }) => (\n <button\n type=\"button\"\n key={key}\n onClick={() => setView(key)}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded transition-colors ${\n view === key\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-elevated'\n }`}\n >\n <Icon className=\"size-3.5\" />\n {label}\n </button>\n ))}\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-4\">\n {view === 'overview' && (\n <div className=\"space-y-4\">\n {/* Harness Grid */}\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.supportedHarnesses', 'Supported Harnesses')}\n </h4>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n {HARNESSES.map((h) => (\n <button\n type=\"button\"\n key={h.id}\n onClick={() => {\n setSelectedHarness(h.id);\n setView('profiles');\n }}\n className=\"px-3 py-2.5 rounded-md border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors text-left\"\n >\n <span className=\"text-xs font-medium text-text-primary\">{h.name}</span>\n <span className=\"block text-[10px] text-text-tertiary font-mono mt-0.5\">\n {h.config}\n </span>\n </button>\n ))}\n </div>\n </div>\n\n {/* Quick Status */}\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.quickActions', 'Quick Actions')}\n </h4>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => showCommand('bridle status')}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors flex items-center gap-1.5\"\n >\n <RefreshCw className=\"size-3\" />{' '}\n {tr('vibecontrols.agentManager.bridle.showStatus', 'Show Status')}\n </button>\n <button\n type=\"button\"\n onClick={() => showCommand('bridle init')}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors flex items-center gap-1.5\"\n >\n <Plus className=\"size-3\" />{' '}\n {tr('vibecontrols.agentManager.bridle.initialize', 'Initialize')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {view === 'profiles' && (\n <div className=\"space-y-4\">\n {/* Harness Selector */}\n <div>\n <label\n htmlFor=\"bridleconfigpanel-5\"\n className=\"block text-xs font-medium text-text-secondary mb-1\"\n >\n Harness\n </label>\n <select\n id=\"bridleconfigpanel-5\"\n value={selectedHarness}\n onChange={(e) => setSelectedHarness(e.target.value)}\n className=\"w-full px-3 py-2 text-sm rounded border border-border-default bg-bg-surface text-text-primary\"\n >\n {HARNESSES.map((h) => (\n <option key={h.id} value={h.id}>\n {h.name}\n </option>\n ))}\n </select>\n </div>\n\n {/* Profile Actions */}\n <div className=\"grid grid-cols-2 gap-2\">\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle profile list ${selectedHarness}`)}\n className=\"px-3 py-2 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors text-left\"\n >\n {tr('vibecontrols.agentManager.bridle.listProfiles', 'List Profiles')}\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile show ${selectedHarness} ${profileName || '<name>'}`)\n }\n className=\"px-3 py-2 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors text-left\"\n >\n {tr('vibecontrols.agentManager.bridle.showProfile', 'Show Profile')}\n </button>\n </div>\n\n {/* Create Profile */}\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.bridle.profileName', 'Profile Name')}\n </label>\n <div className=\"flex gap-2\">\n <input\n aria-label=\"e.g., work, personal, minimal\"\n type=\"text\"\n value={profileName}\n onChange={(e) => setProfileName(e.target.value)}\n placeholder=\"e.g., work, personal, minimal\"\n className=\"flex-1 px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n </div>\n <div className=\"flex gap-2 mt-2\">\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile create ${selectedHarness} ${profileName}`)\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 flex items-center gap-1\"\n >\n <Plus className=\"size-3\" /> Create\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(\n `bridle profile create ${selectedHarness} ${profileName} --from-current`\n )\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated disabled:opacity-50 flex items-center gap-1\"\n >\n <Copy className=\"size-3\" /> From Current\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile switch ${selectedHarness} ${profileName}`)\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated disabled:opacity-50 flex items-center gap-1\"\n >\n <ArrowLeftRight className=\"size-3\" /> Switch\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile delete ${selectedHarness} ${profileName}`)\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded-button border border-status-error-border text-status-error-text hover:bg-status-error-bg-subtle disabled:opacity-50 flex items-center gap-1\"\n >\n <Trash2 className=\"size-3\" /> Delete\n </button>\n </div>\n </div>\n </div>\n )}\n\n {view === 'install' && (\n <div className=\"space-y-4\">\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.installFromGithub', 'Install from GitHub')}\n </h4>\n <p className=\"text-xs text-text-secondary mb-3\">\n {tr(\n 'vibecontrols.agentManager.bridle.installDescription',\n 'Install skills, agents, commands, or MCPs from GitHub repositories.'\n )}\n </p>\n <div className=\"flex gap-2\">\n <input\n aria-label=\"owner/repo or full GitHub URL\"\n type=\"text\"\n value={installSource}\n onChange={(e) => setInstallSource(e.target.value)}\n placeholder=\"owner/repo or full GitHub URL\"\n className=\"flex-1 px-3 py-2 text-sm rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle install ${installSource}`)}\n disabled={!installSource}\n className=\"px-4 py-2 text-sm rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 flex items-center gap-1.5\"\n >\n <Download className=\"size-4\" /> Install\n </button>\n </div>\n <p className=\"text-[10px] text-text-tertiary mt-1.5\">\n Use <code className=\"px-1 py-0.5 rounded bg-bg-elevated\">--force</code> to overwrite\n existing installations\n </p>\n </div>\n </div>\n )}\n\n {view === 'settings' && (\n <div className=\"space-y-4\">\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.configuration', 'Configuration')}\n </h4>\n <div className=\"space-y-3\">\n <div>\n <label\n htmlFor=\"bridleconfigpanel-4\"\n className=\"block text-xs font-medium text-text-secondary mb-1\"\n >\n Key\n </label>\n <input\n id=\"bridleconfigpanel-4\"\n aria-label=\"e.g., editor, default_harness, profile_marker\"\n type=\"text\"\n value={configKey}\n onChange={(e) => setConfigKey(e.target.value)}\n placeholder=\"e.g., editor, default_harness, profile_marker\"\n className=\"w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n </div>\n <div>\n <label\n htmlFor=\"bridleconfigpanel-3\"\n className=\"block text-xs font-medium text-text-secondary mb-1\"\n >\n Value\n </label>\n <input\n id=\"bridleconfigpanel-3\"\n aria-label=\"value\"\n type=\"text\"\n value={configValue}\n onChange={(e) => setConfigValue(e.target.value)}\n placeholder=\"value\"\n className=\"w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n </div>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle config get ${configKey}`)}\n disabled={!configKey}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated disabled:opacity-50\"\n >\n Get\n </button>\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle config set ${configKey} ${configValue}`)}\n disabled={!configKey || !configValue}\n className=\"px-3 py-1.5 text-xs rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n Set\n </button>\n </div>\n </div>\n </div>\n\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr(\n 'vibecontrols.agentManager.bridle.availableConfigKeys',\n 'Available Config Keys'\n )}\n </h4>\n <div className=\"space-y-1 text-xs text-text-secondary\">\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>profile_marker</code>\n <span>Enable debug marker files</span>\n </div>\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>editor</code>\n <span>Default text editor</span>\n </div>\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>tui.view</code>\n <span>Initial TUI view</span>\n </div>\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>default_harness</code>\n <span>Startup harness tab</span>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Output */}\n {output && (\n <div className=\"mt-4 border-t border-border-default pt-3\">\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.agentManager.bridle.command', 'Command')}\n </h4>\n <button\n type=\"button\"\n onClick={() => setOutput('')}\n className=\"text-[10px] text-text-tertiary hover:text-text-secondary\"\n >\n {tr('vibecontrols.agentManager.bridle.clear', 'Clear')}\n </button>\n </div>\n <pre className=\"p-3 rounded-md bg-bg-sunken text-text-primary text-xs font-mono whitespace-pre-wrap border border-border-default\">\n {output}\n </pre>\n <p className=\"text-[10px] text-text-tertiary mt-1 flex items-center gap-1\">\n {copiedCmd ? (\n <>\n <Check className=\"size-3 text-status-success-text\" />{' '}\n {tr('vibecontrols.agentManager.bridle.copiedToClipboard', 'Copied to clipboard')}\n </>\n ) : (\n tr('vibecontrols.agentManager.bridle.commandCopied', 'Command copied to clipboard')\n )}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BridleConfigPanel.js","names":[],"sources":["../../../src/components/agent-manager/BridleConfigPanel.tsx"],"sourcesContent":["/**\n * Bridle Configuration Manager Panel.\n *\n * Provides a full UI for managing cross-harness AI assistant configurations\n * via the Bridle CLI tool. Supports profile management, skill installation,\n * and config editing across Claude Code, OpenCode, Goose, Amp, Copilot, and Crush.\n */\n\nimport { useState, useCallback } from 'react';\nimport {\n Terminal,\n Copy,\n Check,\n Plus,\n ArrowLeftRight,\n Trash2,\n Download,\n Settings,\n RefreshCw,\n} from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface BridleConfigPanelProps {\n agent: { id: string; profile: string };\n}\n\nconst HARNESSES = [\n {\n name: 'Claude Code',\n id: 'claude',\n config: '~/.claude/',\n color: 'bg-accent-purple-subtle text-text-primary',\n },\n {\n name: 'OpenCode',\n id: 'opencode',\n config: '~/.config/opencode/',\n color: 'bg-status-info-bg-subtle text-status-info-text',\n },\n {\n name: 'Goose',\n id: 'goose',\n config: '~/.config/goose/',\n color: 'bg-status-success-bg-subtle text-status-success-text',\n },\n {\n name: 'Amp',\n id: 'amp',\n config: '~/.amp/',\n color: 'bg-status-warning-bg-subtle text-status-warning-text',\n },\n {\n name: 'Copilot',\n id: 'copilot',\n config: '~/.copilot/',\n color: 'bg-bg-sunken text-text-secondary',\n },\n {\n name: 'Crush',\n id: 'crush',\n config: '~/.config/crush/',\n color: 'bg-status-error-bg-subtle text-status-error-text',\n },\n];\n\ntype PanelView = 'overview' | 'profiles' | 'install' | 'settings';\n\nexport function BridleConfigPanel({ agent: _agent }: BridleConfigPanelProps) {\n const tr = useTr();\n const [view, setView] = useState<PanelView>('overview');\n const [selectedHarness, setSelectedHarness] = useState('claude');\n const [profileName, setProfileName] = useState('');\n const [installSource, setInstallSource] = useState('');\n const [configKey, setConfigKey] = useState('');\n const [configValue, setConfigValue] = useState('');\n const [output, setOutput] = useState('');\n const [copiedCmd, setCopiedCmd] = useState<string | null>(null);\n\n const copyToClipboard = useCallback((text: string) => {\n void navigator.clipboard.writeText(text);\n setCopiedCmd(text);\n setTimeout(() => setCopiedCmd(null), 2000);\n }, []);\n\n const showCommand = (cmd: string) => {\n setOutput(`$ ${cmd}\\n\\nRun this command in your terminal to execute.`);\n copyToClipboard(cmd);\n };\n\n const navItems: Array<{ key: PanelView; label: string; icon: typeof Settings }> = [\n { key: 'overview', label: 'Overview', icon: RefreshCw },\n { key: 'profiles', label: 'Profiles', icon: ArrowLeftRight },\n { key: 'install', label: 'Install', icon: Download },\n { key: 'settings', label: 'Settings', icon: Settings },\n ];\n\n return (\n <div className=\"flex flex-col h-full max-h-[65vh] overflow-hidden\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default flex-shrink-0\">\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"size-4\" />\n {tr('vibecontrols.agentManager.bridle.title', 'Bridle — Cross-Harness Config Manager')}\n </h3>\n <p className=\"text-[11px] text-text-secondary mt-0.5\">\n {tr(\n 'vibecontrols.agentManager.bridle.description',\n 'Manage profiles, skills, and configurations across all AI coding assistants'\n )}\n </p>\n </div>\n </div>\n\n {/* Sub-navigation */}\n <div className=\"flex gap-1 px-4 py-2 border-b border-border-default flex-shrink-0\">\n {navItems.map(({ key, label, icon: Icon }) => (\n <button\n type=\"button\"\n key={key}\n onClick={() => setView(key)}\n className={`flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded transition-colors ${\n view === key\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-elevated'\n }`}\n >\n <Icon className=\"size-3.5\" />\n {label}\n </button>\n ))}\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-4\">\n {view === 'overview' && (\n <div className=\"space-y-4\">\n {/* Harness Grid */}\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.supportedHarnesses', 'Supported Harnesses')}\n </h4>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 gap-2\">\n {HARNESSES.map((h) => (\n <button\n type=\"button\"\n key={h.id}\n onClick={() => {\n setSelectedHarness(h.id);\n setView('profiles');\n }}\n className=\"px-3 py-2.5 rounded-md border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors text-left\"\n >\n <span className=\"text-xs font-medium text-text-primary\">{h.name}</span>\n <span className=\"block text-[10px] text-text-tertiary font-mono mt-0.5\">\n {h.config}\n </span>\n </button>\n ))}\n </div>\n </div>\n\n {/* Quick Status */}\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.quickActions', 'Quick Actions')}\n </h4>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => showCommand('bridle status')}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors flex items-center gap-1.5\"\n >\n <RefreshCw className=\"size-3\" />{' '}\n {tr('vibecontrols.agentManager.bridle.showStatus', 'Show Status')}\n </button>\n <button\n type=\"button\"\n onClick={() => showCommand('bridle init')}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors flex items-center gap-1.5\"\n >\n <Plus className=\"size-3\" />{' '}\n {tr('vibecontrols.agentManager.bridle.initialize', 'Initialize')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {view === 'profiles' && (\n <div className=\"space-y-4\">\n {/* Harness Selector */}\n <div>\n <label\n htmlFor=\"bridleconfigpanel-5\"\n className=\"block text-xs font-medium text-text-secondary mb-1\"\n >\n Harness\n </label>\n <select\n id=\"bridleconfigpanel-5\"\n value={selectedHarness}\n onChange={(e) => setSelectedHarness(e.target.value)}\n className=\"w-full px-3 py-2 text-sm rounded border border-border-default bg-bg-surface text-text-primary\"\n >\n {HARNESSES.map((h) => (\n <option key={h.id} value={h.id}>\n {h.name}\n </option>\n ))}\n </select>\n </div>\n\n {/* Profile Actions */}\n <div className=\"grid grid-cols-2 gap-2\">\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle profile list ${selectedHarness}`)}\n className=\"px-3 py-2 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors text-left\"\n >\n {tr('vibecontrols.agentManager.bridle.listProfiles', 'List Profiles')}\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile show ${selectedHarness} ${profileName || '<name>'}`)\n }\n className=\"px-3 py-2 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated transition-colors text-left\"\n >\n {tr('vibecontrols.agentManager.bridle.showProfile', 'Show Profile')}\n </button>\n </div>\n\n {/* Create Profile */}\n <div>\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.bridle.profileName', 'Profile Name')}\n </label>\n <div className=\"flex gap-2\">\n <input\n aria-label={tr(\n 'vibecontrols.agentManager.bridle.profileNameAriaLabel',\n 'Profile name'\n )}\n type=\"text\"\n value={profileName}\n onChange={(e) => setProfileName(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.bridle.profileNamePlaceholder',\n 'e.g., work, personal, minimal'\n )}\n className=\"flex-1 px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n </div>\n <div className=\"flex gap-2 mt-2\">\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile create ${selectedHarness} ${profileName}`)\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 flex items-center gap-1\"\n >\n <Plus className=\"size-3\" /> Create\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(\n `bridle profile create ${selectedHarness} ${profileName} --from-current`\n )\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated disabled:opacity-50 flex items-center gap-1\"\n >\n <Copy className=\"size-3\" /> From Current\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile switch ${selectedHarness} ${profileName}`)\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated disabled:opacity-50 flex items-center gap-1\"\n >\n <ArrowLeftRight className=\"size-3\" /> Switch\n </button>\n <button\n type=\"button\"\n onClick={() =>\n showCommand(`bridle profile delete ${selectedHarness} ${profileName}`)\n }\n disabled={!profileName}\n className=\"px-3 py-1.5 text-xs rounded-button border border-status-error-border text-status-error-text hover:bg-status-error-bg-subtle disabled:opacity-50 flex items-center gap-1\"\n >\n <Trash2 className=\"size-3\" /> Delete\n </button>\n </div>\n </div>\n </div>\n )}\n\n {view === 'install' && (\n <div className=\"space-y-4\">\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.installFromGithub', 'Install from GitHub')}\n </h4>\n <p className=\"text-xs text-text-secondary mb-3\">\n {tr(\n 'vibecontrols.agentManager.bridle.installDescription',\n 'Install skills, agents, commands, or MCPs from GitHub repositories.'\n )}\n </p>\n <div className=\"flex gap-2\">\n <input\n aria-label={tr(\n 'vibecontrols.agentManager.bridle.installSourceAriaLabel',\n 'GitHub repository or full URL'\n )}\n type=\"text\"\n value={installSource}\n onChange={(e) => setInstallSource(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.bridle.installSourcePlaceholder',\n 'owner/repo or full GitHub URL'\n )}\n className=\"flex-1 px-3 py-2 text-sm rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle install ${installSource}`)}\n disabled={!installSource}\n className=\"px-4 py-2 text-sm rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 flex items-center gap-1.5\"\n >\n <Download className=\"size-4\" /> Install\n </button>\n </div>\n <p className=\"text-[10px] text-text-tertiary mt-1.5\">\n Use <code className=\"px-1 py-0.5 rounded bg-bg-elevated\">--force</code> to overwrite\n existing installations\n </p>\n </div>\n </div>\n )}\n\n {view === 'settings' && (\n <div className=\"space-y-4\">\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.bridle.configuration', 'Configuration')}\n </h4>\n <div className=\"space-y-3\">\n <div>\n <label\n htmlFor=\"bridleconfigpanel-4\"\n className=\"block text-xs font-medium text-text-secondary mb-1\"\n >\n {tr('vibecontrols.agentManager.bridle.configKeyLabel', 'Key')}\n </label>\n <input\n id=\"bridleconfigpanel-4\"\n aria-label={tr(\n 'vibecontrols.agentManager.bridle.configKeyAriaLabel',\n 'Configuration key'\n )}\n type=\"text\"\n value={configKey}\n onChange={(e) => setConfigKey(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.bridle.configKeyPlaceholder',\n 'e.g., editor, default_harness, profile_marker'\n )}\n className=\"w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n </div>\n <div>\n <label\n htmlFor=\"bridleconfigpanel-3\"\n className=\"block text-xs font-medium text-text-secondary mb-1\"\n >\n {tr('vibecontrols.agentManager.bridle.configValueLabel', 'Value')}\n </label>\n <input\n id=\"bridleconfigpanel-3\"\n aria-label={tr(\n 'vibecontrols.agentManager.bridle.configValueAriaLabel',\n 'Configuration value'\n )}\n type=\"text\"\n value={configValue}\n onChange={(e) => setConfigValue(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.bridle.configValuePlaceholder',\n 'value'\n )}\n className=\"w-full px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong\"\n />\n </div>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle config get ${configKey}`)}\n disabled={!configKey}\n className=\"px-3 py-1.5 text-xs rounded border border-border-default bg-bg-surface hover:bg-bg-elevated disabled:opacity-50\"\n >\n Get\n </button>\n <button\n type=\"button\"\n onClick={() => showCommand(`bridle config set ${configKey} ${configValue}`)}\n disabled={!configKey || !configValue}\n className=\"px-3 py-1.5 text-xs rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n Set\n </button>\n </div>\n </div>\n </div>\n\n <div>\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr(\n 'vibecontrols.agentManager.bridle.availableConfigKeys',\n 'Available Config Keys'\n )}\n </h4>\n <div className=\"space-y-1 text-xs text-text-secondary\">\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>profile_marker</code>\n <span>Enable debug marker files</span>\n </div>\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>editor</code>\n <span>Default text editor</span>\n </div>\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>tui.view</code>\n <span>Initial TUI view</span>\n </div>\n <div className=\"flex justify-between px-2 py-1 rounded bg-bg-surface\">\n <code>default_harness</code>\n <span>Startup harness tab</span>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Output */}\n {output && (\n <div className=\"mt-4 border-t border-border-default pt-3\">\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.agentManager.bridle.command', 'Command')}\n </h4>\n <button\n type=\"button\"\n onClick={() => setOutput('')}\n className=\"text-[10px] text-text-tertiary hover:text-text-secondary\"\n >\n {tr('vibecontrols.agentManager.bridle.clear', 'Clear')}\n </button>\n </div>\n <pre className=\"p-3 rounded-md bg-bg-sunken text-text-primary text-xs font-mono whitespace-pre-wrap border border-border-default\">\n {output}\n </pre>\n <p className=\"text-[10px] text-text-tertiary mt-1 flex items-center gap-1\">\n {copiedCmd ? (\n <>\n <Check className=\"size-3 text-status-success-text\" />{' '}\n {tr('vibecontrols.agentManager.bridle.copiedToClipboard', 'Copied to clipboard')}\n </>\n ) : (\n tr('vibecontrols.agentManager.bridle.commandCopied', 'Command copied to clipboard')\n )}\n </p>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { useGetFileDownloadUrlLazyQuery as e, useGetWorkspaceFilesQuery as t } from "../../generated/wspace-operations.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { useTr as n } from "../../shared/hooks/useTr.js";
|
|
3
|
+
import { fetchFileIntoContext as r } from "../../services/aiApi.js";
|
|
4
|
+
import { useAgentManagerStore as i } from "../../store/agentManagerStore.js";
|
|
5
|
+
import { useCallback as a, useState as o } from "react";
|
|
6
|
+
import { FileText as s, Loader2 as c, Paperclip as l, X as u } from "lucide-react";
|
|
7
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
7
8
|
//#region src/components/agent-manager/FilePickerModal.tsx
|
|
8
|
-
function
|
|
9
|
+
function p(e) {
|
|
9
10
|
let t = Number(e);
|
|
10
11
|
if (!Number.isFinite(t) || t <= 0) return "0 B";
|
|
11
12
|
let n = [
|
|
@@ -17,132 +18,137 @@ function f(e) {
|
|
|
17
18
|
], r = Math.min(Math.floor(Math.log(t) / Math.log(1024)), n.length - 1);
|
|
18
19
|
return `${(t / 1024 ** r).toFixed(r === 0 ? 0 : 1)} ${n[r]}`;
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
-
let { data:
|
|
21
|
+
function m({ isOpen: m, onClose: h, agent: g, sessionId: _ }) {
|
|
22
|
+
let v = n(), { data: y, loading: b } = t({
|
|
22
23
|
variables: { pagination: {
|
|
23
24
|
limit: 50,
|
|
24
25
|
offset: 0
|
|
25
26
|
} },
|
|
26
|
-
skip: !
|
|
27
|
+
skip: !m,
|
|
27
28
|
fetchPolicy: "cache-and-network"
|
|
28
|
-
}), [
|
|
29
|
-
|
|
29
|
+
}), [x] = e(), S = i((e) => e.addSessionContext), [C, w] = o(null), [T, E] = o(null), D = a(async (e) => {
|
|
30
|
+
E(null), w(e.id);
|
|
30
31
|
try {
|
|
31
|
-
let t = (await
|
|
32
|
+
let t = (await x({ variables: {
|
|
32
33
|
id: e.id,
|
|
33
34
|
expiresIn: 300
|
|
34
35
|
} })).data?.getFileDownloadUrl;
|
|
35
36
|
if (!t) {
|
|
36
|
-
|
|
37
|
+
E(v("vibecontrols.agentManager.filePicker.errorDownloadUrl", "Could not get a download URL for this file."));
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
|
-
let
|
|
40
|
+
let n = await r(g, {
|
|
40
41
|
downloadUrl: t,
|
|
41
42
|
filename: e.name,
|
|
42
|
-
sessionId:
|
|
43
|
+
sessionId: _
|
|
43
44
|
});
|
|
44
|
-
|
|
45
|
+
S(_, {
|
|
45
46
|
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
46
47
|
kind: "file",
|
|
47
48
|
label: e.name,
|
|
48
|
-
path:
|
|
49
|
-
content:
|
|
50
|
-
}),
|
|
49
|
+
path: n.path,
|
|
50
|
+
content: n.inline ?? null
|
|
51
|
+
}), h();
|
|
51
52
|
} catch (e) {
|
|
52
|
-
|
|
53
|
+
E(e instanceof Error ? e.message : v("vibecontrols.agentManager.filePicker.errorAttachFailed", "Failed to attach file"));
|
|
53
54
|
} finally {
|
|
54
|
-
|
|
55
|
+
w(null);
|
|
55
56
|
}
|
|
56
57
|
}, [
|
|
57
|
-
h,
|
|
58
58
|
g,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
_,
|
|
60
|
+
x,
|
|
61
|
+
S,
|
|
62
|
+
h,
|
|
63
|
+
v
|
|
62
64
|
]);
|
|
63
|
-
if (!
|
|
64
|
-
let
|
|
65
|
-
return /* @__PURE__ */
|
|
65
|
+
if (!m) return null;
|
|
66
|
+
let O = y?.getFiles?.files ?? [], k = y?.getFiles?.total ?? O.length;
|
|
67
|
+
return y?.getFiles?.hasMore, /* @__PURE__ */ f("div", {
|
|
66
68
|
className: "fixed inset-0 z-50 flex items-center justify-center",
|
|
67
|
-
children: [/* @__PURE__ */
|
|
69
|
+
children: [/* @__PURE__ */ d("div", {
|
|
68
70
|
role: "button",
|
|
69
71
|
tabIndex: 0,
|
|
70
72
|
onKeyDown: (e) => {
|
|
71
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
73
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), h());
|
|
72
74
|
},
|
|
73
75
|
className: "absolute inset-0 bg-bg-overlay",
|
|
74
|
-
onClick:
|
|
75
|
-
}), /* @__PURE__ */
|
|
76
|
+
onClick: h
|
|
77
|
+
}), /* @__PURE__ */ f("div", {
|
|
76
78
|
"data-testid": "file-picker-modal",
|
|
77
79
|
className: "relative w-full max-w-lg mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl",
|
|
78
80
|
children: [
|
|
79
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ f("div", {
|
|
80
82
|
className: "flex items-center justify-between px-6 py-4 border-b border-border-default",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
83
|
+
children: [/* @__PURE__ */ d("h3", {
|
|
82
84
|
className: "text-lg font-semibold text-text-primary",
|
|
83
|
-
children: "Add file as context"
|
|
84
|
-
}), /* @__PURE__ */
|
|
85
|
+
children: v("vibecontrols.agentManager.filePicker.title", "Add file as context")
|
|
86
|
+
}), /* @__PURE__ */ d("button", {
|
|
85
87
|
type: "button",
|
|
86
|
-
onClick:
|
|
87
|
-
"aria-label": "Close",
|
|
88
|
+
onClick: h,
|
|
89
|
+
"aria-label": v("vibecontrols.agentManager.filePicker.closeAriaLabel", "Close"),
|
|
88
90
|
className: "p-1 rounded hover:bg-bg-sunken transition-colors",
|
|
89
|
-
children: /* @__PURE__ */ u
|
|
91
|
+
children: /* @__PURE__ */ d(u, { className: "size-5 text-text-secondary" })
|
|
90
92
|
})]
|
|
91
93
|
}),
|
|
92
|
-
|
|
94
|
+
T && /* @__PURE__ */ d("div", {
|
|
93
95
|
className: "mx-6 mt-4 px-3 py-2 rounded-md bg-action-danger-bg text-action-danger-text text-sm",
|
|
94
|
-
children:
|
|
96
|
+
children: T
|
|
95
97
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ d("div", {
|
|
97
99
|
className: "max-h-80 overflow-y-auto px-2 py-2",
|
|
98
|
-
children:
|
|
100
|
+
children: b && O.length === 0 ? /* @__PURE__ */ f("div", {
|
|
99
101
|
className: "flex items-center justify-center gap-2 px-4 py-12 text-text-secondary",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
102
|
+
children: [/* @__PURE__ */ d(c, { className: "size-5 animate-spin" }), /* @__PURE__ */ d("span", {
|
|
101
103
|
className: "text-sm",
|
|
102
|
-
children: "Loading files…"
|
|
104
|
+
children: v("vibecontrols.agentManager.filePicker.loading", "Loading files…")
|
|
103
105
|
})]
|
|
104
|
-
}) :
|
|
106
|
+
}) : O.length === 0 ? /* @__PURE__ */ f("div", {
|
|
105
107
|
className: "flex flex-col items-center justify-center gap-2 px-4 py-12 text-center",
|
|
106
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ d(s, { className: "size-8 text-text-tertiary" }), /* @__PURE__ */ d("p", {
|
|
107
109
|
className: "text-sm text-text-secondary",
|
|
108
|
-
children: "No files found in this workspace."
|
|
110
|
+
children: v("vibecontrols.agentManager.filePicker.emptyDescription", "No files found in this workspace.")
|
|
109
111
|
})]
|
|
110
|
-
}) : /* @__PURE__ */
|
|
112
|
+
}) : /* @__PURE__ */ d("ul", {
|
|
111
113
|
className: "space-y-1",
|
|
112
|
-
children:
|
|
113
|
-
let t =
|
|
114
|
-
return /* @__PURE__ */
|
|
114
|
+
children: O.map((e) => {
|
|
115
|
+
let t = C === e.id;
|
|
116
|
+
return /* @__PURE__ */ f("li", {
|
|
115
117
|
className: "flex items-center gap-3 px-3 py-2 rounded-md hover:bg-bg-elevated transition-colors",
|
|
116
118
|
children: [
|
|
117
|
-
/* @__PURE__ */
|
|
118
|
-
/* @__PURE__ */
|
|
119
|
+
/* @__PURE__ */ d(s, { className: "size-5 shrink-0 text-text-tertiary" }),
|
|
120
|
+
/* @__PURE__ */ f("div", {
|
|
119
121
|
className: "min-w-0 flex-1",
|
|
120
|
-
children: [/* @__PURE__ */
|
|
122
|
+
children: [/* @__PURE__ */ d("p", {
|
|
121
123
|
className: "truncate text-sm font-medium text-text-primary",
|
|
122
124
|
children: e.name
|
|
123
|
-
}), /* @__PURE__ */
|
|
125
|
+
}), /* @__PURE__ */ f("p", {
|
|
124
126
|
className: "text-xs text-text-tertiary",
|
|
125
|
-
children: [
|
|
127
|
+
children: [p(e.size), e.extension ? ` · ${e.extension}` : ""]
|
|
126
128
|
})]
|
|
127
129
|
}),
|
|
128
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ f("button", {
|
|
129
131
|
type: "button",
|
|
130
132
|
"data-testid": "file-picker-attach",
|
|
131
|
-
onClick: () => void
|
|
132
|
-
disabled:
|
|
133
|
+
onClick: () => void D(e),
|
|
134
|
+
disabled: C !== null,
|
|
133
135
|
className: "inline-flex items-center gap-1.5 px-3 py-1 text-sm rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-60 disabled:cursor-not-allowed transition-colors",
|
|
134
|
-
children: [t ? /* @__PURE__ */
|
|
136
|
+
children: [t ? /* @__PURE__ */ d(c, { className: "size-4 animate-spin" }) : /* @__PURE__ */ d(l, { className: "size-4" }), /* @__PURE__ */ d("span", { children: t ? v("vibecontrols.agentManager.filePicker.attaching", "Attaching…") : v("vibecontrols.agentManager.filePicker.attach", "Attach") })]
|
|
135
137
|
})
|
|
136
138
|
]
|
|
137
139
|
}, e.id);
|
|
138
140
|
})
|
|
139
141
|
})
|
|
140
142
|
}),
|
|
141
|
-
/* @__PURE__ */
|
|
143
|
+
/* @__PURE__ */ d("div", {
|
|
142
144
|
className: "px-6 py-3 border-t border-border-default bg-bg-sunken rounded-b-lg",
|
|
143
|
-
children: /* @__PURE__ */
|
|
145
|
+
children: /* @__PURE__ */ d("p", {
|
|
144
146
|
className: "text-xs text-text-tertiary",
|
|
145
|
-
children:
|
|
147
|
+
children: O.length > 0 ? v("vibecontrols.agentManager.filePicker.footerShowing", "Showing {{shown}} of {{total}} file{{suffix}}", {
|
|
148
|
+
shown: O.length,
|
|
149
|
+
total: k,
|
|
150
|
+
suffix: k === 1 ? "" : "s"
|
|
151
|
+
}) : v("vibecontrols.agentManager.filePicker.footerPrompt", "Select a file to attach it as conversation context.")
|
|
146
152
|
})
|
|
147
153
|
})
|
|
148
154
|
]
|
|
@@ -150,6 +156,6 @@ function p({ isOpen: p, onClose: m, agent: h, sessionId: g }) {
|
|
|
150
156
|
});
|
|
151
157
|
}
|
|
152
158
|
//#endregion
|
|
153
|
-
export {
|
|
159
|
+
export { m as FilePickerModal };
|
|
154
160
|
|
|
155
161
|
//# sourceMappingURL=FilePickerModal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePickerModal.js","names":[],"sources":["../../../src/components/agent-manager/FilePickerModal.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { X, FileText, Loader2, Paperclip } from 'lucide-react';\nimport {\n useGetWorkspaceFilesQuery,\n useGetFileDownloadUrlLazyQuery,\n type GetWorkspaceFilesQuery,\n} from '@/generated/wspace-operations';\nimport { fetchFileIntoContext, type AgentRef } from '@/services/aiApi';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport type { ChatContextItem } from '@/types/agentManager';\n\ninterface FilePickerModalProps {\n isOpen: boolean;\n onClose: () => void;\n agent: AgentRef;\n sessionId: string;\n}\n\ntype WorkspaceFile = GetWorkspaceFilesQuery['getFiles']['files'][number];\n\nfunction formatFileSize(size: string): string {\n const bytes = Number(size);\n if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n const value = bytes / Math.pow(1024, exponent);\n return `${value.toFixed(exponent === 0 ? 0 : 1)} ${units[exponent]}`;\n}\n\nexport function FilePickerModal({\n isOpen,\n onClose,\n agent,\n sessionId,\n}: FilePickerModalProps): React.ReactElement | null {\n const { data, loading } = useGetWorkspaceFilesQuery({\n variables: { pagination: { limit: 50, offset: 0 } },\n skip: !isOpen,\n fetchPolicy: 'cache-and-network',\n });\n const [getDownloadUrl] = useGetFileDownloadUrlLazyQuery();\n const addSessionContext = useAgentManagerStore((s) => s.addSessionContext);\n\n const [attachingId, setAttachingId] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const handleAttach = useCallback(\n async (file: WorkspaceFile): Promise<void> => {\n setError(null);\n setAttachingId(file.id);\n try {\n const res = await getDownloadUrl({ variables: { id: file.id, expiresIn: 300 } });\n const url = res.data?.getFileDownloadUrl;\n if (!url) {\n setError('Could not get a download URL for this file.');\n return;\n }\n const out = await fetchFileIntoContext(agent, {\n downloadUrl: url,\n filename: file.name,\n sessionId,\n });\n const item: ChatContextItem = {\n id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n kind: 'file',\n label: file.name,\n path: out.path,\n content: out.inline ?? null,\n };\n addSessionContext(sessionId, item);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to attach file');\n } finally {\n setAttachingId(null);\n }\n },\n [agent, sessionId, getDownloadUrl, addSessionContext, onClose]\n );\n\n if (!isOpen) return null;\n\n const files: WorkspaceFile[] = data?.getFiles?.files ?? [];\n const total = data?.getFiles?.total ?? files.length;\n const hasMore = data?.getFiles?.hasMore ?? false;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClose();\n }\n }}\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={onClose}\n />\n <div\n data-testid=\"file-picker-modal\"\n className=\"relative w-full max-w-lg mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl\"\n >\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Add file as context</h3>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {error && (\n <div className=\"mx-6 mt-4 px-3 py-2 rounded-md bg-action-danger-bg text-action-danger-text text-sm\">\n {error}\n </div>\n )}\n\n <div className=\"max-h-80 overflow-y-auto px-2 py-2\">\n {loading && files.length === 0 ? (\n <div className=\"flex items-center justify-center gap-2 px-4 py-12 text-text-secondary\">\n <Loader2 className=\"size-5 animate-spin\" />\n <span className=\"text-sm\">Loading files…</span>\n </div>\n ) : files.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center gap-2 px-4 py-12 text-center\">\n <FileText className=\"size-8 text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary\">No files found in this workspace.</p>\n </div>\n ) : (\n <ul className=\"space-y-1\">\n {files.map((file) => {\n const isAttaching = attachingId === file.id;\n return (\n <li\n key={file.id}\n className=\"flex items-center gap-3 px-3 py-2 rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <FileText className=\"size-5 shrink-0 text-text-tertiary\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{file.name}</p>\n <p className=\"text-xs text-text-tertiary\">\n {formatFileSize(file.size)}\n {file.extension ? ` · ${file.extension}` : ''}\n </p>\n </div>\n <button\n type=\"button\"\n data-testid=\"file-picker-attach\"\n onClick={() => void handleAttach(file)}\n disabled={attachingId !== null}\n className=\"inline-flex items-center gap-1.5 px-3 py-1 text-sm rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-60 disabled:cursor-not-allowed transition-colors\"\n >\n {isAttaching ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Paperclip className=\"size-4\" />\n )}\n <span>{isAttaching ? 'Attaching…' : 'Attach'}</span>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n\n <div className=\"px-6 py-3 border-t border-border-default bg-bg-sunken rounded-b-lg\">\n <p className=\"text-xs text-text-tertiary\">\n {files.length > 0\n ? `Showing ${files.length} of ${total} file${total === 1 ? '' : 's'}${\n hasMore ? ' (more available)' : ''\n }`\n : 'Select a file to attach it as conversation context.'}\n </p>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FilePickerModal.js","names":[],"sources":["../../../src/components/agent-manager/FilePickerModal.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\nimport { X, FileText, Loader2, Paperclip } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport {\n useGetWorkspaceFilesQuery,\n useGetFileDownloadUrlLazyQuery,\n type GetWorkspaceFilesQuery,\n} from '@/generated/wspace-operations';\nimport { fetchFileIntoContext, type AgentRef } from '@/services/aiApi';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport type { ChatContextItem } from '@/types/agentManager';\n\ninterface FilePickerModalProps {\n isOpen: boolean;\n onClose: () => void;\n agent: AgentRef;\n sessionId: string;\n}\n\ntype WorkspaceFile = GetWorkspaceFilesQuery['getFiles']['files'][number];\n\nfunction formatFileSize(size: string): string {\n const bytes = Number(size);\n if (!Number.isFinite(bytes) || bytes <= 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n const value = bytes / Math.pow(1024, exponent);\n return `${value.toFixed(exponent === 0 ? 0 : 1)} ${units[exponent]}`;\n}\n\nexport function FilePickerModal({\n isOpen,\n onClose,\n agent,\n sessionId,\n}: FilePickerModalProps): React.ReactElement | null {\n const tr = useTr();\n const { data, loading } = useGetWorkspaceFilesQuery({\n variables: { pagination: { limit: 50, offset: 0 } },\n skip: !isOpen,\n fetchPolicy: 'cache-and-network',\n });\n const [getDownloadUrl] = useGetFileDownloadUrlLazyQuery();\n const addSessionContext = useAgentManagerStore((s) => s.addSessionContext);\n\n const [attachingId, setAttachingId] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const handleAttach = useCallback(\n async (file: WorkspaceFile): Promise<void> => {\n setError(null);\n setAttachingId(file.id);\n try {\n const res = await getDownloadUrl({ variables: { id: file.id, expiresIn: 300 } });\n const url = res.data?.getFileDownloadUrl;\n if (!url) {\n setError(\n tr(\n 'vibecontrols.agentManager.filePicker.errorDownloadUrl',\n 'Could not get a download URL for this file.'\n )\n );\n return;\n }\n const out = await fetchFileIntoContext(agent, {\n downloadUrl: url,\n filename: file.name,\n sessionId,\n });\n const item: ChatContextItem = {\n id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n kind: 'file',\n label: file.name,\n path: out.path,\n content: out.inline ?? null,\n };\n addSessionContext(sessionId, item);\n onClose();\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr('vibecontrols.agentManager.filePicker.errorAttachFailed', 'Failed to attach file')\n );\n } finally {\n setAttachingId(null);\n }\n },\n [agent, sessionId, getDownloadUrl, addSessionContext, onClose, tr]\n );\n\n if (!isOpen) return null;\n\n const files: WorkspaceFile[] = data?.getFiles?.files ?? [];\n const total = data?.getFiles?.total ?? files.length;\n const hasMore = data?.getFiles?.hasMore ?? false;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClose();\n }\n }}\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={onClose}\n />\n <div\n data-testid=\"file-picker-modal\"\n className=\"relative w-full max-w-lg mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl\"\n >\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.agentManager.filePicker.title', 'Add file as context')}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label={tr('vibecontrols.agentManager.filePicker.closeAriaLabel', 'Close')}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {error && (\n <div className=\"mx-6 mt-4 px-3 py-2 rounded-md bg-action-danger-bg text-action-danger-text text-sm\">\n {error}\n </div>\n )}\n\n <div className=\"max-h-80 overflow-y-auto px-2 py-2\">\n {loading && files.length === 0 ? (\n <div className=\"flex items-center justify-center gap-2 px-4 py-12 text-text-secondary\">\n <Loader2 className=\"size-5 animate-spin\" />\n <span className=\"text-sm\">\n {tr('vibecontrols.agentManager.filePicker.loading', 'Loading files…')}\n </span>\n </div>\n ) : files.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center gap-2 px-4 py-12 text-center\">\n <FileText className=\"size-8 text-text-tertiary\" />\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.agentManager.filePicker.emptyDescription',\n 'No files found in this workspace.'\n )}\n </p>\n </div>\n ) : (\n <ul className=\"space-y-1\">\n {files.map((file) => {\n const isAttaching = attachingId === file.id;\n return (\n <li\n key={file.id}\n className=\"flex items-center gap-3 px-3 py-2 rounded-md hover:bg-bg-elevated transition-colors\"\n >\n <FileText className=\"size-5 shrink-0 text-text-tertiary\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{file.name}</p>\n <p className=\"text-xs text-text-tertiary\">\n {formatFileSize(file.size)}\n {file.extension ? ` · ${file.extension}` : ''}\n </p>\n </div>\n <button\n type=\"button\"\n data-testid=\"file-picker-attach\"\n onClick={() => void handleAttach(file)}\n disabled={attachingId !== null}\n className=\"inline-flex items-center gap-1.5 px-3 py-1 text-sm rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-60 disabled:cursor-not-allowed transition-colors\"\n >\n {isAttaching ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Paperclip className=\"size-4\" />\n )}\n <span>\n {isAttaching\n ? tr('vibecontrols.agentManager.filePicker.attaching', 'Attaching…')\n : tr('vibecontrols.agentManager.filePicker.attach', 'Attach')}\n </span>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n\n <div className=\"px-6 py-3 border-t border-border-default bg-bg-sunken rounded-b-lg\">\n <p className=\"text-xs text-text-tertiary\">\n {files.length > 0\n ? tr(\n 'vibecontrols.agentManager.filePicker.footerShowing',\n 'Showing {{shown}} of {{total}} file{{suffix}}',\n {\n shown: files.length,\n total,\n suffix: total === 1 ? '' : 's',\n }\n )\n : tr(\n 'vibecontrols.agentManager.filePicker.footerPrompt',\n 'Select a file to attach it as conversation context.'\n )}\n </p>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,74 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
+
import { getNodeTypeConfig as t } from "./nodeIcons.js";
|
|
3
|
+
import { memo as n } from "react";
|
|
4
|
+
import { Bot as r, User as i, Users as a } from "lucide-react";
|
|
5
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
6
|
+
import { Handle as c, Position as l } from "@xyflow/react";
|
|
6
7
|
//#region src/components/graph/MeshAgentNode.tsx
|
|
7
|
-
function
|
|
8
|
-
let
|
|
9
|
-
return /* @__PURE__ */
|
|
10
|
-
className: `rounded-lg border bg-bg-surface shadow-[var(--shadow-elevation-0)] p-2.5 flex flex-col gap-1.5 transition-shadow hover:shadow-[var(--shadow-elevation-1)] ${
|
|
8
|
+
function u({ data: n, selected: u }) {
|
|
9
|
+
let d = e(), f = n, p = t(f.hostType), m = p.icon, h = f.isShared ? a : i;
|
|
10
|
+
return /* @__PURE__ */ s("div", {
|
|
11
|
+
className: `rounded-lg border bg-bg-surface shadow-[var(--shadow-elevation-0)] p-2.5 flex flex-col gap-1.5 transition-shadow hover:shadow-[var(--shadow-elevation-1)] ${u ? "border-action-primary-bg ring-1 ring-action-primary-bg/40" : "border-border-default"}`,
|
|
11
12
|
style: { width: 200 },
|
|
12
|
-
role:
|
|
13
|
-
tabIndex:
|
|
14
|
-
"aria-label":
|
|
13
|
+
role: f.onActivate ? "button" : void 0,
|
|
14
|
+
tabIndex: f.onActivate ? 0 : void 0,
|
|
15
|
+
"aria-label": f.onActivate ? `Open agent ${f.name}` : void 0,
|
|
15
16
|
onKeyDown: (e) => {
|
|
16
|
-
|
|
17
|
+
f.onActivate && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), f.onActivate());
|
|
17
18
|
},
|
|
18
19
|
children: [
|
|
19
|
-
/* @__PURE__ */
|
|
20
|
+
/* @__PURE__ */ o(c, {
|
|
20
21
|
type: "target",
|
|
21
|
-
position:
|
|
22
|
+
position: l.Left,
|
|
22
23
|
className: "!bg-text-tertiary !w-2 !h-2 !border-0"
|
|
23
24
|
}),
|
|
24
|
-
/* @__PURE__ */
|
|
25
|
+
/* @__PURE__ */ o(c, {
|
|
25
26
|
type: "source",
|
|
26
|
-
position:
|
|
27
|
+
position: l.Right,
|
|
27
28
|
className: "!bg-action-primary-bg !w-2 !h-2 !border-0"
|
|
28
29
|
}),
|
|
29
|
-
/* @__PURE__ */
|
|
30
|
+
/* @__PURE__ */ s("div", {
|
|
30
31
|
className: "flex items-center gap-2",
|
|
31
32
|
children: [
|
|
32
|
-
/* @__PURE__ */
|
|
33
|
+
/* @__PURE__ */ o(r, {
|
|
33
34
|
size: 14,
|
|
34
35
|
className: "text-action-primary-bg shrink-0"
|
|
35
36
|
}),
|
|
36
|
-
/* @__PURE__ */
|
|
37
|
+
/* @__PURE__ */ s("div", {
|
|
37
38
|
className: "min-w-0 flex-1",
|
|
38
|
-
children: [/* @__PURE__ */
|
|
39
|
+
children: [/* @__PURE__ */ o("div", {
|
|
39
40
|
className: "text-xs font-semibold text-text-primary truncate",
|
|
40
|
-
children:
|
|
41
|
-
}),
|
|
41
|
+
children: f.name
|
|
42
|
+
}), f.version ? /* @__PURE__ */ s("div", {
|
|
42
43
|
className: "text-[10px] text-text-tertiary",
|
|
43
|
-
children: ["v",
|
|
44
|
+
children: ["v", f.version]
|
|
44
45
|
}) : null]
|
|
45
46
|
}),
|
|
46
|
-
/* @__PURE__ */
|
|
47
|
+
/* @__PURE__ */ o(h, {
|
|
47
48
|
size: 12,
|
|
48
|
-
className: `shrink-0 ${
|
|
49
|
-
"aria-label":
|
|
49
|
+
className: `shrink-0 ${f.isShared ? "text-text-tertiary" : "text-text-secondary"}`,
|
|
50
|
+
"aria-label": f.isShared ? d("vibecontrols.graph.sharedAgent", "Shared agent") : d("vibecontrols.graph.personalAgent", "Personal agent")
|
|
50
51
|
}),
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
-
className: `size-2 rounded-full shrink-0 ${
|
|
53
|
-
title:
|
|
52
|
+
/* @__PURE__ */ o("span", {
|
|
53
|
+
className: `size-2 rounded-full shrink-0 ${f.isActive ? "bg-status-success-bg" : "bg-bg-disabled"}`,
|
|
54
|
+
title: f.isActive ? d("vibecontrols.graph.agentStatusActive", "Active") : d("vibecontrols.graph.agentStatusOffline", "Offline")
|
|
54
55
|
})
|
|
55
56
|
]
|
|
56
57
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
+
/* @__PURE__ */ s("div", {
|
|
58
59
|
className: "flex items-center gap-1",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
60
|
-
className: `inline-flex items-center gap-1 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wider rounded ${
|
|
61
|
-
children: [/* @__PURE__ */
|
|
62
|
-
}),
|
|
60
|
+
children: [/* @__PURE__ */ s("span", {
|
|
61
|
+
className: `inline-flex items-center gap-1 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wider rounded ${p.badge}`,
|
|
62
|
+
children: [/* @__PURE__ */ o(m, { size: 9 }), f.hostType ?? "HOST"]
|
|
63
|
+
}), f.hostLabel ? /* @__PURE__ */ o("span", {
|
|
63
64
|
className: "text-[10px] text-text-tertiary truncate",
|
|
64
|
-
children:
|
|
65
|
+
children: f.hostLabel
|
|
65
66
|
}) : null]
|
|
66
67
|
})
|
|
67
68
|
]
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
|
-
var
|
|
71
|
+
var d = n(u);
|
|
71
72
|
//#endregion
|
|
72
|
-
export {
|
|
73
|
+
export { d as MeshAgentNode };
|
|
73
74
|
|
|
74
75
|
//# sourceMappingURL=MeshAgentNode.js.map
|