@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.
@@ -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": "e.g., work, personal, minimal",
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": "owner/repo or full GitHub URL",
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": "e.g., editor, default_harness, profile_marker",
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 { fetchFileIntoContext as n } from "../../services/aiApi.js";
3
- import { useAgentManagerStore as r } from "../../store/agentManagerStore.js";
4
- import { useCallback as i, useState as a } from "react";
5
- import { FileText as o, Loader2 as s, Paperclip as c, X as l } from "lucide-react";
6
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
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 f(e) {
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 p({ isOpen: p, onClose: m, agent: h, sessionId: g }) {
21
- let { data: _, loading: v } = t({
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: !p,
27
+ skip: !m,
27
28
  fetchPolicy: "cache-and-network"
28
- }), [y] = e(), b = r((e) => e.addSessionContext), [x, S] = a(null), [C, w] = a(null), T = i(async (e) => {
29
- w(null), S(e.id);
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 y({ variables: {
32
+ let t = (await x({ variables: {
32
33
  id: e.id,
33
34
  expiresIn: 300
34
35
  } })).data?.getFileDownloadUrl;
35
36
  if (!t) {
36
- w("Could not get a download URL for this file.");
37
+ E(v("vibecontrols.agentManager.filePicker.errorDownloadUrl", "Could not get a download URL for this file."));
37
38
  return;
38
39
  }
39
- let r = await n(h, {
40
+ let n = await r(g, {
40
41
  downloadUrl: t,
41
42
  filename: e.name,
42
- sessionId: g
43
+ sessionId: _
43
44
  });
44
- b(g, {
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: r.path,
49
- content: r.inline ?? null
50
- }), m();
49
+ path: n.path,
50
+ content: n.inline ?? null
51
+ }), h();
51
52
  } catch (e) {
52
- w(e instanceof Error ? e.message : "Failed to attach file");
53
+ E(e instanceof Error ? e.message : v("vibecontrols.agentManager.filePicker.errorAttachFailed", "Failed to attach file"));
53
54
  } finally {
54
- S(null);
55
+ w(null);
55
56
  }
56
57
  }, [
57
- h,
58
58
  g,
59
- y,
60
- b,
61
- m
59
+ _,
60
+ x,
61
+ S,
62
+ h,
63
+ v
62
64
  ]);
63
- if (!p) return null;
64
- let E = _?.getFiles?.files ?? [], D = _?.getFiles?.total ?? E.length, O = _?.getFiles?.hasMore ?? !1;
65
- return /* @__PURE__ */ d("div", {
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__ */ u("div", {
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(), m());
73
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), h());
72
74
  },
73
75
  className: "absolute inset-0 bg-bg-overlay",
74
- onClick: m
75
- }), /* @__PURE__ */ d("div", {
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__ */ d("div", {
81
+ /* @__PURE__ */ f("div", {
80
82
  className: "flex items-center justify-between px-6 py-4 border-b border-border-default",
81
- children: [/* @__PURE__ */ u("h3", {
83
+ children: [/* @__PURE__ */ d("h3", {
82
84
  className: "text-lg font-semibold text-text-primary",
83
- children: "Add file as context"
84
- }), /* @__PURE__ */ u("button", {
85
+ children: v("vibecontrols.agentManager.filePicker.title", "Add file as context")
86
+ }), /* @__PURE__ */ d("button", {
85
87
  type: "button",
86
- onClick: m,
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(l, { className: "size-5 text-text-secondary" })
91
+ children: /* @__PURE__ */ d(u, { className: "size-5 text-text-secondary" })
90
92
  })]
91
93
  }),
92
- C && /* @__PURE__ */ u("div", {
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: C
96
+ children: T
95
97
  }),
96
- /* @__PURE__ */ u("div", {
98
+ /* @__PURE__ */ d("div", {
97
99
  className: "max-h-80 overflow-y-auto px-2 py-2",
98
- children: v && E.length === 0 ? /* @__PURE__ */ d("div", {
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__ */ u(s, { className: "size-5 animate-spin" }), /* @__PURE__ */ u("span", {
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
- }) : E.length === 0 ? /* @__PURE__ */ d("div", {
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__ */ u(o, { className: "size-8 text-text-tertiary" }), /* @__PURE__ */ u("p", {
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__ */ u("ul", {
112
+ }) : /* @__PURE__ */ d("ul", {
111
113
  className: "space-y-1",
112
- children: E.map((e) => {
113
- let t = x === e.id;
114
- return /* @__PURE__ */ d("li", {
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__ */ u(o, { className: "size-5 shrink-0 text-text-tertiary" }),
118
- /* @__PURE__ */ d("div", {
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__ */ u("p", {
122
+ children: [/* @__PURE__ */ d("p", {
121
123
  className: "truncate text-sm font-medium text-text-primary",
122
124
  children: e.name
123
- }), /* @__PURE__ */ d("p", {
125
+ }), /* @__PURE__ */ f("p", {
124
126
  className: "text-xs text-text-tertiary",
125
- children: [f(e.size), e.extension ? ` · ${e.extension}` : ""]
127
+ children: [p(e.size), e.extension ? ` · ${e.extension}` : ""]
126
128
  })]
127
129
  }),
128
- /* @__PURE__ */ d("button", {
130
+ /* @__PURE__ */ f("button", {
129
131
  type: "button",
130
132
  "data-testid": "file-picker-attach",
131
- onClick: () => void T(e),
132
- disabled: x !== null,
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__ */ u(s, { className: "size-4 animate-spin" }) : /* @__PURE__ */ u(c, { className: "size-4" }), /* @__PURE__ */ u("span", { children: t ? "Attaching…" : "Attach" })]
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__ */ u("div", {
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__ */ u("p", {
145
+ children: /* @__PURE__ */ d("p", {
144
146
  className: "text-xs text-text-tertiary",
145
- children: E.length > 0 ? `Showing ${E.length} of ${D} file${D === 1 ? "" : "s"}${O ? " (more available)" : ""}` : "Select a file to attach it as conversation context."
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 { p as FilePickerModal };
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 { getNodeTypeConfig as e } from "./nodeIcons.js";
2
- import { memo as t } from "react";
3
- import { Bot as n, User as r, Users as i } from "lucide-react";
4
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
- import { Handle as s, Position as c } from "@xyflow/react";
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 l({ data: t, selected: l }) {
8
- let u = t, d = e(u.hostType), f = d.icon, p = u.isShared ? i : r;
9
- return /* @__PURE__ */ o("div", {
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)] ${l ? "border-action-primary-bg ring-1 ring-action-primary-bg/40" : "border-border-default"}`,
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: u.onActivate ? "button" : void 0,
13
- tabIndex: u.onActivate ? 0 : void 0,
14
- "aria-label": u.onActivate ? `Open agent ${u.name}` : void 0,
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
- u.onActivate && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), u.onActivate());
17
+ f.onActivate && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), f.onActivate());
17
18
  },
18
19
  children: [
19
- /* @__PURE__ */ a(s, {
20
+ /* @__PURE__ */ o(c, {
20
21
  type: "target",
21
- position: c.Left,
22
+ position: l.Left,
22
23
  className: "!bg-text-tertiary !w-2 !h-2 !border-0"
23
24
  }),
24
- /* @__PURE__ */ a(s, {
25
+ /* @__PURE__ */ o(c, {
25
26
  type: "source",
26
- position: c.Right,
27
+ position: l.Right,
27
28
  className: "!bg-action-primary-bg !w-2 !h-2 !border-0"
28
29
  }),
29
- /* @__PURE__ */ o("div", {
30
+ /* @__PURE__ */ s("div", {
30
31
  className: "flex items-center gap-2",
31
32
  children: [
32
- /* @__PURE__ */ a(n, {
33
+ /* @__PURE__ */ o(r, {
33
34
  size: 14,
34
35
  className: "text-action-primary-bg shrink-0"
35
36
  }),
36
- /* @__PURE__ */ o("div", {
37
+ /* @__PURE__ */ s("div", {
37
38
  className: "min-w-0 flex-1",
38
- children: [/* @__PURE__ */ a("div", {
39
+ children: [/* @__PURE__ */ o("div", {
39
40
  className: "text-xs font-semibold text-text-primary truncate",
40
- children: u.name
41
- }), u.version ? /* @__PURE__ */ o("div", {
41
+ children: f.name
42
+ }), f.version ? /* @__PURE__ */ s("div", {
42
43
  className: "text-[10px] text-text-tertiary",
43
- children: ["v", u.version]
44
+ children: ["v", f.version]
44
45
  }) : null]
45
46
  }),
46
- /* @__PURE__ */ a(p, {
47
+ /* @__PURE__ */ o(h, {
47
48
  size: 12,
48
- className: `shrink-0 ${u.isShared ? "text-text-tertiary" : "text-text-secondary"}`,
49
- "aria-label": u.isShared ? "Shared agent" : "Personal agent"
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__ */ a("span", {
52
- className: `size-2 rounded-full shrink-0 ${u.isActive ? "bg-status-success-bg" : "bg-bg-disabled"}`,
53
- title: u.isActive ? "Active" : "Offline"
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__ */ o("div", {
58
+ /* @__PURE__ */ s("div", {
58
59
  className: "flex items-center gap-1",
59
- children: [/* @__PURE__ */ o("span", {
60
- className: `inline-flex items-center gap-1 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wider rounded ${d.badge}`,
61
- children: [/* @__PURE__ */ a(f, { size: 9 }), u.hostType ?? "HOST"]
62
- }), u.hostLabel ? /* @__PURE__ */ a("span", {
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: u.hostLabel
65
+ children: f.hostLabel
65
66
  }) : null]
66
67
  })
67
68
  ]
68
69
  });
69
70
  }
70
- var u = t(l);
71
+ var d = n(u);
71
72
  //#endregion
72
- export { u as MeshAgentNode };
73
+ export { d as MeshAgentNode };
73
74
 
74
75
  //# sourceMappingURL=MeshAgentNode.js.map