@tacuchi/agent-workflow-cli 7.3.1 → 9.0.0

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.
Files changed (169) hide show
  1. package/dist/cli/main.js +0 -0
  2. package/dist/cli/tui/app.d.ts.map +1 -1
  3. package/dist/cli/tui/app.js +277 -76
  4. package/dist/cli/tui/app.js.map +1 -1
  5. package/dist/cli/tui/components/activity-feed.d.ts +16 -0
  6. package/dist/cli/tui/components/activity-feed.d.ts.map +1 -0
  7. package/dist/cli/tui/components/activity-feed.js +35 -0
  8. package/dist/cli/tui/components/activity-feed.js.map +1 -0
  9. package/dist/cli/tui/components/command-palette.d.ts +11 -33
  10. package/dist/cli/tui/components/command-palette.d.ts.map +1 -1
  11. package/dist/cli/tui/components/command-palette.js +18 -111
  12. package/dist/cli/tui/components/command-palette.js.map +1 -1
  13. package/dist/cli/tui/components/confirm-banner.d.ts +10 -0
  14. package/dist/cli/tui/components/confirm-banner.d.ts.map +1 -0
  15. package/dist/cli/tui/components/confirm-banner.js +11 -0
  16. package/dist/cli/tui/components/confirm-banner.js.map +1 -0
  17. package/dist/cli/tui/components/detail-panel.d.ts +34 -0
  18. package/dist/cli/tui/components/detail-panel.d.ts.map +1 -0
  19. package/dist/cli/tui/components/detail-panel.js +83 -0
  20. package/dist/cli/tui/components/detail-panel.js.map +1 -0
  21. package/dist/cli/tui/components/family-card.d.ts +14 -0
  22. package/dist/cli/tui/components/family-card.d.ts.map +1 -0
  23. package/dist/cli/tui/components/family-card.js +37 -0
  24. package/dist/cli/tui/components/family-card.js.map +1 -0
  25. package/dist/cli/tui/components/inline-wizard.d.ts +19 -0
  26. package/dist/cli/tui/components/inline-wizard.d.ts.map +1 -0
  27. package/dist/cli/tui/components/inline-wizard.js +16 -0
  28. package/dist/cli/tui/components/inline-wizard.js.map +1 -0
  29. package/dist/cli/tui/components/input-prompt.js +1 -1
  30. package/dist/cli/tui/components/input-prompt.js.map +1 -1
  31. package/dist/cli/tui/components/list-row.d.ts +30 -0
  32. package/dist/cli/tui/components/list-row.d.ts.map +1 -0
  33. package/dist/cli/tui/components/list-row.js +85 -0
  34. package/dist/cli/tui/components/list-row.js.map +1 -0
  35. package/dist/cli/tui/components/page-head.d.ts +11 -10
  36. package/dist/cli/tui/components/page-head.d.ts.map +1 -1
  37. package/dist/cli/tui/components/page-head.js +21 -10
  38. package/dist/cli/tui/components/page-head.js.map +1 -1
  39. package/dist/cli/tui/components/phase-card.d.ts +15 -0
  40. package/dist/cli/tui/components/phase-card.d.ts.map +1 -0
  41. package/dist/cli/tui/components/phase-card.js +13 -0
  42. package/dist/cli/tui/components/phase-card.js.map +1 -0
  43. package/dist/cli/tui/components/quick-actions.d.ts +9 -0
  44. package/dist/cli/tui/components/quick-actions.d.ts.map +1 -0
  45. package/dist/cli/tui/components/quick-actions.js +9 -0
  46. package/dist/cli/tui/components/quick-actions.js.map +1 -0
  47. package/dist/cli/tui/components/section-head.d.ts +10 -0
  48. package/dist/cli/tui/components/section-head.d.ts.map +1 -0
  49. package/dist/cli/tui/components/section-head.js +8 -0
  50. package/dist/cli/tui/components/section-head.js.map +1 -0
  51. package/dist/cli/tui/components/sidebar.d.ts +27 -0
  52. package/dist/cli/tui/components/sidebar.d.ts.map +1 -0
  53. package/dist/cli/tui/components/sidebar.js +37 -0
  54. package/dist/cli/tui/components/sidebar.js.map +1 -0
  55. package/dist/cli/tui/components/stat-tile.d.ts +16 -0
  56. package/dist/cli/tui/components/stat-tile.d.ts.map +1 -0
  57. package/dist/cli/tui/components/stat-tile.js +23 -0
  58. package/dist/cli/tui/components/stat-tile.js.map +1 -0
  59. package/dist/cli/tui/components/toast-stack.d.ts +3 -3
  60. package/dist/cli/tui/components/toast-stack.js +3 -3
  61. package/dist/cli/tui/data/activity.d.ts +21 -0
  62. package/dist/cli/tui/data/activity.d.ts.map +1 -0
  63. package/dist/cli/tui/data/activity.js +83 -0
  64. package/dist/cli/tui/data/activity.js.map +1 -0
  65. package/dist/cli/tui/data/workflow-content.d.ts +16 -0
  66. package/dist/cli/tui/data/workflow-content.d.ts.map +1 -0
  67. package/dist/cli/tui/data/workflow-content.js +202 -0
  68. package/dist/cli/tui/data/workflow-content.js.map +1 -0
  69. package/dist/cli/tui/tabs/mcp-tab.d.ts +3 -16
  70. package/dist/cli/tui/tabs/mcp-tab.d.ts.map +1 -1
  71. package/dist/cli/tui/tabs/mcp-tab.js +150 -195
  72. package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
  73. package/dist/cli/tui/tabs/project-tab.d.ts +0 -11
  74. package/dist/cli/tui/tabs/project-tab.d.ts.map +1 -1
  75. package/dist/cli/tui/tabs/project-tab.js +47 -86
  76. package/dist/cli/tui/tabs/project-tab.js.map +1 -1
  77. package/dist/cli/tui/tabs/skills-tab.d.ts +1 -11
  78. package/dist/cli/tui/tabs/skills-tab.d.ts.map +1 -1
  79. package/dist/cli/tui/tabs/skills-tab.js +165 -126
  80. package/dist/cli/tui/tabs/skills-tab.js.map +1 -1
  81. package/dist/cli/tui/tabs/status-tab.d.ts +14 -14
  82. package/dist/cli/tui/tabs/status-tab.d.ts.map +1 -1
  83. package/dist/cli/tui/tabs/status-tab.js +179 -36
  84. package/dist/cli/tui/tabs/status-tab.js.map +1 -1
  85. package/dist/cli/tui/tabs/workflow-tab.d.ts +9 -0
  86. package/dist/cli/tui/tabs/workflow-tab.d.ts.map +1 -0
  87. package/dist/cli/tui/tabs/workflow-tab.js +40 -0
  88. package/dist/cli/tui/tabs/workflow-tab.js.map +1 -0
  89. package/dist/cli/tui/theme.d.ts +75 -55
  90. package/dist/cli/tui/theme.d.ts.map +1 -1
  91. package/dist/cli/tui/theme.js +75 -50
  92. package/dist/cli/tui/theme.js.map +1 -1
  93. package/package.json +1 -1
  94. package/dist/cli/commands/orchestration.d.ts +0 -5
  95. package/dist/cli/commands/orchestration.d.ts.map +0 -1
  96. package/dist/cli/commands/orchestration.js +0 -84
  97. package/dist/cli/commands/orchestration.js.map +0 -1
  98. package/dist/cli/commands/wave2-extras.d.ts +0 -7
  99. package/dist/cli/commands/wave2-extras.d.ts.map +0 -1
  100. package/dist/cli/commands/wave2-extras.js +0 -87
  101. package/dist/cli/commands/wave2-extras.js.map +0 -1
  102. package/dist/cli/commands/wave2-final.d.ts +0 -8
  103. package/dist/cli/commands/wave2-final.d.ts.map +0 -1
  104. package/dist/cli/commands/wave2-final.js +0 -134
  105. package/dist/cli/commands/wave2-final.js.map +0 -1
  106. package/dist/cli/commands/wave4d-simple.d.ts +0 -6
  107. package/dist/cli/commands/wave4d-simple.d.ts.map +0 -1
  108. package/dist/cli/commands/wave4d-simple.js +0 -138
  109. package/dist/cli/commands/wave4d-simple.js.map +0 -1
  110. package/dist/cli/tui/components/confirm-modal.d.ts +0 -12
  111. package/dist/cli/tui/components/confirm-modal.d.ts.map +0 -1
  112. package/dist/cli/tui/components/confirm-modal.js +0 -18
  113. package/dist/cli/tui/components/confirm-modal.js.map +0 -1
  114. package/dist/cli/tui/components/connections-grid.d.ts +0 -8
  115. package/dist/cli/tui/components/connections-grid.d.ts.map +0 -1
  116. package/dist/cli/tui/components/connections-grid.js +0 -55
  117. package/dist/cli/tui/components/connections-grid.js.map +0 -1
  118. package/dist/cli/tui/components/connections-table.d.ts +0 -5
  119. package/dist/cli/tui/components/connections-table.d.ts.map +0 -1
  120. package/dist/cli/tui/components/connections-table.js +0 -11
  121. package/dist/cli/tui/components/connections-table.js.map +0 -1
  122. package/dist/cli/tui/components/footer.d.ts +0 -4
  123. package/dist/cli/tui/components/footer.d.ts.map +0 -1
  124. package/dist/cli/tui/components/footer.js +0 -6
  125. package/dist/cli/tui/components/footer.js.map +0 -1
  126. package/dist/cli/tui/components/header.d.ts +0 -14
  127. package/dist/cli/tui/components/header.d.ts.map +0 -1
  128. package/dist/cli/tui/components/header.js +0 -21
  129. package/dist/cli/tui/components/header.js.map +0 -1
  130. package/dist/cli/tui/components/host-chip.d.ts +0 -28
  131. package/dist/cli/tui/components/host-chip.d.ts.map +0 -1
  132. package/dist/cli/tui/components/host-chip.js +0 -35
  133. package/dist/cli/tui/components/host-chip.js.map +0 -1
  134. package/dist/cli/tui/components/keymap-bar.d.ts +0 -17
  135. package/dist/cli/tui/components/keymap-bar.d.ts.map +0 -1
  136. package/dist/cli/tui/components/keymap-bar.js +0 -13
  137. package/dist/cli/tui/components/keymap-bar.js.map +0 -1
  138. package/dist/cli/tui/components/pill.d.ts +0 -16
  139. package/dist/cli/tui/components/pill.d.ts.map +0 -1
  140. package/dist/cli/tui/components/pill.js +0 -24
  141. package/dist/cli/tui/components/pill.js.map +0 -1
  142. package/dist/cli/tui/components/sectioned-menu.d.ts +0 -24
  143. package/dist/cli/tui/components/sectioned-menu.d.ts.map +0 -1
  144. package/dist/cli/tui/components/sectioned-menu.js +0 -72
  145. package/dist/cli/tui/components/sectioned-menu.js.map +0 -1
  146. package/dist/cli/tui/components/tab-bar.d.ts +0 -23
  147. package/dist/cli/tui/components/tab-bar.d.ts.map +0 -1
  148. package/dist/cli/tui/components/tab-bar.js +0 -17
  149. package/dist/cli/tui/components/tab-bar.js.map +0 -1
  150. package/dist/cli/tui/screens/main-menu.d.ts +0 -8
  151. package/dist/cli/tui/screens/main-menu.d.ts.map +0 -1
  152. package/dist/cli/tui/screens/main-menu.js +0 -24
  153. package/dist/cli/tui/screens/main-menu.js.map +0 -1
  154. package/dist/cli/tui/screens/mcp-done.d.ts +0 -10
  155. package/dist/cli/tui/screens/mcp-done.d.ts.map +0 -1
  156. package/dist/cli/tui/screens/mcp-done.js +0 -24
  157. package/dist/cli/tui/screens/mcp-done.js.map +0 -1
  158. package/dist/cli/tui/screens/mcp-wizard.d.ts +0 -10
  159. package/dist/cli/tui/screens/mcp-wizard.d.ts.map +0 -1
  160. package/dist/cli/tui/screens/mcp-wizard.js +0 -97
  161. package/dist/cli/tui/screens/mcp-wizard.js.map +0 -1
  162. package/dist/cli/tui/tabs/plugins-tab.d.ts +0 -8
  163. package/dist/cli/tui/tabs/plugins-tab.d.ts.map +0 -1
  164. package/dist/cli/tui/tabs/plugins-tab.js +0 -635
  165. package/dist/cli/tui/tabs/plugins-tab.js.map +0 -1
  166. package/dist/cli/tui/tabs/update-tab.d.ts +0 -20
  167. package/dist/cli/tui/tabs/update-tab.d.ts.map +0 -1
  168. package/dist/cli/tui/tabs/update-tab.js +0 -83
  169. package/dist/cli/tui/tabs/update-tab.js.map +0 -1
