@burdenoff/microfe-vibecontrols 2026.521.3 → 2026.522.2
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/VibeControlsRoot.js +86 -78
- package/dist/VibeControlsRoot.js.map +1 -1
- package/dist/VibeControlsRoutes.js +168 -125
- package/dist/VibeControlsRoutes.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerBookmarksDrawer.js +174 -0
- package/dist/components/agent-manager/AgentManagerBookmarksDrawer.js.map +1 -0
- package/dist/components/agent-manager/AgentManagerChatPane.js +149 -94
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js +52 -41
- package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageList.js +22 -15
- package/dist/components/agent-manager/AgentManagerMessageList.js.map +1 -1
- package/dist/components/agents/OpenInEditorMenu.js +241 -0
- package/dist/components/agents/OpenInEditorMenu.js.map +1 -0
- package/dist/components/agents/VibeOpenInEditorMenu.js +20 -0
- package/dist/components/agents/VibeOpenInEditorMenu.js.map +1 -0
- package/dist/components/agents/idePresets.js +148 -0
- package/dist/components/agents/idePresets.js.map +1 -0
- package/dist/components/agents/index.js +3 -0
- package/dist/components/ai/AIPlanPanel.js +332 -0
- package/dist/components/ai/AIPlanPanel.js.map +1 -0
- package/dist/components/analytics/index.js +2 -2
- package/dist/components/assistant/AssistantMessageItem.js +55 -47
- package/dist/components/assistant/AssistantMessageItem.js.map +1 -1
- package/dist/components/audit/AuditExportButton.js +87 -41
- package/dist/components/audit/AuditExportButton.js.map +1 -1
- package/dist/components/gitops/CIDurationChart.js +11 -11
- package/dist/components/security/SecurityEmptyState.js +33 -0
- package/dist/components/security/SecurityEmptyState.js.map +1 -0
- package/dist/components/security/SecurityEvidenceList.js +42 -0
- package/dist/components/security/SecurityEvidenceList.js.map +1 -0
- package/dist/components/security/SecurityFindingsTable.js +201 -0
- package/dist/components/security/SecurityFindingsTable.js.map +1 -0
- package/dist/components/security/SecurityHeaderStrip.js +67 -0
- package/dist/components/security/SecurityHeaderStrip.js.map +1 -0
- package/dist/components/security/SecurityLifecycleStepper.js +66 -0
- package/dist/components/security/SecurityLifecycleStepper.js.map +1 -0
- package/dist/components/security/SecurityProviderDrawer.js +112 -0
- package/dist/components/security/SecurityProviderDrawer.js.map +1 -0
- package/dist/components/security/SecurityTabPanel.js +105 -0
- package/dist/components/security/SecurityTabPanel.js.map +1 -0
- package/dist/components/security/gql.js +128 -0
- package/dist/components/security/gql.js.map +1 -0
- package/dist/components/security/index.js +8 -0
- package/dist/components/security/types.js +80 -0
- package/dist/components/security/types.js.map +1 -0
- package/dist/components/settings/IdePreferencesSection.js +66 -0
- package/dist/components/settings/IdePreferencesSection.js.map +1 -0
- package/dist/components/shared/PageSkeleton.js +88 -0
- package/dist/components/shared/PageSkeleton.js.map +1 -0
- package/dist/constants/pluginCatalog.js +20 -8
- package/dist/constants/pluginCatalog.js.map +1 -1
- package/dist/generated/wspace-operations.js +1350 -1262
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/hooks/useToggleAgentBookmark.js +32 -0
- package/dist/hooks/useToggleAgentBookmark.js.map +1 -0
- package/dist/index.js +10 -10
- package/dist/pages/AgentDetailsPage.js +25 -25
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +326 -327
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/AnalyticsPage.js +425 -420
- package/dist/pages/AnalyticsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +258 -249
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +22 -22
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +30 -30
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +23 -23
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/LogsPage.js +107 -0
- package/dist/pages/LogsPage.js.map +1 -0
- package/dist/pages/NoteDetailsPage.js +12 -12
- package/dist/pages/NoteDetailsPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +12 -12
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +158 -136
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/SettingsPage.js +60 -52
- package/dist/pages/SettingsPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +18 -18
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +328 -331
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +17 -17
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +17 -17
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +552 -535
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibesPage.js +321 -296
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +184 -0
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -0
- package/dist/pages/ai/AIPage.js +138 -109
- package/dist/pages/ai/AIPage.js.map +1 -1
- package/dist/services/planApi.js +18 -0
- package/dist/services/planApi.js.map +1 -0
- package/dist/store/vibeControlsStore.js +20 -2
- package/dist/store/vibeControlsStore.js.map +1 -1
- package/dist/translations/en.js +30 -1
- package/dist/translations/en.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
//#region src/components/agents/idePresets.ts
|
|
2
|
+
var e = Object.freeze([
|
|
3
|
+
{
|
|
4
|
+
command: "code",
|
|
5
|
+
label: "VS Code",
|
|
6
|
+
family: "vscode",
|
|
7
|
+
protocol: "vscode",
|
|
8
|
+
protocolShape: "vscode"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
command: "code-insiders",
|
|
12
|
+
label: "VS Code (Insiders)",
|
|
13
|
+
family: "vscode",
|
|
14
|
+
protocol: "vscode-insiders",
|
|
15
|
+
protocolShape: "vscode"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
command: "codium",
|
|
19
|
+
label: "VSCodium",
|
|
20
|
+
family: "vscode",
|
|
21
|
+
protocol: "vscodium",
|
|
22
|
+
protocolShape: "vscode"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
command: "cursor",
|
|
26
|
+
label: "Cursor",
|
|
27
|
+
family: "vscode",
|
|
28
|
+
protocol: "cursor",
|
|
29
|
+
protocolShape: "vscode"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
command: "idea",
|
|
33
|
+
label: "IntelliJ IDEA",
|
|
34
|
+
family: "jetbrains",
|
|
35
|
+
protocol: "idea",
|
|
36
|
+
protocolShape: "jetbrains"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
command: "pycharm",
|
|
40
|
+
label: "PyCharm",
|
|
41
|
+
family: "jetbrains",
|
|
42
|
+
protocol: "pycharm",
|
|
43
|
+
protocolShape: "jetbrains"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
command: "webstorm",
|
|
47
|
+
label: "WebStorm",
|
|
48
|
+
family: "jetbrains",
|
|
49
|
+
protocol: "webstorm",
|
|
50
|
+
protocolShape: "jetbrains"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
command: "goland",
|
|
54
|
+
label: "GoLand",
|
|
55
|
+
family: "jetbrains",
|
|
56
|
+
protocol: "goland",
|
|
57
|
+
protocolShape: "jetbrains"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
command: "phpstorm",
|
|
61
|
+
label: "PhpStorm",
|
|
62
|
+
family: "jetbrains",
|
|
63
|
+
protocol: "phpstorm",
|
|
64
|
+
protocolShape: "jetbrains"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
command: "rubymine",
|
|
68
|
+
label: "RubyMine",
|
|
69
|
+
family: "jetbrains",
|
|
70
|
+
protocol: "rubymine",
|
|
71
|
+
protocolShape: "jetbrains"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
command: "clion",
|
|
75
|
+
label: "CLion",
|
|
76
|
+
family: "jetbrains",
|
|
77
|
+
protocol: "clion",
|
|
78
|
+
protocolShape: "jetbrains"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
command: "rider",
|
|
82
|
+
label: "Rider",
|
|
83
|
+
family: "jetbrains",
|
|
84
|
+
protocol: "rider",
|
|
85
|
+
protocolShape: "jetbrains"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
command: "zed",
|
|
89
|
+
label: "Zed",
|
|
90
|
+
family: "other",
|
|
91
|
+
protocol: "zed",
|
|
92
|
+
protocolShape: "vscode"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
command: "fleet",
|
|
96
|
+
label: "JetBrains Fleet",
|
|
97
|
+
family: "jetbrains"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
command: "subl",
|
|
101
|
+
label: "Sublime Text",
|
|
102
|
+
family: "other"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
command: "neovide",
|
|
106
|
+
label: "Neovide",
|
|
107
|
+
family: "other"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
command: "helix",
|
|
111
|
+
label: "Helix",
|
|
112
|
+
family: "terminal",
|
|
113
|
+
hint: "Terminal editor — requires an attached session"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
command: "vim",
|
|
117
|
+
label: "Vim",
|
|
118
|
+
family: "terminal",
|
|
119
|
+
hint: "Terminal editor — requires an attached session"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
command: "nvim",
|
|
123
|
+
label: "Neovim",
|
|
124
|
+
family: "terminal",
|
|
125
|
+
hint: "Terminal editor — requires an attached session"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
command: "emacs",
|
|
129
|
+
label: "Emacs",
|
|
130
|
+
family: "terminal",
|
|
131
|
+
hint: "Terminal editor — requires an attached session"
|
|
132
|
+
}
|
|
133
|
+
]), t = new Map(e.map((e) => [e.command, e]));
|
|
134
|
+
function n(e) {
|
|
135
|
+
return e ? t.get(e) ?? null : null;
|
|
136
|
+
}
|
|
137
|
+
function r(e, t) {
|
|
138
|
+
if (!e.protocol) return null;
|
|
139
|
+
let n = t.startsWith("/") ? t.slice(1) : t;
|
|
140
|
+
return e.protocolShape === "jetbrains" ? `${e.protocol}://open?file=${encodeURIComponent(t)}` : `${e.protocol}://file/${n}`;
|
|
141
|
+
}
|
|
142
|
+
function i(e, t, n) {
|
|
143
|
+
return n?.[e] || t || "code";
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { e as IDE_PRESETS, r as buildProtocolUrl, n as getIdePreset, i as resolveEffectiveIdeCommand };
|
|
147
|
+
|
|
148
|
+
//# sourceMappingURL=idePresets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idePresets.js","names":[],"sources":["../../../src/components/agents/idePresets.ts"],"sourcesContent":["/**\n * IDE preset catalog — single source of truth for the frontend.\n *\n * Each entry describes one launch target the \"Open in editor\" menu can\n * offer. The token in `command` is what the user-preference + per-Vibe\n * override store on the backend; it's also what the agent's\n * `/api/editor/open` allowlist matches against. Keep this list in sync\n * with:\n * - wspace-vibecontrols-svc settings.service `KNOWN_IDE_COMMANDS`\n * - vibecontrols-agent routes/editor.routes `ALLOWED_COMMANDS`\n *\n * `protocol` is optional — when present, the menu offers a one-click\n * deep-link launch that doesn't require an online agent. Browsers\n * silently no-op the navigation when the OS has no handler registered,\n * which is why we also surface the agent-exec fallback for every entry.\n */\n\nexport type IdeLaunchMode = 'protocol' | 'agent' | 'both';\n\nexport interface IdePreset {\n /** Allowlisted command token. Frozen contract — see header. */\n command: string;\n /** Display name shown in menus. */\n label: string;\n /** Short vendor / family tag, used to group in pickers. */\n family: 'vscode' | 'jetbrains' | 'terminal' | 'other';\n /**\n * `vscode`/`cursor`/`idea`/`pycharm`/... — these IDEs ship URL\n * handlers; we deep-link via `<protocol>://file/<path>` (VS Code\n * family) or `<protocol>://open?file=<path>` (JetBrains family).\n * When unset, only agent-exec works.\n */\n protocol?: string;\n /** Shape of the protocol URL — varies by IDE family. */\n protocolShape?: 'vscode' | 'jetbrains';\n /** Hint shown as the menu item subtitle / tooltip. */\n hint?: string;\n}\n\nexport const IDE_PRESETS: readonly IdePreset[] = Object.freeze([\n {\n command: 'code',\n label: 'VS Code',\n family: 'vscode',\n protocol: 'vscode',\n protocolShape: 'vscode',\n },\n {\n command: 'code-insiders',\n label: 'VS Code (Insiders)',\n family: 'vscode',\n protocol: 'vscode-insiders',\n protocolShape: 'vscode',\n },\n {\n command: 'codium',\n label: 'VSCodium',\n family: 'vscode',\n protocol: 'vscodium',\n protocolShape: 'vscode',\n },\n {\n command: 'cursor',\n label: 'Cursor',\n family: 'vscode',\n protocol: 'cursor',\n protocolShape: 'vscode',\n },\n {\n command: 'idea',\n label: 'IntelliJ IDEA',\n family: 'jetbrains',\n protocol: 'idea',\n protocolShape: 'jetbrains',\n },\n {\n command: 'pycharm',\n label: 'PyCharm',\n family: 'jetbrains',\n protocol: 'pycharm',\n protocolShape: 'jetbrains',\n },\n {\n command: 'webstorm',\n label: 'WebStorm',\n family: 'jetbrains',\n protocol: 'webstorm',\n protocolShape: 'jetbrains',\n },\n {\n command: 'goland',\n label: 'GoLand',\n family: 'jetbrains',\n protocol: 'goland',\n protocolShape: 'jetbrains',\n },\n {\n command: 'phpstorm',\n label: 'PhpStorm',\n family: 'jetbrains',\n protocol: 'phpstorm',\n protocolShape: 'jetbrains',\n },\n {\n command: 'rubymine',\n label: 'RubyMine',\n family: 'jetbrains',\n protocol: 'rubymine',\n protocolShape: 'jetbrains',\n },\n {\n command: 'clion',\n label: 'CLion',\n family: 'jetbrains',\n protocol: 'clion',\n protocolShape: 'jetbrains',\n },\n {\n command: 'rider',\n label: 'Rider',\n family: 'jetbrains',\n protocol: 'rider',\n protocolShape: 'jetbrains',\n },\n { command: 'zed', label: 'Zed', family: 'other', protocol: 'zed', protocolShape: 'vscode' },\n { command: 'fleet', label: 'JetBrains Fleet', family: 'jetbrains' },\n { command: 'subl', label: 'Sublime Text', family: 'other' },\n { command: 'neovide', label: 'Neovide', family: 'other' },\n {\n command: 'helix',\n label: 'Helix',\n family: 'terminal',\n hint: 'Terminal editor — requires an attached session',\n },\n {\n command: 'vim',\n label: 'Vim',\n family: 'terminal',\n hint: 'Terminal editor — requires an attached session',\n },\n {\n command: 'nvim',\n label: 'Neovim',\n family: 'terminal',\n hint: 'Terminal editor — requires an attached session',\n },\n {\n command: 'emacs',\n label: 'Emacs',\n family: 'terminal',\n hint: 'Terminal editor — requires an attached session',\n },\n]);\n\nconst PRESETS_BY_COMMAND = new Map(IDE_PRESETS.map((p) => [p.command, p]));\n\nexport function getIdePreset(command: string | null | undefined): IdePreset | null {\n if (!command) return null;\n return PRESETS_BY_COMMAND.get(command) ?? null;\n}\n\n/**\n * Build the IDE-specific deep-link URL for `path`. Returns `null` when\n * the preset has no registered protocol.\n *\n * vscode-family → `vscode://file/<absolute-path>`\n * jetbrains → `idea://open?file=<encoded-path>`\n */\nexport function buildProtocolUrl(preset: IdePreset, path: string): string | null {\n if (!preset.protocol) return null;\n const trimmed = path.startsWith('/') ? path.slice(1) : path;\n if (preset.protocolShape === 'jetbrains') {\n return `${preset.protocol}://open?file=${encodeURIComponent(path)}`;\n }\n return `${preset.protocol}://file/${trimmed}`;\n}\n\n/**\n * Resolve the effective IDE command for a Vibe, applying the\n * vibeOverride → userDefault → 'code' precedence chain.\n */\nexport function resolveEffectiveIdeCommand(\n vibeId: string,\n userDefault: string | null | undefined,\n perVibeOverrides: Record<string, string> | null | undefined\n): string {\n return perVibeOverrides?.[vibeId] || userDefault || 'code';\n}\n"],"mappings":";AAuCA,IAAa,IAAoC,OAAO,OAAO;CAC7D;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,UAAU;EACV,eAAe;EAChB;CACD;EAAE,SAAS;EAAO,OAAO;EAAO,QAAQ;EAAS,UAAU;EAAO,eAAe;EAAU;CAC3F;EAAE,SAAS;EAAS,OAAO;EAAmB,QAAQ;EAAa;CACnE;EAAE,SAAS;EAAQ,OAAO;EAAgB,QAAQ;EAAS;CAC3D;EAAE,SAAS;EAAW,OAAO;EAAW,QAAQ;EAAS;CACzD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,MAAM;EACP;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,MAAM;EACP;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,MAAM;EACP;CACD;EACE,SAAS;EACT,OAAO;EACP,QAAQ;EACR,MAAM;EACP;CACF,CAAC,EAEI,IAAqB,IAAI,IAAI,EAAY,KAAK,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;AAE1E,SAAgB,EAAa,GAAsD;AAEjF,QADK,IACE,EAAmB,IAAI,EAAQ,IAAI,OADrB;;AAWvB,SAAgB,EAAiB,GAAmB,GAA6B;AAC/E,KAAI,CAAC,EAAO,SAAU,QAAO;CAC7B,IAAM,IAAU,EAAK,WAAW,IAAI,GAAG,EAAK,MAAM,EAAE,GAAG;AAIvD,QAHI,EAAO,kBAAkB,cACpB,GAAG,EAAO,SAAS,eAAe,mBAAmB,EAAK,KAE5D,GAAG,EAAO,SAAS,UAAU;;AAOtC,SAAgB,EACd,GACA,GACA,GACQ;AACR,QAAO,IAAmB,MAAW,KAAe"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { PLAN_META_PACKAGE as e, PLAN_PLANNOTATOR_PACKAGE as t } from "../../constants/pluginCatalog.js";
|
|
2
|
+
import { PluginGate as n } from "../shared/PluginGate.js";
|
|
3
|
+
import "../shared/index.js";
|
|
4
|
+
import { configureAgentHook as r, getPlannotatorStatus as i, installPlannotatorBinary as a, listSupportedAgents as o } from "../../services/planApi.js";
|
|
5
|
+
import { useCallback as s, useEffect as c, useMemo as l, useRef as u, useState as d } from "react";
|
|
6
|
+
import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
7
|
+
import { AlertCircle as p, CheckCircle2 as m, Loader2 as h, PlayCircle as g, RefreshCcw as _, Settings as v, Wifi as y, WifiOff as b } from "lucide-react";
|
|
8
|
+
import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
9
|
+
//#region src/components/ai/AIPlanPanel.tsx
|
|
10
|
+
function w({ agent: r, agentApiKey: i, tunnelUrl: a }) {
|
|
11
|
+
return /* @__PURE__ */ S(n, {
|
|
12
|
+
agentId: r.id,
|
|
13
|
+
required: [e, t],
|
|
14
|
+
mode: "all",
|
|
15
|
+
eyebrow: "plan.pluginRequiredEyebrow",
|
|
16
|
+
title: "plan.installPlanProviderTitle",
|
|
17
|
+
description: "plan.installPlanProviderDesc",
|
|
18
|
+
children: /* @__PURE__ */ S(T, {
|
|
19
|
+
agent: r,
|
|
20
|
+
agentApiKey: i,
|
|
21
|
+
tunnelUrl: a
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function T({ agent: e, agentApiKey: t, tunnelUrl: n }) {
|
|
26
|
+
let { t: u } = f(), m = s((e, t) => {
|
|
27
|
+
let n = u(e);
|
|
28
|
+
return n === e ? t : n;
|
|
29
|
+
}, [u]), [g, v] = d(null), [y, b] = d(null), [x, w] = d(!0), [T, k] = d([]), [A, j] = d(!1), [M, N] = d(null), [P, F] = d(null), [I, L] = d(null), R = s(async () => {
|
|
30
|
+
w(!0), b(null);
|
|
31
|
+
try {
|
|
32
|
+
let [t, n] = await Promise.all([i(e), o(e).catch(() => ({ agents: [] }))]);
|
|
33
|
+
v(t), k(n.agents ?? []);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
b(e instanceof Error ? e.message : "Failed to load plan status");
|
|
36
|
+
} finally {
|
|
37
|
+
w(!1);
|
|
38
|
+
}
|
|
39
|
+
}, [e]);
|
|
40
|
+
c(() => {
|
|
41
|
+
R();
|
|
42
|
+
}, [R]);
|
|
43
|
+
let z = s(async () => {
|
|
44
|
+
j(!0), L(null), F(null);
|
|
45
|
+
try {
|
|
46
|
+
let t = await a(e);
|
|
47
|
+
t.ok ? (F(m("plan.cliInstalled", "Plannotator CLI installed.")), await R()) : L(t.error ?? "Install failed");
|
|
48
|
+
} catch (e) {
|
|
49
|
+
L(e instanceof Error ? e.message : "Install failed");
|
|
50
|
+
} finally {
|
|
51
|
+
j(!1);
|
|
52
|
+
}
|
|
53
|
+
}, [
|
|
54
|
+
e,
|
|
55
|
+
R,
|
|
56
|
+
m
|
|
57
|
+
]), B = s(async (t) => {
|
|
58
|
+
N(t), L(null), F(null);
|
|
59
|
+
try {
|
|
60
|
+
let n = await r(e, t);
|
|
61
|
+
n.ok ? (F(m("plan.hookConfigured", `Hook configured for ${t}.`)), await R()) : L(n.error ?? "Hook configure failed");
|
|
62
|
+
} catch (e) {
|
|
63
|
+
L(e instanceof Error ? e.message : "Hook configure failed");
|
|
64
|
+
} finally {
|
|
65
|
+
N(null);
|
|
66
|
+
}
|
|
67
|
+
}, [
|
|
68
|
+
e,
|
|
69
|
+
R,
|
|
70
|
+
m
|
|
71
|
+
]), V = l(() => x ? "loading" : y ? "status-error" : g?.installed ? T.some((e) => e.hookConfigured) ? "ready" : "wizard" : "install-cli", [
|
|
72
|
+
g,
|
|
73
|
+
y,
|
|
74
|
+
x,
|
|
75
|
+
T
|
|
76
|
+
]);
|
|
77
|
+
return V === "loading" ? /* @__PURE__ */ C("div", {
|
|
78
|
+
className: "flex items-center gap-2 p-6 text-text-secondary",
|
|
79
|
+
children: [/* @__PURE__ */ S(h, { className: "h-4 w-4 animate-spin" }), /* @__PURE__ */ S("span", { children: m("plan.loadingStatus", "Loading plan status…") })]
|
|
80
|
+
}) : V === "status-error" ? /* @__PURE__ */ S("div", {
|
|
81
|
+
className: "rounded-md border border-status-error-border bg-status-error-bg p-4 text-sm text-status-error-text",
|
|
82
|
+
children: /* @__PURE__ */ C("div", {
|
|
83
|
+
className: "flex items-start gap-2",
|
|
84
|
+
children: [/* @__PURE__ */ S(p, { className: "h-4 w-4 mt-0.5 shrink-0" }), /* @__PURE__ */ C("div", {
|
|
85
|
+
className: "flex-1",
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ S("p", {
|
|
88
|
+
className: "font-medium",
|
|
89
|
+
children: m("plan.statusError", "Could not load plan status from the agent.")
|
|
90
|
+
}),
|
|
91
|
+
/* @__PURE__ */ S("p", {
|
|
92
|
+
className: "text-xs opacity-80 mt-1",
|
|
93
|
+
children: y
|
|
94
|
+
}),
|
|
95
|
+
/* @__PURE__ */ C("button", {
|
|
96
|
+
onClick: () => void R(),
|
|
97
|
+
className: "mt-3 inline-flex items-center gap-1 text-xs font-medium hover:underline",
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ S(_, { className: "h-3 w-3" }),
|
|
100
|
+
" ",
|
|
101
|
+
m("plan.retry", "Retry")
|
|
102
|
+
]
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
})]
|
|
106
|
+
})
|
|
107
|
+
}) : /* @__PURE__ */ C("div", {
|
|
108
|
+
className: "space-y-4",
|
|
109
|
+
children: [
|
|
110
|
+
P && /* @__PURE__ */ S("div", {
|
|
111
|
+
role: "status",
|
|
112
|
+
className: "rounded-md border border-status-success-border bg-status-success-bg px-3 py-2 text-xs text-status-success-text",
|
|
113
|
+
children: P
|
|
114
|
+
}),
|
|
115
|
+
I && /* @__PURE__ */ S("div", {
|
|
116
|
+
role: "alert",
|
|
117
|
+
className: "rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-xs text-status-error-text",
|
|
118
|
+
children: I
|
|
119
|
+
}),
|
|
120
|
+
V === "install-cli" && /* @__PURE__ */ S(E, {
|
|
121
|
+
installing: A,
|
|
122
|
+
onInstall: z,
|
|
123
|
+
tr: m
|
|
124
|
+
}),
|
|
125
|
+
V === "wizard" && /* @__PURE__ */ S(D, {
|
|
126
|
+
agents: T,
|
|
127
|
+
configuring: M,
|
|
128
|
+
onConfigure: B,
|
|
129
|
+
tr: m
|
|
130
|
+
}),
|
|
131
|
+
V === "ready" && /* @__PURE__ */ S(O, {
|
|
132
|
+
agent: e,
|
|
133
|
+
agents: T,
|
|
134
|
+
agentApiKey: t,
|
|
135
|
+
tunnelUrl: n,
|
|
136
|
+
onReconfigure: () => F(null),
|
|
137
|
+
tr: m
|
|
138
|
+
})
|
|
139
|
+
]
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function E({ installing: e, onInstall: t, tr: n }) {
|
|
143
|
+
return /* @__PURE__ */ S("div", {
|
|
144
|
+
className: "rounded-lg border border-border-default bg-bg-elevated p-6",
|
|
145
|
+
children: /* @__PURE__ */ C("div", {
|
|
146
|
+
className: "flex items-start gap-3",
|
|
147
|
+
children: [/* @__PURE__ */ S(g, { className: "h-6 w-6 text-action-primary-bg shrink-0" }), /* @__PURE__ */ C("div", {
|
|
148
|
+
className: "flex-1",
|
|
149
|
+
children: [
|
|
150
|
+
/* @__PURE__ */ S("h3", {
|
|
151
|
+
className: "text-base font-semibold text-text-primary",
|
|
152
|
+
children: n("plan.installCliTitle", "Install the plannotator CLI")
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ S("p", {
|
|
155
|
+
className: "text-sm text-text-secondary mt-1",
|
|
156
|
+
children: n("plan.installCliDesc", "Plan mode runs a local plannotator binary on the agent and proxies its UI back here. The plugin installs the binary into ~/.local/bin/plannotator (sha256-pinned). Roughly 30 seconds.")
|
|
157
|
+
}),
|
|
158
|
+
/* @__PURE__ */ S("button", {
|
|
159
|
+
onClick: t,
|
|
160
|
+
disabled: e,
|
|
161
|
+
className: "mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bgHover disabled:opacity-50",
|
|
162
|
+
children: e ? /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S(h, { className: "h-4 w-4 animate-spin" }), n("plan.installing", "Installing…")] }) : n("plan.installCliCta", "Install plannotator CLI")
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
})]
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function D({ agents: e, configuring: t, onConfigure: n, tr: r }) {
|
|
170
|
+
let i = e.filter((e) => e.cliInstalled);
|
|
171
|
+
return /* @__PURE__ */ S("div", {
|
|
172
|
+
className: "rounded-lg border border-border-default bg-bg-elevated p-6",
|
|
173
|
+
children: /* @__PURE__ */ C("div", {
|
|
174
|
+
className: "flex items-start gap-3",
|
|
175
|
+
children: [/* @__PURE__ */ S(v, { className: "h-6 w-6 text-action-primary-bg shrink-0" }), /* @__PURE__ */ C("div", {
|
|
176
|
+
className: "flex-1",
|
|
177
|
+
children: [
|
|
178
|
+
/* @__PURE__ */ S("h3", {
|
|
179
|
+
className: "text-base font-semibold text-text-primary",
|
|
180
|
+
children: r("plan.wizardTitle", "Connect an AI coding agent")
|
|
181
|
+
}),
|
|
182
|
+
/* @__PURE__ */ S("p", {
|
|
183
|
+
className: "text-sm text-text-secondary mt-1",
|
|
184
|
+
children: r("plan.wizardDesc", "Configure a plannotator hook for at least one installed AI coding agent. The hook forwards plan content from the agent to plannotator on every plan-finalisation step.")
|
|
185
|
+
}),
|
|
186
|
+
i.length === 0 && /* @__PURE__ */ S("p", {
|
|
187
|
+
className: "mt-4 text-sm text-status-warning-text",
|
|
188
|
+
children: r("plan.wizardNoAgents", "No AI coding agents detected in this sandbox. Install one (Claude Code, OpenCode, Codex, Pi, or Gemini) and refresh.")
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ S("ul", {
|
|
191
|
+
className: "mt-4 space-y-2",
|
|
192
|
+
children: e.map((e) => /* @__PURE__ */ C("li", {
|
|
193
|
+
className: "flex items-start gap-3 p-3 border border-border-default rounded-md bg-bg-surface",
|
|
194
|
+
children: [
|
|
195
|
+
e.hookConfigured ? /* @__PURE__ */ S(m, { className: "h-5 w-5 text-status-success-text shrink-0 mt-0.5" }) : /* @__PURE__ */ S("div", { className: "h-5 w-5 rounded-full border-2 border-border-default shrink-0 mt-0.5" }),
|
|
196
|
+
/* @__PURE__ */ C("div", {
|
|
197
|
+
className: "flex-1",
|
|
198
|
+
children: [
|
|
199
|
+
/* @__PURE__ */ S("p", {
|
|
200
|
+
className: "text-sm font-medium text-text-primary",
|
|
201
|
+
children: e.name
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ S("p", {
|
|
204
|
+
className: "text-xs text-text-secondary mt-0.5",
|
|
205
|
+
children: e.instructions
|
|
206
|
+
}),
|
|
207
|
+
!e.cliInstalled && /* @__PURE__ */ S("p", {
|
|
208
|
+
className: "text-xs text-status-warning-text mt-1",
|
|
209
|
+
children: r("plan.agentCliMissing", "CLI not detected on this sandbox.")
|
|
210
|
+
})
|
|
211
|
+
]
|
|
212
|
+
}),
|
|
213
|
+
/* @__PURE__ */ S("button", {
|
|
214
|
+
disabled: !e.cliInstalled || e.hookConfigured || t === e.agent,
|
|
215
|
+
onClick: () => n(e.agent),
|
|
216
|
+
className: "px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover disabled:opacity-50",
|
|
217
|
+
children: e.hookConfigured ? r("plan.hookConfiguredLabel", "Configured") : t === e.agent ? r("plan.configuring", "Configuring…") : r("plan.configureHook", "Configure hook")
|
|
218
|
+
})
|
|
219
|
+
]
|
|
220
|
+
}, e.agent))
|
|
221
|
+
})
|
|
222
|
+
]
|
|
223
|
+
})]
|
|
224
|
+
})
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function O({ agent: e, agents: t, agentApiKey: n, tunnelUrl: r, onReconfigure: i, tr: a }) {
|
|
228
|
+
let o = u(null), [c, f] = d("connecting"), m = l(() => {
|
|
229
|
+
if (!r) return null;
|
|
230
|
+
let e = r.replace(/\/$/, "");
|
|
231
|
+
return new URL(`${e}/plan/`).toString();
|
|
232
|
+
}, [r]), g = s(() => {
|
|
233
|
+
let e = o.current;
|
|
234
|
+
if (!(!e?.contentWindow || !n || !r)) try {
|
|
235
|
+
let t = new URL(r).origin;
|
|
236
|
+
e.contentWindow.postMessage({
|
|
237
|
+
type: "vibe-auth",
|
|
238
|
+
apiKey: n
|
|
239
|
+
}, t);
|
|
240
|
+
} catch {}
|
|
241
|
+
}, [n, r]), x = s(() => {
|
|
242
|
+
f("connected"), g();
|
|
243
|
+
}, [g]), w = s(() => {
|
|
244
|
+
f("error");
|
|
245
|
+
}, []), T = s(() => {
|
|
246
|
+
let e = o.current;
|
|
247
|
+
if (!e) return;
|
|
248
|
+
f("connecting");
|
|
249
|
+
let t = e.src;
|
|
250
|
+
e.src = "about:blank", requestAnimationFrame(() => {
|
|
251
|
+
e.src = t;
|
|
252
|
+
});
|
|
253
|
+
}, []);
|
|
254
|
+
if (!r || !n) return /* @__PURE__ */ S("div", {
|
|
255
|
+
className: "rounded-lg border border-status-warning-border bg-status-warning-bg p-4 text-sm text-status-warning-text",
|
|
256
|
+
children: a("plan.tunnelMissing", "Agent tunnel URL or API key is missing. Bring the agent online and refresh.")
|
|
257
|
+
});
|
|
258
|
+
let E = t.filter((e) => e.hookConfigured);
|
|
259
|
+
return /* @__PURE__ */ C("div", {
|
|
260
|
+
className: "space-y-3",
|
|
261
|
+
children: [/* @__PURE__ */ C("div", {
|
|
262
|
+
className: "flex items-center gap-2 text-xs text-text-secondary",
|
|
263
|
+
children: [
|
|
264
|
+
/* @__PURE__ */ C("span", {
|
|
265
|
+
className: "inline-flex items-center gap-1",
|
|
266
|
+
children: [
|
|
267
|
+
c === "connected" && /* @__PURE__ */ S(y, { className: "h-3.5 w-3.5 text-status-success-text" }),
|
|
268
|
+
c === "connecting" && /* @__PURE__ */ S(h, { className: "h-3.5 w-3.5 animate-spin text-status-warning-text" }),
|
|
269
|
+
c === "error" && /* @__PURE__ */ S(b, { className: "h-3.5 w-3.5 text-status-error-text" }),
|
|
270
|
+
a(`plan.connection.${c}`, c)
|
|
271
|
+
]
|
|
272
|
+
}),
|
|
273
|
+
/* @__PURE__ */ S("span", {
|
|
274
|
+
"aria-hidden": "true",
|
|
275
|
+
children: "·"
|
|
276
|
+
}),
|
|
277
|
+
/* @__PURE__ */ S("span", { children: a("plan.hookCount", `${E.length} hook(s) configured`) }),
|
|
278
|
+
/* @__PURE__ */ C("button", {
|
|
279
|
+
onClick: i,
|
|
280
|
+
className: "ml-auto inline-flex items-center gap-1 hover:text-text-primary",
|
|
281
|
+
children: [/* @__PURE__ */ S(v, { className: "h-3.5 w-3.5" }), a("plan.reopenWizard", "Manage hooks")]
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
}), /* @__PURE__ */ C("div", {
|
|
285
|
+
className: "border border-border-default rounded-lg overflow-hidden bg-bg-sunken relative h-[calc(100vh-320px)] min-h-[500px]",
|
|
286
|
+
children: [
|
|
287
|
+
m && /* @__PURE__ */ S("iframe", {
|
|
288
|
+
ref: o,
|
|
289
|
+
src: m,
|
|
290
|
+
title: a("plan.iframeTitle", "Plannotator plan workspace"),
|
|
291
|
+
className: "w-full h-full border-0",
|
|
292
|
+
allow: "clipboard-read; clipboard-write",
|
|
293
|
+
sandbox: "allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation-by-user-activation",
|
|
294
|
+
onLoad: x,
|
|
295
|
+
onError: w,
|
|
296
|
+
"data-testid": "plan-iframe"
|
|
297
|
+
}),
|
|
298
|
+
c === "connecting" && /* @__PURE__ */ S("div", {
|
|
299
|
+
className: "absolute inset-0 flex items-center justify-center bg-bg-sunken/80 pointer-events-none",
|
|
300
|
+
children: /* @__PURE__ */ S(h, { className: "h-6 w-6 animate-spin text-action-primary-bg" })
|
|
301
|
+
}),
|
|
302
|
+
c === "error" && /* @__PURE__ */ S("div", {
|
|
303
|
+
className: "absolute inset-0 flex items-center justify-center bg-bg-sunken p-6 text-center",
|
|
304
|
+
children: /* @__PURE__ */ C("div", { children: [
|
|
305
|
+
/* @__PURE__ */ S(p, { className: "h-6 w-6 text-status-error-text mx-auto" }),
|
|
306
|
+
/* @__PURE__ */ S("p", {
|
|
307
|
+
className: "text-sm font-medium text-text-primary mt-2",
|
|
308
|
+
children: a("plan.iframeErrorTitle", "Could not load plannotator.")
|
|
309
|
+
}),
|
|
310
|
+
/* @__PURE__ */ S("p", {
|
|
311
|
+
className: "text-xs text-text-secondary mt-1",
|
|
312
|
+
children: a("plan.iframeErrorDesc", "The agent reverse proxy returned an error. Check the agent status and try again.")
|
|
313
|
+
}),
|
|
314
|
+
/* @__PURE__ */ C("button", {
|
|
315
|
+
onClick: T,
|
|
316
|
+
className: "mt-3 inline-flex items-center gap-1 rounded-md bg-action-primary-bg px-3 py-1.5 text-sm text-action-primary-text hover:bg-action-primary-bgHover",
|
|
317
|
+
children: [
|
|
318
|
+
/* @__PURE__ */ S(_, { className: "h-3.5 w-3.5" }),
|
|
319
|
+
" ",
|
|
320
|
+
a("plan.retry", "Retry")
|
|
321
|
+
]
|
|
322
|
+
})
|
|
323
|
+
] })
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
})]
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
//#endregion
|
|
330
|
+
export { w as AIPlanPanel };
|
|
331
|
+
|
|
332
|
+
//# sourceMappingURL=AIPlanPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIPlanPanel.js","names":[],"sources":["../../../src/components/ai/AIPlanPanel.tsx"],"sourcesContent":["/**\n * AIPlanPanel — the body of /ai-tools/plan.\n *\n * Five UI states gated in order:\n * 1. installing-plugin → vibe-plugin-plan + vibe-plugin-plan-plannotator\n * not installed on the agent. Renders the PluginGate install card.\n * 2. installing-cli → plugins installed but plannotator binary\n * missing on disk. Renders an Install CLI CTA.\n * 3. wizard → CLI installed but no AI-agent hook configured\n * yet. Renders the Claude/OpenCode/Codex/Pi/Gemini wizard.\n * 4. ready → all prereqs satisfied. Renders the tunnel\n * iframe pointing at ${tunnelUrl}/plan/, with postMessage auth\n * handoff on iframe load (mirrors PluginUIPanel.tsx).\n * 5. error → unrecoverable load failure for the status\n * query. Renders an error banner with retry.\n *\n * Auth handoff (matches PluginUIPanel.tsx:194–210):\n * onLoad → iframe.contentWindow.postMessage({type:'vibe-auth', apiKey},\n * new URL(tunnelUrl).origin)\n *\n * Surface contracts:\n * GET /api/plan-plannotator/status → PlannotatorStatus\n * POST /api/plan-plannotator/install → install binary\n * GET /api/plan-plannotator/agents/supported → AgentDetectionResult[]\n * POST /api/plan-plannotator/agents/:agent/configure-hook\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n AlertCircle,\n CheckCircle2,\n Loader2,\n PlayCircle,\n RefreshCcw,\n Settings,\n Wifi,\n WifiOff,\n} from 'lucide-react';\n\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { PluginGate } from '@/components/shared';\nimport { PLAN_META_PACKAGE, PLAN_PLANNOTATOR_PACKAGE } from '@/constants/pluginCatalog';\nimport {\n configureAgentHook,\n getPlannotatorStatus,\n installPlannotatorBinary,\n listSupportedAgents,\n type AgentDetectionResult,\n type PlannotatorStatus,\n} from '@/services/planApi';\nimport type { AgentRef } from '@/services/aiApi';\n\ninterface AIPlanPanelProps {\n agent: AgentRef;\n agentApiKey: string | null;\n tunnelUrl: string | null;\n}\n\ntype ConnectionStatus = 'connecting' | 'connected' | 'error';\n\nexport function AIPlanPanel({ agent, agentApiKey, tunnelUrl }: AIPlanPanelProps) {\n return (\n <PluginGate\n agentId={agent.id}\n required={[PLAN_META_PACKAGE, PLAN_PLANNOTATOR_PACKAGE]}\n mode=\"all\"\n eyebrow=\"plan.pluginRequiredEyebrow\"\n title=\"plan.installPlanProviderTitle\"\n description=\"plan.installPlanProviderDesc\"\n >\n <PlanPanelInner agent={agent} agentApiKey={agentApiKey} tunnelUrl={tunnelUrl} />\n </PluginGate>\n );\n}\n\nfunction PlanPanelInner({ agent, agentApiKey, tunnelUrl }: AIPlanPanelProps) {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const [status, setStatus] = useState<PlannotatorStatus | null>(null);\n const [statusError, setStatusError] = useState<string | null>(null);\n const [statusLoading, setStatusLoading] = useState(true);\n const [agents, setAgents] = useState<AgentDetectionResult[]>([]);\n const [installing, setInstalling] = useState(false);\n const [configuring, setConfiguring] = useState<string | null>(null);\n const [actionMessage, setActionMessage] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n\n const refresh = useCallback(async () => {\n setStatusLoading(true);\n setStatusError(null);\n try {\n const [statusResult, agentsResult] = await Promise.all([\n getPlannotatorStatus(agent),\n listSupportedAgents(agent).catch(() => ({ agents: [] })),\n ]);\n setStatus(statusResult);\n setAgents(agentsResult.agents ?? []);\n } catch (err) {\n setStatusError(err instanceof Error ? err.message : 'Failed to load plan status');\n } finally {\n setStatusLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const handleInstallCli = useCallback(async () => {\n setInstalling(true);\n setActionError(null);\n setActionMessage(null);\n try {\n const result = await installPlannotatorBinary(agent);\n if (result.ok) {\n setActionMessage(tr('plan.cliInstalled', 'Plannotator CLI installed.'));\n await refresh();\n } else {\n setActionError(result.error ?? 'Install failed');\n }\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Install failed');\n } finally {\n setInstalling(false);\n }\n }, [agent, refresh, tr]);\n\n const handleConfigureHook = useCallback(\n async (agentKind: AgentDetectionResult['agent']) => {\n setConfiguring(agentKind);\n setActionError(null);\n setActionMessage(null);\n try {\n const result = await configureAgentHook(agent, agentKind);\n if (result.ok) {\n setActionMessage(tr('plan.hookConfigured', `Hook configured for ${agentKind}.`));\n await refresh();\n } else {\n setActionError(result.error ?? 'Hook configure failed');\n }\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Hook configure failed');\n } finally {\n setConfiguring(null);\n }\n },\n [agent, refresh, tr]\n );\n\n // Derived render state — guarded ordering means we always render the\n // most prerequisite-bound CTA first.\n const view = useMemo<'loading' | 'status-error' | 'install-cli' | 'wizard' | 'ready'>(() => {\n if (statusLoading) return 'loading';\n if (statusError) return 'status-error';\n if (!status?.installed) return 'install-cli';\n const anyConfigured = agents.some((a) => a.hookConfigured);\n if (!anyConfigured) return 'wizard';\n return 'ready';\n }, [status, statusError, statusLoading, agents]);\n\n if (view === 'loading') {\n return (\n <div className=\"flex items-center gap-2 p-6 text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n <span>{tr('plan.loadingStatus', 'Loading plan status…')}</span>\n </div>\n );\n }\n\n if (view === 'status-error') {\n return (\n <div className=\"rounded-md border border-status-error-border bg-status-error-bg p-4 text-sm text-status-error-text\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle className=\"h-4 w-4 mt-0.5 shrink-0\" />\n <div className=\"flex-1\">\n <p className=\"font-medium\">\n {tr('plan.statusError', 'Could not load plan status from the agent.')}\n </p>\n <p className=\"text-xs opacity-80 mt-1\">{statusError}</p>\n <button\n onClick={() => void refresh()}\n className=\"mt-3 inline-flex items-center gap-1 text-xs font-medium hover:underline\"\n >\n <RefreshCcw className=\"h-3 w-3\" /> {tr('plan.retry', 'Retry')}\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4\">\n {actionMessage && (\n <div\n role=\"status\"\n className=\"rounded-md border border-status-success-border bg-status-success-bg px-3 py-2 text-xs text-status-success-text\"\n >\n {actionMessage}\n </div>\n )}\n {actionError && (\n <div\n role=\"alert\"\n className=\"rounded-md border border-status-error-border bg-status-error-bg px-3 py-2 text-xs text-status-error-text\"\n >\n {actionError}\n </div>\n )}\n\n {view === 'install-cli' && (\n <InstallCliCard installing={installing} onInstall={handleInstallCli} tr={tr} />\n )}\n\n {view === 'wizard' && (\n <WizardCard\n agents={agents}\n configuring={configuring}\n onConfigure={handleConfigureHook}\n tr={tr}\n />\n )}\n\n {view === 'ready' && (\n <PlanReadyPanel\n agent={agent}\n agents={agents}\n agentApiKey={agentApiKey}\n tunnelUrl={tunnelUrl}\n onReconfigure={() => setActionMessage(null)}\n tr={tr}\n />\n )}\n </div>\n );\n}\n\ninterface InstallCliCardProps {\n installing: boolean;\n onInstall: () => void;\n tr: (key: string, fallback: string) => string;\n}\n\nfunction InstallCliCard({ installing, onInstall, tr }: InstallCliCardProps) {\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-elevated p-6\">\n <div className=\"flex items-start gap-3\">\n <PlayCircle className=\"h-6 w-6 text-action-primary-bg shrink-0\" />\n <div className=\"flex-1\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('plan.installCliTitle', 'Install the plannotator CLI')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tr(\n 'plan.installCliDesc',\n 'Plan mode runs a local plannotator binary on the agent and proxies its UI back here. The plugin installs the binary into ~/.local/bin/plannotator (sha256-pinned). Roughly 30 seconds.'\n )}\n </p>\n <button\n onClick={onInstall}\n disabled={installing}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bgHover disabled:opacity-50\"\n >\n {installing ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n {tr('plan.installing', 'Installing…')}\n </>\n ) : (\n tr('plan.installCliCta', 'Install plannotator CLI')\n )}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\ninterface WizardCardProps {\n agents: AgentDetectionResult[];\n configuring: string | null;\n onConfigure: (agentKind: AgentDetectionResult['agent']) => void;\n tr: (key: string, fallback: string) => string;\n}\n\nfunction WizardCard({ agents, configuring, onConfigure, tr }: WizardCardProps) {\n const installed = agents.filter((a) => a.cliInstalled);\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-elevated p-6\">\n <div className=\"flex items-start gap-3\">\n <Settings className=\"h-6 w-6 text-action-primary-bg shrink-0\" />\n <div className=\"flex-1\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('plan.wizardTitle', 'Connect an AI coding agent')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tr(\n 'plan.wizardDesc',\n 'Configure a plannotator hook for at least one installed AI coding agent. The hook forwards plan content from the agent to plannotator on every plan-finalisation step.'\n )}\n </p>\n {installed.length === 0 && (\n <p className=\"mt-4 text-sm text-status-warning-text\">\n {tr(\n 'plan.wizardNoAgents',\n 'No AI coding agents detected in this sandbox. Install one (Claude Code, OpenCode, Codex, Pi, or Gemini) and refresh.'\n )}\n </p>\n )}\n <ul className=\"mt-4 space-y-2\">\n {agents.map((entry) => (\n <li\n key={entry.agent}\n className=\"flex items-start gap-3 p-3 border border-border-default rounded-md bg-bg-surface\"\n >\n {entry.hookConfigured ? (\n <CheckCircle2 className=\"h-5 w-5 text-status-success-text shrink-0 mt-0.5\" />\n ) : (\n <div className=\"h-5 w-5 rounded-full border-2 border-border-default shrink-0 mt-0.5\" />\n )}\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">{entry.name}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">{entry.instructions}</p>\n {!entry.cliInstalled && (\n <p className=\"text-xs text-status-warning-text mt-1\">\n {tr('plan.agentCliMissing', 'CLI not detected on this sandbox.')}\n </p>\n )}\n </div>\n <button\n disabled={\n !entry.cliInstalled || entry.hookConfigured || configuring === entry.agent\n }\n onClick={() => onConfigure(entry.agent)}\n className=\"px-3 py-1.5 text-xs rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover disabled:opacity-50\"\n >\n {entry.hookConfigured\n ? tr('plan.hookConfiguredLabel', 'Configured')\n : configuring === entry.agent\n ? tr('plan.configuring', 'Configuring…')\n : tr('plan.configureHook', 'Configure hook')}\n </button>\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n );\n}\n\ninterface PlanReadyPanelProps {\n agent: AgentRef;\n agents: AgentDetectionResult[];\n agentApiKey: string | null;\n tunnelUrl: string | null;\n onReconfigure: () => void;\n tr: (key: string, fallback: string) => string;\n}\n\nfunction PlanReadyPanel({\n agent,\n agents,\n agentApiKey,\n tunnelUrl,\n onReconfigure,\n tr,\n}: PlanReadyPanelProps) {\n const iframeRef = useRef<HTMLIFrameElement | null>(null);\n const [connection, setConnection] = useState<ConnectionStatus>('connecting');\n\n const iframeSrc = useMemo(() => {\n if (!tunnelUrl) return null;\n const base = tunnelUrl.replace(/\\/$/, '');\n return new URL(`${base}/plan/`).toString();\n }, [tunnelUrl]);\n\n const sendAuth = useCallback(() => {\n const iframe = iframeRef.current;\n if (!iframe?.contentWindow || !agentApiKey || !tunnelUrl) return;\n try {\n const targetOrigin = new URL(tunnelUrl).origin;\n iframe.contentWindow.postMessage({ type: 'vibe-auth', apiKey: agentApiKey }, targetOrigin);\n } catch {\n // Origin parsing can throw on malformed tunnelUrl — ignored.\n }\n }, [agentApiKey, tunnelUrl]);\n\n const handleLoad = useCallback(() => {\n setConnection('connected');\n sendAuth();\n }, [sendAuth]);\n\n const handleError = useCallback(() => {\n setConnection('error');\n }, []);\n\n const handleRetry = useCallback(() => {\n const iframe = iframeRef.current;\n if (!iframe) return;\n setConnection('connecting');\n const src = iframe.src;\n iframe.src = 'about:blank';\n requestAnimationFrame(() => {\n iframe.src = src;\n });\n }, []);\n\n // Used elsewhere for analytics / breadcrumbs.\n void agent;\n\n if (!tunnelUrl || !agentApiKey) {\n return (\n <div className=\"rounded-lg border border-status-warning-border bg-status-warning-bg p-4 text-sm text-status-warning-text\">\n {tr(\n 'plan.tunnelMissing',\n 'Agent tunnel URL or API key is missing. Bring the agent online and refresh.'\n )}\n </div>\n );\n }\n\n const configuredAgents = agents.filter((a) => a.hookConfigured);\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center gap-1\">\n {connection === 'connected' && <Wifi className=\"h-3.5 w-3.5 text-status-success-text\" />}\n {connection === 'connecting' && (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin text-status-warning-text\" />\n )}\n {connection === 'error' && <WifiOff className=\"h-3.5 w-3.5 text-status-error-text\" />}\n {tr(`plan.connection.${connection}`, connection)}\n </span>\n <span aria-hidden=\"true\">·</span>\n <span>{tr('plan.hookCount', `${configuredAgents.length} hook(s) configured`)}</span>\n <button\n onClick={onReconfigure}\n className=\"ml-auto inline-flex items-center gap-1 hover:text-text-primary\"\n >\n <Settings className=\"h-3.5 w-3.5\" />\n {tr('plan.reopenWizard', 'Manage hooks')}\n </button>\n </div>\n\n <div className=\"border border-border-default rounded-lg overflow-hidden bg-bg-sunken relative h-[calc(100vh-320px)] min-h-[500px]\">\n {iframeSrc && (\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n title={tr('plan.iframeTitle', 'Plannotator plan workspace')}\n className=\"w-full h-full border-0\"\n allow=\"clipboard-read; clipboard-write\"\n sandbox=\"allow-same-origin allow-scripts allow-forms allow-popups allow-top-navigation-by-user-activation\"\n onLoad={handleLoad}\n onError={handleError}\n data-testid=\"plan-iframe\"\n />\n )}\n {connection === 'connecting' && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-bg-sunken/80 pointer-events-none\">\n <Loader2 className=\"h-6 w-6 animate-spin text-action-primary-bg\" />\n </div>\n )}\n {connection === 'error' && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-bg-sunken p-6 text-center\">\n <div>\n <AlertCircle className=\"h-6 w-6 text-status-error-text mx-auto\" />\n <p className=\"text-sm font-medium text-text-primary mt-2\">\n {tr('plan.iframeErrorTitle', 'Could not load plannotator.')}\n </p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {tr(\n 'plan.iframeErrorDesc',\n 'The agent reverse proxy returned an error. Check the agent status and try again.'\n )}\n </p>\n <button\n onClick={handleRetry}\n className=\"mt-3 inline-flex items-center gap-1 rounded-md bg-action-primary-bg px-3 py-1.5 text-sm text-action-primary-text hover:bg-action-primary-bgHover\"\n >\n <RefreshCcw className=\"h-3.5 w-3.5\" /> {tr('plan.retry', 'Retry')}\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import "./AnalyticsBreakdownChart.js";
|
|
2
|
+
import "./AnalyticsTimeSeriesChart.js";
|
|
1
3
|
import "./types.js";
|
|
2
4
|
import "./AnalyticsFilterBar.js";
|
|
3
5
|
import "./AnalyticsKpiGrid.js";
|
|
4
|
-
import "./AnalyticsTimeSeriesChart.js";
|
|
5
|
-
import "./AnalyticsBreakdownChart.js";
|
|
6
6
|
import "./AnalyticsBreakdownTable.js";
|
|
7
7
|
import "./AnalyticsEntityTabs.js";
|
|
8
8
|
import "./SandboxAnalyticsSection.js";
|