@@ -1,635 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { readdir, stat } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { Box, Text, useInput } from "ink";
5
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
- import { installPluginSkillsFromGit } from "../../../application/self/install-plugin-skills-git.js";
7
- import { selfInstallPluginSkills } from "../../../application/self/install-plugin-skills.js";
8
- import { selfClearPluginCache, } from "../../../application/self/plugin-cache-clear.js";
9
- import { selfReloadPluginCache } from "../../../application/self/plugin-cache-reload.js";
10
- import { HostChip, HostChipStrip } from "../components/host-chip.js";
11
- import { InputPrompt } from "../components/input-prompt.js";
12
- import { PageHead } from "../components/page-head.js";
13
- import { Pill } from "../components/pill.js";
14
- import { SectionedMenu, } from "../components/sectioned-menu.js";
15
- import { Toast } from "../components/toast.js";
16
- import { useInputLock } from "../input-lock.js";
17
- import { colors, icons } from "../theme.js";
18
- const HOST_LABELS = {
19
- claude: "Claude Code",
20
- codex: "Codex",
21
- warp: "Warp Terminal",
22
- agents: "Oz / Agents",
23
- };
24
- const INSTALLED_TRAILING = {
25
- icon: icons.check,
26
- color: colors.success,
27
- text: "instalado",
28
- };
29
- const CACHED_TRAILING = {
30
- icon: icons.check,
31
- color: colors.success,
32
- text: "cacheado",
33
- };
34
- const NOT_INSTALLED_TRAILING = {
35
- icon: "–",
36
- color: colors.fgMoreSubtle,
37
- text: "no detectado",
38
- };
39
- function targetTrailing(plugin, id) {
40
- const installed = plugin.targets.find((t) => t.id === id)?.installed === true;
41
- if (!installed)
42
- return NOT_INSTALLED_TRAILING;
43
- return id === "claude" || id === "codex" ? CACHED_TRAILING : INSTALLED_TRAILING;
44
- }
45
- function buildActionMenuItems(plugin) {
46
- const items = [];
47
- // Claude Code section (host-managed cache)
48
- items.push({
49
- kind: "item",
50
- label: "Limpiar cache de Claude Code",
51
- value: "clear-claude",
52
- trailing: targetTrailing(plugin, "claude"),
53
- });
54
- items.push({
55
- kind: "item",
56
- label: "Recargar en Claude Code (limpiar + reiniciar host)",
57
- value: "reload-claude",
58
- });
59
- items.push({ kind: "section" });
60
- // Codex section
61
- items.push({
62
- kind: "item",
63
- label: "Limpiar cache de Codex",
64
- value: "clear-codex",
65
- trailing: targetTrailing(plugin, "codex"),
66
- });
67
- items.push({
68
- kind: "item",
69
- label: "Recargar en Codex (limpiar + reiniciar host)",
70
- value: "reload-codex",
71
- });
72
- items.push({ kind: "section" });
73
- // Warp section
74
- items.push({
75
- kind: "item",
76
- label: "Instalar/actualizar en Warp Terminal",
77
- value: "install-warp",
78
- trailing: targetTrailing(plugin, "warp"),
79
- });
80
- items.push({
81
- kind: "item",
82
- label: "Reinstalar en Warp Terminal (force)",
83
- value: "install-warp-force",
84
- });
85
- items.push({
86
- kind: "item",
87
- label: "Clonar desde git e instalar en Warp",
88
- value: "install-warp-git",
89
- });
90
- items.push({ kind: "item", label: "Limpiar instalación en Warp", value: "clear-warp" });
91
- items.push({
92
- kind: "item",
93
- label: "Recargar en Warp (limpiar + reinstalar desde cache)",
94
- value: "reload-warp",
95
- });
96
- items.push({ kind: "section" });
97
- // Agents section
98
- items.push({
99
- kind: "item",
100
- label: "Instalar/actualizar en Oz/Agents",
101
- value: "install-agents",
102
- trailing: targetTrailing(plugin, "agents"),
103
- });
104
- items.push({
105
- kind: "item",
106
- label: "Reinstalar en Oz/Agents (force)",
107
- value: "install-agents-force",
108
- });
109
- items.push({ kind: "item", label: "Limpiar instalación en Oz/Agents", value: "clear-agents" });
110
- items.push({
111
- kind: "item",
112
- label: "Recargar en Oz/Agents (limpiar + reinstalar desde cache)",
113
- value: "reload-agents",
114
- });
115
- return items;
116
- }
117
- const NEW_PLUGIN_MENU_ITEMS = [
118
- { kind: "item", label: "Agregar nuevo plugin desde URL en Warp Terminal", value: "warp" },
119
- { kind: "item", label: "Agregar nuevo plugin desde URL en Oz/Agents", value: "agents" },
120
- ];
121
- const PLUGIN_FILTERS = [
122
- { id: "all", label: "todos" },
123
- { id: "installed", label: "instalados" },
124
- { id: "missing", label: "faltantes" },
125
- { id: "multi", label: "multi-host" },
126
- ];
127
- export function PluginsTab({ ctx, isActive }) {
128
- const [plugins, setPlugins] = useState([]);
129
- const [cursor, setCursor] = useState(0);
130
- const [busy, setBusy] = useState(null);
131
- const [mode, setMode] = useState({ kind: "idle" });
132
- const [toast, setToast] = useState(null);
133
- const [query, setQuery] = useState("");
134
- const [searchOpen, setSearchOpen] = useState(false);
135
- const [filter, setFilter] = useState("all");
136
- const startedRef = useRef(false);
137
- const { lock, unlock } = useInputLock();
138
- // Filtra plugins según el filter activo + query case-insensitive.
139
- const filteredPlugins = useMemo(() => {
140
- const q = query.trim().toLowerCase();
141
- return plugins.filter((p) => {
142
- if (filter === "installed" && !p.targets.some((t) => t.installed))
143
- return false;
144
- if (filter === "missing" && p.sourcePath !== null)
145
- return false;
146
- if (filter === "multi" && p.targets.filter((t) => t.installed).length < 2)
147
- return false;
148
- if (q && !p.label.toLowerCase().includes(q) && !p.namespace.toLowerCase().includes(q))
149
- return false;
150
- return true;
151
- });
152
- }, [plugins, filter, query]);
153
- // Cuando cambia el filtro, mover cursor al primero válido.
154
- useEffect(() => {
155
- setCursor((c) => Math.min(c, Math.max(0, filteredPlugins.length - 1)));
156
- }, [filteredPlugins.length]);
157
- useEffect(() => {
158
- if (mode.kind === "idle")
159
- unlock();
160
- else {
161
- lock();
162
- setToast(null);
163
- }
164
- }, [mode, lock, unlock]);
165
- useEffect(() => {
166
- return () => unlock();
167
- }, [unlock]);
168
- const refresh = useCallback(async () => {
169
- const home = ctx.env.homeDir();
170
- const entries = await buildPluginEntries(home);
171
- setPlugins(entries);
172
- setCursor((c) => Math.min(Math.max(0, entries.length - 1), Math.max(0, c)));
173
- }, [ctx]);
174
- useEffect(() => {
175
- if (startedRef.current)
176
- return;
177
- startedRef.current = true;
178
- void refresh();
179
- }, [refresh]);
180
- const installFromLocal = useCallback(async (target, force) => {
181
- const plugin = filteredPlugins[cursor];
182
- if (!plugin?.sourcePath)
183
- return false;
184
- setBusy(`instalando en ${target}…`);
185
- setToast(null);
186
- try {
187
- const args = {
188
- rest: [],
189
- plugin: {},
190
- flags: new Set(force ? ["--force"] : []),
191
- values: new Map([
192
- ["from", plugin.sourcePath],
193
- ["target", target],
194
- ["namespace", plugin.namespace],
195
- ]),
196
- valuesMulti: new Map(),
197
- };
198
- const result = await selfInstallPluginSkills(args, ctx);
199
- const summary = result.data?.summary ?? result.error?.message ?? "";
200
- setToast({ tone: result.ok ? "success" : "error", message: summary });
201
- await refresh();
202
- }
203
- catch (err) {
204
- setToast({ tone: "error", message: err.message });
205
- }
206
- finally {
207
- setBusy(null);
208
- }
209
- return true;
210
- }, [filteredPlugins, cursor, ctx, refresh]);
211
- const installFromGit = useCallback(async (target, force, url, ref, namespaceOverride) => {
212
- const namespace = namespaceOverride ?? filteredPlugins[cursor]?.namespace ?? "";
213
- const label = HOST_LABELS[target] ?? target;
214
- setBusy(`clonando e instalando en ${label}…`);
215
- setToast(null);
216
- try {
217
- const fullUrl = ref ? `${url}#${ref}` : url;
218
- const args = {
219
- rest: [],
220
- plugin: {},
221
- flags: new Set(force ? ["--force"] : []),
222
- values: new Map([
223
- ["url", fullUrl],
224
- ["target", target],
225
- ["namespace", namespace],
226
- ]),
227
- valuesMulti: new Map(),
228
- };
229
- const result = await installPluginSkillsFromGit(args, ctx);
230
- const summary = result.data?.summary ?? result.error?.message ?? "";
231
- setToast({ tone: result.ok ? "success" : "error", message: summary });
232
- await refresh();
233
- }
234
- catch (err) {
235
- setToast({ tone: "error", message: err.message });
236
- }
237
- finally {
238
- setBusy(null);
239
- }
240
- }, [filteredPlugins, cursor, ctx, refresh]);
241
- const install = useCallback(async (target, force = false, forceGit = false) => {
242
- const plugin = filteredPlugins[cursor];
243
- if (!plugin)
244
- return;
245
- if (!forceGit && plugin.sourcePath) {
246
- await installFromLocal(target, force);
247
- return;
248
- }
249
- if (plugin.sourceUrl) {
250
- await installFromGit(target, force, plugin.sourceUrl, plugin.sourceRef);
251
- return;
252
- }
253
- setMode({ kind: "entering-url", target, force });
254
- }, [filteredPlugins, cursor, installFromLocal, installFromGit]);
255
- const clearCache = useCallback(async (target) => {
256
- const plugin = filteredPlugins[cursor];
257
- if (!plugin)
258
- return;
259
- const label = HOST_LABELS[target];
260
- setBusy(`limpiando ${label}…`);
261
- setToast(null);
262
- try {
263
- const args = {
264
- rest: [],
265
- plugin: {},
266
- flags: new Set(),
267
- values: new Map([
268
- ["plugin", plugin.namespace],
269
- ["target", target],
270
- ]),
271
- valuesMulti: new Map(),
272
- };
273
- const result = await selfClearPluginCache(args, ctx);
274
- const summary = result.data?.summary ?? result.error?.message ?? "";
275
- setToast({ tone: result.ok ? "success" : "error", message: summary });
276
- await refresh();
277
- }
278
- catch (err) {
279
- setToast({ tone: "error", message: err.message });
280
- }
281
- finally {
282
- setBusy(null);
283
- }
284
- }, [filteredPlugins, cursor, ctx, refresh]);
285
- const reloadCache = useCallback(async (target) => {
286
- const plugin = filteredPlugins[cursor];
287
- if (!plugin)
288
- return;
289
- const label = HOST_LABELS[target];
290
- setBusy(`recargando ${label}…`);
291
- setToast(null);
292
- try {
293
- const args = {
294
- rest: [],
295
- plugin: {},
296
- flags: new Set(),
297
- values: new Map([
298
- ["plugin", plugin.namespace],
299
- ["target", target],
300
- ]),
301
- valuesMulti: new Map(),
302
- };
303
- const result = await selfReloadPluginCache(args, ctx);
304
- const summary = result.data?.summary ?? result.error?.message ?? "";
305
- setToast({ tone: result.ok ? "success" : "error", message: summary });
306
- await refresh();
307
- }
308
- catch (err) {
309
- setToast({ tone: "error", message: err.message });
310
- }
311
- finally {
312
- setBusy(null);
313
- }
314
- }, [filteredPlugins, cursor, ctx, refresh]);
315
- const addCustom = useCallback((target) => {
316
- setMode({ kind: "entering-custom-url", target });
317
- }, []);
318
- useInput((input, key) => {
319
- if (!isActive || busy || mode.kind !== "idle")
320
- return;
321
- if (searchOpen)
322
- return; // InputPrompt has focus
323
- if (key.upArrow) {
324
- setCursor((c) => Math.max(0, c - 1));
325
- return;
326
- }
327
- if (key.downArrow) {
328
- setCursor((c) => filteredPlugins.length === 0 ? 0 : Math.min(filteredPlugins.length - 1, c + 1));
329
- return;
330
- }
331
- if (input === "n" || input === "N") {
332
- setMode({ kind: "new-plugin-menu" });
333
- return;
334
- }
335
- if (input === "/") {
336
- setSearchOpen(true);
337
- return;
338
- }
339
- if (input === "f" || input === "F") {
340
- const idx = PLUGIN_FILTERS.findIndex((f) => f.id === filter);
341
- const next = PLUGIN_FILTERS[(idx + 1) % PLUGIN_FILTERS.length];
342
- if (next)
343
- setFilter(next.id);
344
- return;
345
- }
346
- if (input === "r" || input === "R") {
347
- void refresh();
348
- return;
349
- }
350
- if (key.return) {
351
- const target = filteredPlugins[cursor];
352
- if (target)
353
- setMode({ kind: "action-menu", target });
354
- }
355
- }, { isActive });
356
- useInput((_, key) => {
357
- if (!isActive)
358
- return;
359
- if (mode.kind === "idle")
360
- return;
361
- if (key.escape)
362
- setMode({ kind: "idle" });
363
- }, { isActive });
364
- const handleActionSelect = useCallback((action) => {
365
- if (mode.kind !== "action-menu")
366
- return;
367
- setMode({ kind: "idle" });
368
- switch (action) {
369
- case "install-warp":
370
- void install("warp");
371
- return;
372
- case "install-warp-force":
373
- void install("warp", true);
374
- return;
375
- case "install-warp-git":
376
- void install("warp", false, true);
377
- return;
378
- case "install-agents":
379
- void install("agents");
380
- return;
381
- case "install-agents-force":
382
- void install("agents", true);
383
- return;
384
- case "clear-claude":
385
- void clearCache("claude");
386
- return;
387
- case "reload-claude":
388
- void reloadCache("claude");
389
- return;
390
- case "clear-codex":
391
- void clearCache("codex");
392
- return;
393
- case "reload-codex":
394
- void reloadCache("codex");
395
- return;
396
- case "clear-warp":
397
- void clearCache("warp");
398
- return;
399
- case "reload-warp":
400
- void reloadCache("warp");
401
- return;
402
- case "clear-agents":
403
- void clearCache("agents");
404
- return;
405
- case "reload-agents":
406
- void reloadCache("agents");
407
- return;
408
- }
409
- }, [mode, install, clearCache, reloadCache]);
410
- const handleNewPluginSelect = useCallback((target) => {
411
- setMode({ kind: "idle" });
412
- addCustom(target);
413
- }, [addCustom]);
414
- if (mode.kind === "action-menu") {
415
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.fg, bold: true, children: "Plugins" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.fgSubtle, children: [icons.bullet, " acciones de", " ", _jsx(Text, { color: colors.fg, bold: true, children: mode.target.label })] }) }), _jsx(Box, { marginTop: 1, children: _jsx(SectionedMenu, { items: buildActionMenuItems(mode.target), onSelect: handleActionSelect, isActive: isActive }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.fgMoreSubtle, children: "Esc para cerrar sin aplicar." }) })] }));
416
- }
417
- if (mode.kind === "new-plugin-menu") {
418
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.fg, bold: true, children: "Plugins" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.fgSubtle, children: [icons.bullet, " agregar nuevo plugin desde URL git"] }) }), _jsx(Box, { marginTop: 1, children: _jsx(SectionedMenu, { items: NEW_PLUGIN_MENU_ITEMS, onSelect: handleNewPluginSelect, isActive: isActive }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.fgMoreSubtle, children: "Esc para cerrar sin aplicar." }) })] }));
419
- }
420
- if (mode.kind === "entering-url") {
421
- const label = HOST_LABELS[mode.target] ?? mode.target;
422
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.fg, bold: true, children: "Plugins" }), _jsx(Box, { marginTop: 1, children: _jsx(InputPrompt, { message: `URL git del plugin para instalar en ${label}:`, validate: (v) => v.startsWith("http") || "Debe ser una URL git válida (https://...)", onSubmit: (url) => {
423
- setMode({ kind: "idle" });
424
- void installFromGit(mode.target, mode.force, url);
425
- }, isActive: true }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.fgMoreSubtle, children: "Esc para cancelar \u00B7 \u23CE para confirmar" }) })] }));
426
- }
427
- if (mode.kind === "entering-custom-url") {
428
- const label = HOST_LABELS[mode.target] ?? mode.target;
429
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.fg, bold: true, children: "Plugins" }), _jsx(Box, { marginTop: 1, children: _jsx(InputPrompt, { message: `URL git de un plugin nuevo (acepta #rama) — destino ${label}:`, validate: (v) => v.startsWith("http") || "Debe ser una URL git válida (https://...)", onSubmit: (raw) => {
430
- const target = mode.target;
431
- setMode({ kind: "idle" });
432
- const ns = extractNamespaceFromUrl(raw);
433
- void installFromGit(target, true, raw, null, ns);
434
- }, isActive: true }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.fgMoreSubtle, children: "Esc para cancelar \u00B7 \u23CE para confirmar \u00B7 ej: https://bitbucket.org/foo/my-plugin.git#feature/x" }) })] }));
435
- }
436
- const currentPlugin = filteredPlugins[cursor] ?? null;
437
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(PageHead, { title: "Plugins", count: { label: `${filteredPlugins.length}/${plugins.length}`, tone: "info" } }), _jsxs(Box, { children: [PLUGIN_FILTERS.map((f, idx) => (_jsx(Box, { marginLeft: idx === 0 ? 0 : 1, children: _jsx(Text, { color: filter === f.id ? colors.accent : colors.fgFaint, bold: filter === f.id, children: filter === f.id ? `[${f.label}]` : ` ${f.label} ` }) }, f.id))), _jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: colors.fgFaint, children: [_jsx(Text, { color: colors.accent, bold: true, children: "f" }), " filtros · ", _jsx(Text, { color: colors.accent, bold: true, children: "/" }), " buscar · ", _jsx(Text, { color: colors.accent, bold: true, children: "r" }), " refrescar"] }) })] }), searchOpen ? (_jsx(Box, { marginTop: 1, children: _jsx(InputPrompt, { message: "Buscar plugin:", defaultValue: query, onSubmit: (v) => {
438
- setQuery(v.trim());
439
- setSearchOpen(false);
440
- }, isActive: isActive }) })) : query ? (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.fgFaint, children: "filtro:" }), _jsxs(Text, { color: colors.info, children: [" ", query] }), _jsx(Text, { color: colors.fgFaint, children: " (Esc o `/` para cambiar)" })] })) : null, plugins.length === 0 && !busy ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.fgMoreSubtle, italic: true, children: ["(sin plugins detectados \u2014 pulsa ", _jsx(Text, { color: colors.accent, children: "n" }), " para agregar desde URL git, o instala un companion plugin desde el marketplace de Claude Code)"] }) })) : (_jsxs(Box, { marginTop: 1, children: [_jsxs(Box, { flexDirection: "column", minWidth: 42, marginRight: 1, borderStyle: "round", borderColor: colors.borderActive, paddingX: 1, children: [_jsx(Text, { color: colors.fgMoreSubtle, children: "PLUGINS" }), filteredPlugins.length === 0 ? (_jsx(Text, { color: colors.fgFaint, children: "(sin resultados \u2014 `f` cambia filtro)" })) : (filteredPlugins.map((p, i) => (_jsx(PluginListRow, { plugin: p, focused: isActive && i === cursor }, p.id))))] }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: colors.borderFaint, paddingX: 1, children: [_jsx(Text, { color: colors.fgMoreSubtle, children: "DETALLE" }), currentPlugin ? (_jsx(PluginDetail, { plugin: currentPlugin })) : (_jsx(Text, { color: colors.fgFaint, children: "(seleccion\u00E1 un plugin)" }))] })] })), busy ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.warning, children: [icons.spinner, " ", busy] }) })) : null, toast ? _jsx(Toast, { tone: toast.tone, message: toast.message }) : null] }));
441
- }
442
- function PluginListRow({ plugin, focused }) {
443
- const installedHosts = plugin.targets.filter((t) => t.installed).map((t) => t.id);
444
- return (_jsxs(Box, { children: [_jsx(Text, { color: focused ? colors.accent : colors.fgFaint, ...(focused ? { bold: true } : {}), children: focused ? "▸" : " " }), _jsx(Text, { children: " " }), _jsx(Box, { minWidth: 22, children: _jsx(Text, { color: focused ? colors.fgBright : colors.fgSubtle, ...(focused ? { bold: true, inverse: true } : {}), children: focused ? ` ${plugin.namespace} ` : plugin.namespace }) }), _jsx(Box, { minWidth: 10, children: _jsx(Text, { color: colors.info, children: plugin.version ? `v${plugin.version}` : "—" }) }), _jsx(Box, { children: _jsxs(Text, { color: colors.fgFaint, children: [installedHosts.length, "/", plugin.targets.length] }) }), _jsx(Box, { marginLeft: 1, children: _jsx(HostChipStrip, { active: installedHosts, hosts: plugin.targets.map((t) => ({
445
- id: t.id,
446
- name: t.label,
447
- glyph: t.id[0]?.toUpperCase() ?? "?",
448
- short: t.id,
449
- backed: true,
450
- })) }) })] }));
451
- }
452
- function PluginDetail({ plugin }) {
453
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.fgBright, bold: true, children: plugin.label }), _jsxs(Text, { color: colors.fgMoreSubtle, children: ["version \u00B7 ", _jsx(Text, { color: colors.info, children: plugin.version ?? "—" }), plugin.skillCount !== null ? (_jsxs(Text, { color: colors.fgFaint, children: [" \u00B7 ", plugin.skillCount, " skills"] })) : null] }), !plugin.sourcePath && !plugin.sourceUrl ? (_jsx(Box, { marginTop: 1, children: _jsx(Pill, { tone: "warn", children: "fuente no encontrada" }) })) : !plugin.sourcePath && plugin.sourceUrl ? (_jsx(Box, { marginTop: 1, children: _jsx(Pill, { tone: "info", children: "instalar\u00E1 desde git" }) })) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.fgMoreSubtle, children: "hosts" }), plugin.targets.map((t) => (_jsxs(Box, { children: [_jsx(HostChip, { id: t.id, on: t.installed }), _jsx(Text, { children: " " }), _jsx(Text, { color: t.installed ? colors.fgBright : colors.fgFaint, children: t.label }), _jsxs(Text, { color: colors.fgFaint, children: [" \u00B7 ", t.path] })] }, t.id)))] }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.fgFaint, children: [_jsx(Text, { color: colors.accent, bold: true, children: "\u23CE" }), " ", "acciones \u00B7", " ", _jsx(Text, { color: colors.accent, bold: true, children: "n" }), " ", "nuevo desde URL"] }) })] }));
454
- }
455
- async function buildPluginEntries(homeDir) {
456
- return detectCompanionPlugins(homeDir);
457
- }
458
- async function detectCompanionPlugins(homeDir) {
459
- const tuples = await discoverPluginTuples(homeDir);
460
- const entries = [];
461
- const seen = new Set();
462
- for (const { marketplace, namespace } of tuples) {
463
- if (seen.has(namespace))
464
- continue;
465
- seen.add(namespace);
466
- const entry = await buildCompanionEntry(homeDir, marketplace, namespace);
467
- if (entry)
468
- entries.push(entry);
469
- }
470
- return entries;
471
- }
472
- async function discoverPluginTuples(homeDir) {
473
- const tuples = [];
474
- const claudeCache = join(homeDir, ".claude", "plugins", "cache");
475
- try {
476
- const marketplaces = await readdir(claudeCache);
477
- for (const mp of marketplaces) {
478
- try {
479
- const plugins = await readdir(join(claudeCache, mp));
480
- for (const p of plugins) {
481
- try {
482
- const s = await stat(join(claudeCache, mp, p));
483
- if (s.isDirectory()) {
484
- tuples.push({ marketplace: mp, namespace: p });
485
- }
486
- }
487
- catch {
488
- // skip non-stat entries
489
- }
490
- }
491
- }
492
- catch {
493
- // skip non-readable marketplace
494
- }
495
- }
496
- }
497
- catch {
498
- // no claude cache yet
499
- }
500
- return tuples;
501
- }
502
- async function buildCompanionEntry(homeDir, marketplace, namespace) {
503
- const cacheBase = join(homeDir, ".claude", "plugins", "cache", marketplace, namespace);
504
- const version = await findLatestVersion(cacheBase);
505
- const skillsDir = version ? join(cacheBase, version, "skills") : null;
506
- const skillCount = skillsDir ? await countSkillDirs(skillsDir) : null;
507
- const targets = [
508
- {
509
- id: "claude",
510
- label: HOST_LABELS.claude,
511
- path: `~/.claude/plugins/cache/*/${namespace}/`,
512
- installed: await isHostCacheDetected(homeDir, "claude", namespace),
513
- },
514
- {
515
- id: "codex",
516
- label: HOST_LABELS.codex,
517
- path: `~/.codex/plugins/cache/*/${namespace}/`,
518
- installed: await isHostCacheDetected(homeDir, "codex", namespace),
519
- },
520
- {
521
- id: "warp",
522
- label: HOST_LABELS.warp,
523
- path: `~/.warp/skills/${namespace}-*/`,
524
- installed: await areSkillsInstalled(homeDir, "warp", namespace),
525
- },
526
- {
527
- id: "agents",
528
- label: HOST_LABELS.agents,
529
- path: `~/.agents/skills/${namespace}-*/`,
530
- installed: await areSkillsInstalled(homeDir, "agents", namespace),
531
- },
532
- ];
533
- return {
534
- id: namespace,
535
- label: `${marketplace}/${namespace}`,
536
- namespace,
537
- sourcePath: skillsDir,
538
- sourceUrl: null,
539
- sourceRef: null,
540
- version: version ?? null,
541
- skillCount,
542
- targets,
543
- };
544
- }
545
- async function findLatestVersion(base) {
546
- try {
547
- const entries = await readdir(base);
548
- const versions = entries.filter((e) => /^\d+\.\d+\.\d+/.test(e)).sort(semverDesc);
549
- return versions[0] ?? null;
550
- }
551
- catch {
552
- return null;
553
- }
554
- }
555
- async function countSkillDirs(skillsDir) {
556
- try {
557
- const entries = await readdir(skillsDir);
558
- let count = 0;
559
- for (const e of entries) {
560
- try {
561
- const s = await stat(join(skillsDir, e));
562
- if (s.isDirectory())
563
- count += 1;
564
- }
565
- catch {
566
- // skip
567
- }
568
- }
569
- return count;
570
- }
571
- catch {
572
- return null;
573
- }
574
- }
575
- async function isHostCacheDetected(homeDir, host, namespace) {
576
- const cacheRoot = join(homeDir, `.${host}`, "plugins", "cache");
577
- try {
578
- const marketplaces = await readdir(cacheRoot);
579
- for (const mp of marketplaces) {
580
- const pluginDir = join(cacheRoot, mp, namespace);
581
- try {
582
- const s = await stat(pluginDir);
583
- if (s.isDirectory())
584
- return true;
585
- }
586
- catch {
587
- // not here
588
- }
589
- }
590
- }
591
- catch {
592
- return false;
593
- }
594
- return false;
595
- }
596
- async function areSkillsInstalled(homeDir, host, namespace) {
597
- const skillsRoot = join(homeDir, `.${host}`, "skills");
598
- try {
599
- const entries = await readdir(skillsRoot);
600
- const prefix = `${namespace}-`;
601
- for (const e of entries) {
602
- if (!e.startsWith(prefix))
603
- continue;
604
- try {
605
- const s = await stat(join(skillsRoot, e));
606
- if (s.isDirectory())
607
- return true;
608
- }
609
- catch {
610
- // skip
611
- }
612
- }
613
- }
614
- catch {
615
- return false;
616
- }
617
- return false;
618
- }
619
- function semverDesc(a, b) {
620
- const parse = (v) => v.split(".").map(Number);
621
- const [aMaj = 0, aMin = 0, aPatch = 0] = parse(a);
622
- const [bMaj = 0, bMin = 0, bPatch = 0] = parse(b);
623
- return bMaj - aMaj || bMin - aMin || bPatch - aPatch;
624
- }
625
- export function extractNamespaceFromUrl(rawUrl) {
626
- const url = rawUrl.split("#")[0] ?? rawUrl;
627
- const lastSeg = url.replace(/\/+$/, "").split("/").pop() ?? "";
628
- const cleaned = lastSeg.replace(/\.git$/i, "");
629
- const slug = cleaned
630
- .toLowerCase()
631
- .replace(/[^a-z0-9]+/g, "-")
632
- .replace(/^-+|-+$/g, "");
633
- return slug.slice(0, 32);
634
- }
635
- //# sourceMappingURL=plugins-tab.js.map