@tacuchi/agent-workflow-cli 7.3.0 → 8.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 (75) hide show
  1. package/dist/cli/tui/app.d.ts.map +1 -1
  2. package/dist/cli/tui/app.js +195 -53
  3. package/dist/cli/tui/app.js.map +1 -1
  4. package/dist/cli/tui/components/action-modal.d.ts +33 -0
  5. package/dist/cli/tui/components/action-modal.d.ts.map +1 -0
  6. package/dist/cli/tui/components/action-modal.js +41 -0
  7. package/dist/cli/tui/components/action-modal.js.map +1 -0
  8. package/dist/cli/tui/components/command-palette.d.ts +12 -33
  9. package/dist/cli/tui/components/command-palette.d.ts.map +1 -1
  10. package/dist/cli/tui/components/command-palette.js +17 -110
  11. package/dist/cli/tui/components/command-palette.js.map +1 -1
  12. package/dist/cli/tui/components/connections-grid.js +3 -3
  13. package/dist/cli/tui/components/connections-grid.js.map +1 -1
  14. package/dist/cli/tui/components/connections-table.js +1 -1
  15. package/dist/cli/tui/components/connections-table.js.map +1 -1
  16. package/dist/cli/tui/components/family-card.d.ts +10 -0
  17. package/dist/cli/tui/components/family-card.d.ts.map +1 -0
  18. package/dist/cli/tui/components/family-card.js +7 -0
  19. package/dist/cli/tui/components/family-card.js.map +1 -0
  20. package/dist/cli/tui/components/frame-box.d.ts +10 -0
  21. package/dist/cli/tui/components/frame-box.d.ts.map +1 -0
  22. package/dist/cli/tui/components/frame-box.js +9 -0
  23. package/dist/cli/tui/components/frame-box.js.map +1 -0
  24. package/dist/cli/tui/components/input-prompt.js +1 -1
  25. package/dist/cli/tui/components/input-prompt.js.map +1 -1
  26. package/dist/cli/tui/components/list-row.d.ts +22 -0
  27. package/dist/cli/tui/components/list-row.d.ts.map +1 -0
  28. package/dist/cli/tui/components/list-row.js +27 -0
  29. package/dist/cli/tui/components/list-row.js.map +1 -0
  30. package/dist/cli/tui/components/page-head.d.ts +14 -5
  31. package/dist/cli/tui/components/page-head.d.ts.map +1 -1
  32. package/dist/cli/tui/components/page-head.js +9 -5
  33. package/dist/cli/tui/components/page-head.js.map +1 -1
  34. package/dist/cli/tui/components/phase-card.d.ts +14 -0
  35. package/dist/cli/tui/components/phase-card.d.ts.map +1 -0
  36. package/dist/cli/tui/components/phase-card.js +8 -0
  37. package/dist/cli/tui/components/phase-card.js.map +1 -0
  38. package/dist/cli/tui/components/sectioned-menu.js +1 -1
  39. package/dist/cli/tui/components/sectioned-menu.js.map +1 -1
  40. package/dist/cli/tui/components/stat-tile.d.ts +14 -0
  41. package/dist/cli/tui/components/stat-tile.d.ts.map +1 -0
  42. package/dist/cli/tui/components/stat-tile.js +22 -0
  43. package/dist/cli/tui/components/stat-tile.js.map +1 -0
  44. package/dist/cli/tui/data/workflow-content.d.ts +16 -0
  45. package/dist/cli/tui/data/workflow-content.d.ts.map +1 -0
  46. package/dist/cli/tui/data/workflow-content.js +202 -0
  47. package/dist/cli/tui/data/workflow-content.js.map +1 -0
  48. package/dist/cli/tui/tabs/mcp-tab.d.ts +6 -12
  49. package/dist/cli/tui/tabs/mcp-tab.d.ts.map +1 -1
  50. package/dist/cli/tui/tabs/mcp-tab.js +127 -141
  51. package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
  52. package/dist/cli/tui/tabs/project-tab.d.ts.map +1 -1
  53. package/dist/cli/tui/tabs/project-tab.js +30 -29
  54. package/dist/cli/tui/tabs/project-tab.js.map +1 -1
  55. package/dist/cli/tui/tabs/skills-tab.d.ts +18 -8
  56. package/dist/cli/tui/tabs/skills-tab.d.ts.map +1 -1
  57. package/dist/cli/tui/tabs/skills-tab.js +175 -112
  58. package/dist/cli/tui/tabs/skills-tab.js.map +1 -1
  59. package/dist/cli/tui/tabs/status-tab.d.ts +11 -14
  60. package/dist/cli/tui/tabs/status-tab.d.ts.map +1 -1
  61. package/dist/cli/tui/tabs/status-tab.js +138 -34
  62. package/dist/cli/tui/tabs/status-tab.js.map +1 -1
  63. package/dist/cli/tui/tabs/workflow-tab.d.ts +7 -0
  64. package/dist/cli/tui/tabs/workflow-tab.d.ts.map +1 -0
  65. package/dist/cli/tui/tabs/workflow-tab.js +24 -0
  66. package/dist/cli/tui/tabs/workflow-tab.js.map +1 -0
  67. package/package.json +1 -1
  68. package/dist/cli/tui/tabs/plugins-tab.d.ts +0 -8
  69. package/dist/cli/tui/tabs/plugins-tab.d.ts.map +0 -1
  70. package/dist/cli/tui/tabs/plugins-tab.js +0 -635
  71. package/dist/cli/tui/tabs/plugins-tab.js.map +0 -1
  72. package/dist/cli/tui/tabs/update-tab.d.ts +0 -20
  73. package/dist/cli/tui/tabs/update-tab.d.ts.map +0 -1
  74. package/dist/cli/tui/tabs/update-tab.js +0 -83
  75. package/dist/cli/tui/tabs/update-tab.js.map +0 -1
@@ -0,0 +1,202 @@
1
+ // Datos del Workflow tab — hardcoded para evitar I/O en render.
2
+ // Sincronizado con (verificado en T4):
3
+ // - skills/agent-workflow/SKILL.md (familias de comandos)
4
+ // - skills/agent-workflow/commands/ (17 slash commands)
5
+ // - skills/agent-workflow/hooks/hooks.template.json (5 eventos)
6
+ // - aw --help (familias del CLI real)
7
+ //
8
+ // Puntos de drift: si se agregan/quitan slash commands en `commands/` o se
9
+ // renombran familias en SKILL.md, actualizar este archivo. Los totales se
10
+ // derivan con `.length` en runtime — NO hardcodear cantidades en strings.
11
+ export const WORKFLOW_CONTENT = {
12
+ overview: "Universal session-lifecycle harness — 11 families, 17 slash commands, 5 hooks.",
13
+ // 5-phase user-facing lifecycle.
14
+ phases: [
15
+ {
16
+ id: "discover",
17
+ n: 1,
18
+ title: "Discover",
19
+ desc: "Detect workspace state — sources, branches, mode, stack.",
20
+ commands: ["sources", "workspace-mode", "sessions"],
21
+ slash: "—",
22
+ hook: "—",
23
+ },
24
+ {
25
+ id: "start",
26
+ n: 2,
27
+ title: "Start",
28
+ desc: "Open a tracked session with OBJECTIVE + flow (core/dev/design).",
29
+ commands: ["session-create", "session-resume"],
30
+ slash: "/agent-workflow:session",
31
+ hook: "SessionStart",
32
+ },
33
+ {
34
+ id: "plan",
35
+ n: 3,
36
+ title: "Plan",
37
+ desc: "Choose planning depth + detect phase.",
38
+ commands: ["auto-plan-decide", "phase-detect", "specialty-choose"],
39
+ slash: "/agent-workflow:rules",
40
+ hook: "—",
41
+ },
42
+ {
43
+ id: "work",
44
+ n: 4,
45
+ title: "Work",
46
+ desc: "Persist progress in CHECKPOINT.md. Drift caught by topic-change.",
47
+ commands: ["checkpoint-write", "topic-change-check", "tasks-data"],
48
+ slash: "/agent-workflow:compact",
49
+ hook: "PreToolUse · PreCompact · PostCompact",
50
+ },
51
+ {
52
+ id: "close",
53
+ n: 5,
54
+ title: "Close / Graduate",
55
+ desc: "Close session + export artifacts. Handoff or release.",
56
+ commands: ["session-close", "release-data", "graduate"],
57
+ slash: "/agent-workflow:resume",
58
+ hook: "SessionEnd",
59
+ },
60
+ ],
61
+ // 11 command families verified against `aw --help`.
62
+ commandFamilies: [
63
+ {
64
+ id: "session",
65
+ title: "Session mgmt",
66
+ items: ["sessions", "session-create", "session-resume", "session-close", "session-artifacts"],
67
+ },
68
+ {
69
+ id: "objetivo",
70
+ title: "Objective / Tasks",
71
+ items: ["objetivo-data", "tasks-data", "decisiones-list", "dependencias-list"],
72
+ },
73
+ {
74
+ id: "checkpoint",
75
+ title: "Checkpoint",
76
+ items: [
77
+ "checkpoint-read",
78
+ "checkpoint-write",
79
+ "compress-checkpoint",
80
+ "auto-compact-on-close",
81
+ ],
82
+ },
83
+ {
84
+ id: "sources",
85
+ title: "Sources / branches",
86
+ items: ["sources", "attach-multiroot", "detach-multiroot", "check-branch"],
87
+ },
88
+ {
89
+ id: "orchestration",
90
+ title: "Orchestration",
91
+ items: [
92
+ "phase-detect",
93
+ "phase-next",
94
+ "workflows",
95
+ "workspace-mode",
96
+ "stack",
97
+ "skill-index",
98
+ "auto-plan-decide",
99
+ "topic-change-check",
100
+ "specialty-choose",
101
+ "resume-summary",
102
+ ],
103
+ },
104
+ {
105
+ id: "doctor",
106
+ title: "Doctor / Data",
107
+ items: [
108
+ "plugin-doctor",
109
+ "plugin-cache",
110
+ "history-data",
111
+ "history-update",
112
+ "release-data",
113
+ "code-scan",
114
+ "project-md-upsert",
115
+ "bootstrap-dsn",
116
+ "graduate",
117
+ "upgrade-hub-mode",
118
+ ],
119
+ },
120
+ {
121
+ id: "hooks",
122
+ title: "Hooks (cli)",
123
+ items: ["hook branch-check", "hook sql-mutation-guard", "hook git-commit-advisor"],
124
+ },
125
+ {
126
+ id: "mcp",
127
+ title: "MCP / DSN",
128
+ items: ["mcp dbhub", "mcp setup", "mcp remove", "mcp doctor", "mcp warp-status"],
129
+ },
130
+ {
131
+ id: "dev",
132
+ title: "Dev-only",
133
+ items: ["harness", "profiles", "logs", "next-number"],
134
+ },
135
+ {
136
+ id: "self",
137
+ title: "Self",
138
+ items: [
139
+ "self doctor",
140
+ "self install",
141
+ "self uninstall",
142
+ "self detect-hosts",
143
+ "self mcp",
144
+ "self bootstrap",
145
+ ],
146
+ },
147
+ {
148
+ id: "other",
149
+ title: "Other",
150
+ items: ["graduation-check", "hub-init", "visibility"],
151
+ },
152
+ ],
153
+ // 17 slash commands — `ls skills/agent-workflow/commands/*.md`.
154
+ slashCommands: [
155
+ "/agent-workflow:session",
156
+ "/agent-workflow:resume",
157
+ "/agent-workflow:compact",
158
+ "/agent-workflow:doctor",
159
+ "/agent-workflow:rules",
160
+ "/agent-workflow:migrate",
161
+ "/agent-workflow:project-init",
162
+ "/agent-workflow:hub-init",
163
+ "/agent-workflow:export-plan",
164
+ "/agent-workflow:export-arq",
165
+ "/agent-workflow:export-report",
166
+ "/agent-workflow:export-conclusions",
167
+ "/agent-workflow:export-scripts",
168
+ "/agent-workflow:export-requirement",
169
+ "/agent-workflow:export-qa-note",
170
+ "/agent-workflow:export-tech-note",
171
+ "/agent-workflow:export-tech-manuals",
172
+ ],
173
+ // 5 hooks de hooks.template.json — matcher real + qué disparan.
174
+ hooks: [
175
+ {
176
+ name: "SessionStart",
177
+ matcher: "startup|resume|clear",
178
+ fires: "Inject namespace into ~/.config/agent-workflow/namespace",
179
+ },
180
+ {
181
+ name: "PreToolUse",
182
+ matcher: "Edit|Write|MultiEdit · mcp__*__execute_sql · Bash",
183
+ fires: "branch-check · sql-mutation-guard · git-commit-advisor",
184
+ },
185
+ {
186
+ name: "SessionEnd",
187
+ matcher: "(any)",
188
+ fires: "agent-workflow auto-compact-on-close",
189
+ },
190
+ {
191
+ name: "PreCompact",
192
+ matcher: "(any)",
193
+ fires: "checkpoint-write — preserves OBJECTIVE before compacting",
194
+ },
195
+ {
196
+ name: "PostCompact",
197
+ matcher: "(any)",
198
+ fires: "resume-summary + prompt to reload CHECKPOINT.md",
199
+ },
200
+ ],
201
+ };
202
+ //# sourceMappingURL=workflow-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-content.js","sourceRoot":"","sources":["../../../../src/cli/tui/data/workflow-content.ts"],"names":[],"mappings":"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"}
@@ -9,20 +9,14 @@ export interface McpTabProps {
9
9
  }) => void;
10
10
  }
11
11
  /**
12
- * MCPTab redesign split view:
12
+ * McpTablistado MCP single-column + ActionModal overlay + Add wizard inline.
13
13
  *
14
- * ┌─ conexiones ──────────────┐ ┌─ detalle (selected) ─┐
15
- * qtc-cert DB_CERT_DSN │ │ host visible en │
16
- * qtc-prod DB_PROD_DSN │ │ acciones: i/o/w/t/r │
17
- * └───────────────────────────┘ └──────────────────────┘
14
+ * Layout match con handoff (variant-palette.jsx MCPTab):
15
+ * PageHead con `+ add connection` action button → FrameBox "connections" accent
16
+ * con ListRow por conexión → ActionModal overlay al ⏎ (Test / Edit / Remove).
18
17
  *
19
- * - `↑↓` mueve cursor en la lista
20
- * - `n` nueva conexión, `r` eliminar la actual, `t` doctor
21
- * - `i/o/w` install en claude/codex/warp respectivamente
22
- * - Host chips reemplazan columnas Claude/Codex/Warp
23
- *
24
- * Mantiene los modos (new-name/new-dsn/confirm-delete/busy) tal cual; sólo
25
- * cambia el render de list y la forma de invocar acciones.
18
+ * Add/Edit wizard inline tras `a` shortcut o acción Edit. ConfirmModal para
19
+ * remove. Busy label durante ops.
26
20
  */
27
21
  export declare function McpTab({ ctx, isActive, onToast }: McpTabProps): import("react/jsx-runtime").JSX.Element;
28
22
  //# sourceMappingURL=mcp-tab.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-tab.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/tabs/mcp-tab.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAoCjD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACxF;AAYD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,2CAiQ7D"}
1
+ {"version":3,"file":"mcp-tab.d.ts","sourceRoot":"","sources":["../../../../src/cli/tui/tabs/mcp-tab.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAoBjD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACxF;AAYD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,2CAiY7D"}
@@ -2,24 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
4
  import { selfMcpConfig, } from "../../../application/self/mcp-config.js";
5
+ import { ActionModal } from "../components/action-modal.js";
5
6
  import { ConfirmModal } from "../components/confirm-modal.js";
7
+ import { FrameBox } from "../components/frame-box.js";
6
8
  import { InputPrompt } from "../components/input-prompt.js";
9
+ import { ListRow } from "../components/list-row.js";
7
10
  import { PageHead } from "../components/page-head.js";
8
- import { Pill } from "../components/pill.js";
9
11
  import { useInputLock } from "../input-lock.js";
10
12
  import { colors, icons } from "../theme.js";
11
- const ACTIONS = [
12
- {
13
- id: "install-claude",
14
- label: "Instalar en Claude Code",
15
- busyLabel: () => "instalando en Claude…",
16
- },
17
- { id: "install-codex", label: "Instalar en Codex", busyLabel: () => "instalando en Codex…" },
18
- { id: "install-warp", label: "Instalar en Warp", busyLabel: () => "instalando en Warp…" },
19
- { id: "doctor", label: "Diagnosticar (doctor)", busyLabel: () => "diagnosticando…" },
20
- { id: "remove", label: "Eliminar conexión…", busyLabel: (n) => `eliminando ${n}…`, danger: true },
21
- { id: "new", label: "Nueva conexión…", busyLabel: () => "" },
22
- ];
23
13
  function buildArgs(action, values = {}) {
24
14
  return {
25
15
  rest: ["mcp", action],
@@ -30,31 +20,23 @@ function buildArgs(action, values = {}) {
30
20
  };
31
21
  }
32
22
  /**
33
- * MCPTab redesign split view:
23
+ * McpTablistado MCP single-column + ActionModal overlay + Add wizard inline.
34
24
  *
35
- * ┌─ conexiones ──────────────┐ ┌─ detalle (selected) ─┐
36
- * qtc-cert DB_CERT_DSN │ │ host visible en │
37
- * qtc-prod DB_PROD_DSN │ │ acciones: i/o/w/t/r │
38
- * └───────────────────────────┘ └──────────────────────┘
25
+ * Layout match con handoff (variant-palette.jsx MCPTab):
26
+ * PageHead con `+ add connection` action button → FrameBox "connections" accent
27
+ * con ListRow por conexión → ActionModal overlay al ⏎ (Test / Edit / Remove).
39
28
  *
40
- * - `↑↓` mueve cursor en la lista
41
- * - `n` nueva conexión, `r` eliminar la actual, `t` doctor
42
- * - `i/o/w` install en claude/codex/warp respectivamente
43
- * - Host chips reemplazan columnas Claude/Codex/Warp
44
- *
45
- * Mantiene los modos (new-name/new-dsn/confirm-delete/busy) tal cual; sólo
46
- * cambia el render de list y la forma de invocar acciones.
29
+ * Add/Edit wizard inline tras `a` shortcut o acción Edit. ConfirmModal para
30
+ * remove. Busy label durante ops.
47
31
  */
48
32
  export function McpTab({ ctx, isActive, onToast }) {
49
33
  const [connections, setConnections] = useState([]);
50
34
  const [cursor, setCursor] = useState(0);
51
35
  const [actionCursor, setActionCursor] = useState(0);
52
36
  const [mode, setMode] = useState({ kind: "list" });
53
- const [warpHint, setWarpHint] = useState(null);
54
37
  const startedRef = useRef(false);
55
38
  const { lock, unlock } = useInputLock();
56
39
  useEffect(() => {
57
- // Lock global hotkeys solo en modes que toman input crítico (text inputs).
58
40
  if (mode.kind === "list" || mode.kind === "actions")
59
41
  unlock();
60
42
  else
@@ -66,10 +48,10 @@ export function McpTab({ ctx, isActive, onToast }) {
66
48
  const result = await selfMcpConfig(buildArgs("list"), ctx);
67
49
  const next = result.ok ? (result.data?.connections ?? []) : [];
68
50
  setConnections(next);
69
- setCursor((c) => Math.min(Math.max(0, next.length - 1), Math.max(0, c)));
51
+ setCursor((c) => Math.min(Math.max(0, c), Math.max(0, next.length - 1)));
70
52
  }
71
53
  catch (err) {
72
- onToast?.({ tone: "err", title: "Error cargando MCP", body: err.message });
54
+ onToast?.({ tone: "err", title: "Error loading MCP", body: err.message });
73
55
  }
74
56
  }, [ctx, onToast]);
75
57
  useEffect(() => {
@@ -78,59 +60,97 @@ export function McpTab({ ctx, isActive, onToast }) {
78
60
  startedRef.current = true;
79
61
  void refresh();
80
62
  }, [refresh]);
81
- const current = connections[cursor];
82
- const runAction = useCallback(async (action, name, label) => {
63
+ const current = connections[cursor] ?? null;
64
+ const runRawAction = useCallback(async (action, name, label) => {
83
65
  setMode({ kind: "busy", label });
84
- setWarpHint(null);
85
66
  try {
86
67
  const result = await selfMcpConfig(buildArgs(action, { name }), ctx);
87
- const summary = result.data?.summary ?? result.error?.message ?? "";
88
- const isWarpInstall = result.ok && action === "install-warp" && result.data?.warp_hint;
89
- onToast?.({
90
- tone: result.ok ? "ok" : "err",
91
- title: result.ok ? "Acción aplicada" : "Falló",
92
- body: summary,
93
- });
94
- if (isWarpInstall && result.data?.warp_hint)
95
- setWarpHint(result.data.warp_hint);
96
- await refresh();
68
+ if (!result.ok) {
69
+ const summary = result.error?.message ?? "failed";
70
+ onToast?.({ tone: "err", title: `Step ${action} failed`, body: summary });
71
+ return false;
72
+ }
73
+ return true;
97
74
  }
98
75
  catch (err) {
99
76
  onToast?.({ tone: "err", title: "Error", body: err.message });
77
+ return false;
100
78
  }
101
- finally {
102
- setMode({ kind: "list" });
103
- }
104
- }, [ctx, refresh, onToast]);
105
- const applyAction = useCallback((def) => {
106
- if (def.id === "new") {
107
- setMode({ kind: "new-name" });
108
- return;
109
- }
79
+ }, [ctx, onToast]);
80
+ const runDoctor = useCallback(async (name) => {
81
+ const ok = await runRawAction("doctor", name, `pinging ${name}…`);
82
+ if (ok)
83
+ onToast?.({ tone: "ok", title: `Test OK · ${name}`, body: "DSN reachable" });
84
+ await refresh();
85
+ setMode({ kind: "list" });
86
+ }, [runRawAction, refresh, onToast]);
87
+ const applyModalAction = useCallback((id) => {
110
88
  if (!current)
111
89
  return;
112
- if (def.id === "remove") {
113
- setMode({ kind: "confirm-delete", name: current.nombre });
114
- return;
115
- }
116
- void runAction(def.id, current.nombre, def.busyLabel(current.nombre));
117
- }, [current, runAction]);
118
- // input — list mode (cursor en la lista de conexiones)
90
+ switch (id) {
91
+ case "test":
92
+ void runDoctor(current.nombre);
93
+ return;
94
+ case "edit":
95
+ setMode({
96
+ kind: "wizard-name",
97
+ editingName: current.nombre,
98
+ prefillDsn: current.dsn_var,
99
+ });
100
+ return;
101
+ case "remove":
102
+ setMode({ kind: "confirm-delete", name: current.nombre });
103
+ return;
104
+ }
105
+ }, [current, runDoctor]);
106
+ // 3 acciones: Test / Edit / Remove. Match con MCPActionModal del handoff.
107
+ const modalActions = current
108
+ ? [
109
+ {
110
+ id: "test",
111
+ icon: icons.refresh,
112
+ label: "Test connection",
113
+ desc: `Open a socket to ${current.server_name} and run \`SELECT 1\``,
114
+ },
115
+ {
116
+ id: "edit",
117
+ icon: icons.edit,
118
+ label: "Edit connection",
119
+ desc: "Modify alias, host or database in profile.json",
120
+ },
121
+ {
122
+ id: "remove",
123
+ icon: icons.cross,
124
+ label: "Remove connection",
125
+ desc: `Delete from \`mcp_databases[]\` and unexport ${current.dsn_var}`,
126
+ danger: true,
127
+ },
128
+ ]
129
+ : [];
130
+ // input — list mode
119
131
  useInput((input, key) => {
120
132
  if (!isActive || mode.kind !== "list")
121
133
  return;
122
- if (handleNav(key, connections.length, setCursor))
134
+ if (input === "a" || input === "A") {
135
+ setMode({ kind: "wizard-name" });
136
+ return;
137
+ }
138
+ if (key.upArrow) {
139
+ setCursor((c) => Math.max(0, c - 1));
140
+ setActionCursor(0);
123
141
  return;
124
- if (input === "n" || input === "N") {
125
- setMode({ kind: "new-name" });
142
+ }
143
+ if (key.downArrow) {
144
+ setCursor((c) => (connections.length === 0 ? 0 : Math.min(connections.length - 1, c + 1)));
145
+ setActionCursor(0);
126
146
  return;
127
147
  }
128
- if (key.return) {
148
+ if (key.return && current) {
129
149
  setActionCursor(0);
130
150
  setMode({ kind: "actions" });
131
151
  }
132
152
  }, { isActive });
133
- // input — actions mode (cursor en las acciones del detail panel)
153
+ // input — actions mode (modal)
134
154
  useInput((_input, key) => {
135
155
  if (!isActive || mode.kind !== "actions")
136
156
  return;
@@ -139,7 +159,7 @@ export function McpTab({ ctx, isActive, onToast }) {
139
159
  return;
140
160
  }
141
161
  if (key.downArrow) {
142
- setActionCursor((c) => Math.min(ACTIONS.length - 1, c + 1));
162
+ setActionCursor((c) => Math.min(modalActions.length - 1, c + 1));
143
163
  return;
144
164
  }
145
165
  if (key.escape) {
@@ -147,9 +167,9 @@ export function McpTab({ ctx, isActive, onToast }) {
147
167
  return;
148
168
  }
149
169
  if (key.return) {
150
- const def = ACTIONS[actionCursor];
170
+ const def = modalActions[actionCursor];
151
171
  if (def)
152
- applyAction(def);
172
+ applyModalAction(def.id);
153
173
  }
154
174
  }, { isActive });
155
175
  // input — confirm-delete
@@ -157,50 +177,65 @@ export function McpTab({ ctx, isActive, onToast }) {
157
177
  if (!isActive || mode.kind !== "confirm-delete")
158
178
  return;
159
179
  if (input === "y" || input === "Y") {
160
- void runAction("remove", mode.name, `eliminando ${mode.name}…`);
180
+ void runRawAction("remove", mode.name, `removing ${mode.name}…`).then(async (ok) => {
181
+ if (ok)
182
+ onToast?.({ tone: "ok", title: `Connection '${mode.name}' removed` });
183
+ await refresh();
184
+ setMode({ kind: "list" });
185
+ });
161
186
  }
162
187
  else if (key.escape || input === "n" || input === "N") {
163
188
  setMode({ kind: "list" });
164
189
  }
165
190
  }, { isActive });
166
- // input — esc en new-name/new-dsn
191
+ // input — esc en wizard
167
192
  useInput((_input, key) => {
168
193
  if (!isActive)
169
194
  return;
170
- if (mode.kind === "new-name" || mode.kind === "new-dsn") {
195
+ if (mode.kind === "wizard-name" || mode.kind === "wizard-dsn") {
171
196
  if (key.escape)
172
197
  setMode({ kind: "list" });
173
198
  }
174
199
  }, { isActive });
175
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(PageHead, { title: "MCP", count: { label: `${connections.length}`, tone: "info" } }), mode.kind === "list" || mode.kind === "actions" ? (_jsx(McpSplitView, { connections: connections, cursor: cursor, current: current ?? null, actionMode: mode.kind === "actions", actionCursor: actionCursor })) : null, mode.kind === "new-name" ? (_jsx(InputPrompt, { message: "Nombre de la nueva conexi\u00F3n (slug-kebab):", onSubmit: (value) => {
176
- const trimmed = value.trim();
177
- if (!trimmed) {
178
- onToast?.({ tone: "err", title: "Nombre vacío" });
179
- setMode({ kind: "list" });
180
- return;
181
- }
182
- setMode({ kind: "new-dsn", name: trimmed });
183
- }, isActive: isActive })) : null, mode.kind === "new-dsn" ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsxs(Text, { color: colors.fgSubtle, children: [icons.bullet, " nombre:", " ", _jsx(Text, { color: colors.fgBright, bold: true, children: mode.name })] }) }), _jsx(Box, { marginTop: 1, children: _jsx(InputPrompt, { message: "Variable de entorno con la DSN (UPPER_SNAKE_CASE):", onSubmit: (value) => {
184
- const dsnVar = value.trim();
185
- if (!dsnVar) {
186
- onToast?.({ tone: "err", title: "DSN var vacía" });
187
- setMode({ kind: "list" });
188
- return;
189
- }
190
- void runAction("use-env", mode.name, `registrando ${mode.name}…`);
191
- // NOTE: la acción `use-env` requiere también `dsn-var`; el helper
192
- // existente buildArgs sólo pasa `name`. Reusamos selfMcpConfig
193
- // directo aquí.
194
- void registerConnection(mode.name, dsnVar);
195
- }, isActive: isActive }) })] })) : null, mode.kind === "confirm-delete" ? (_jsx(ConfirmModal, { tone: "danger", title: "Eliminar conexi\u00F3n", body: [`Vas a eliminar la conexión '${mode.name}'.`, "Esta acción no se puede deshacer."], confirmKey: "y", confirmLabel: `Sí, eliminar ${mode.name}`, cancelKey: "n / Esc", cancelLabel: "Cancelar" })) : null, mode.kind === "busy" ? (_jsx(Box, { children: _jsxs(Text, { color: colors.warning, children: [icons.spinner, " ", mode.label] }) })) : null, warpHint ? _jsx(WarpHintPanel, { hint: warpHint }) : null, mode.kind === "list" ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.fgFaint, children: "\u23CE ver acciones \u00B7 n nueva conexi\u00F3n \u00B7 q salir" }) })) : null, mode.kind === "actions" ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.fgFaint, children: "\u2191\u2193 navegar acciones \u00B7 \u23CE aplicar \u00B7 esc volver" }) })) : null] }));
200
+ const inListMode = mode.kind === "list";
201
+ const addButton = (_jsx(Text, { color: colors.accent, bold: true, inverse: true, children: " a · + add connection " }));
202
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(PageHead, { title: "MCP", count: {
203
+ label: `${connections.length} db`,
204
+ tone: connections.length > 0 ? "accent" : "muted",
205
+ }, desc: "databases for skill consumption \u00B7 aliases match `mcp_databases[]` in profile.json", action: addButton }), inListMode ? (_jsx(FrameBox, { title: `connections · ${connections.length}`, accent: connections.length > 0, dim: connections.length === 0, children: connections.length === 0 ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.fgSubtle, children: "No MCP connections yet." }), _jsxs(Text, { color: colors.fgSubtle, children: ["Register a DSN to let skills query your DB. Press", " ", _jsx(Text, { color: colors.accent, bold: true, children: "a" }), " ", "to start."] })] })) : (connections.map((c, i) => (_jsx(ListRow, { icon: icons.diamond, iconActive: true, title: c.nombre, subtitle: `${c.server_name} · ${c.dsn_var}`, state: { label: "registered", tone: "ok" }, chevron: true, active: i === cursor }, c.nombre)))) })) : null, mode.kind === "actions" && current ? (_jsx(Box, { flexDirection: "column", alignItems: "center", paddingY: 2, children: _jsx(Box, { width: "80%", flexDirection: "column", children: _jsx(ActionModal, { glyph: icons.diamond, title: current.nombre, subtitle: `${current.dsn_var} · ${current.server_name}`, state: { label: "registered", tone: "ok" }, actions: modalActions, cursor: actionCursor, footerRight: current.nombre }) }) })) : null, mode.kind === "wizard-name" ? (_jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsxs(FrameBox, { title: mode.editingName
206
+ ? `edit MCP connection · ${mode.editingName}`
207
+ : "register MCP connection", accent: true, children: [_jsxs(Text, { color: colors.fgSubtle, children: ["Step 1/2 \u2014 connection alias (slug-kebab).", " ", mode.editingName ? `Current: ${mode.editingName}` : ""] }), _jsx(Box, { marginTop: 1, children: _jsx(InputPrompt, { message: "alias:", onSubmit: (value) => {
208
+ const trimmed = value.trim() || mode.editingName || "";
209
+ if (!trimmed) {
210
+ onToast?.({ tone: "err", title: "Empty alias" });
211
+ setMode({ kind: "list" });
212
+ return;
213
+ }
214
+ setMode({
215
+ kind: "wizard-dsn",
216
+ name: trimmed,
217
+ ...(mode.editingName ? { editingExisting: mode.editingName } : {}),
218
+ });
219
+ }, isActive: isActive }) }), _jsx(Text, { color: colors.fgSubtle, children: "esc cancel" })] }) })) : null, mode.kind === "wizard-dsn" ? (_jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsxs(FrameBox, { title: "register MCP connection \u00B7 step 2/2", accent: true, children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.fgSubtle, children: "alias \u00B7 " }), _jsx(Text, { color: colors.fgBright, bold: true, children: mode.name })] }), _jsx(Box, { marginTop: 1, children: _jsx(InputPrompt, { message: "DSN env var (UPPER_SNAKE_CASE):", onSubmit: (value) => {
220
+ const dsnVar = value.trim();
221
+ if (!dsnVar) {
222
+ onToast?.({ tone: "err", title: "Empty DSN var" });
223
+ setMode({ kind: "list" });
224
+ return;
225
+ }
226
+ void registerConnection(mode.name, dsnVar);
227
+ }, isActive: isActive }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.fgMoreSubtle, children: "PREVIEW \u00B7 profile.json" }), _jsx(Text, { color: colors.fgSubtle, children: "{" }), _jsx(Text, { color: colors.fgSubtle, children: ` "mcp-servers": {` }), _jsx(Text, { color: colors.fg, children: ` "${mode.name}": {` }), _jsx(Text, { color: colors.fg, children: ` "env": "<DSN env var>",` }), _jsx(Text, { color: colors.fg, children: ` "type": "stdio"` }), _jsx(Text, { color: colors.fg, children: " }" }), _jsx(Text, { color: colors.fgSubtle, children: " }" }), _jsx(Text, { color: colors.fgSubtle, children: "}" })] }), _jsx(Text, { color: colors.fgSubtle, children: "\u23CE register \u00B7 esc cancel" })] }) })) : null, mode.kind === "confirm-delete" ? (_jsx(Box, { marginTop: 1, children: _jsx(ConfirmModal, { tone: "danger", title: "Remove connection", body: [
228
+ `You are about to remove the connection '${mode.name}'.`,
229
+ "This action cannot be undone.",
230
+ ], confirmKey: "y", confirmLabel: `Yes, remove ${mode.name}`, cancelKey: "n / esc", cancelLabel: "Cancel" }) })) : null, mode.kind === "busy" ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.warning, children: [icons.spinner, " ", mode.label] }) })) : null] }));
196
231
  async function registerConnection(name, dsnVar) {
197
- setMode({ kind: "busy", label: `registrando ${name}…` });
232
+ setMode({ kind: "busy", label: `registering ${name}…` });
198
233
  try {
199
234
  const result = await selfMcpConfig(buildArgs("use-env", { name, "dsn-var": dsnVar }), ctx);
200
235
  const summary = result.data?.summary ?? result.error?.message ?? "";
201
236
  onToast?.({
202
237
  tone: result.ok ? "ok" : "err",
203
- title: result.ok ? "Conexión registrada" : "Falló",
238
+ title: result.ok ? "Connection registered" : "Failed",
204
239
  body: summary,
205
240
  });
206
241
  await refresh();
@@ -213,53 +248,4 @@ export function McpTab({ ctx, isActive, onToast }) {
213
248
  }
214
249
  }
215
250
  }
216
- // ===== sub-components =====
217
- function McpSplitView({ connections, cursor, current, actionMode, actionCursor, }) {
218
- return (_jsxs(Box, { children: [_jsxs(Box, { flexDirection: "column", minWidth: 42, marginRight: 1, borderStyle: "round", borderColor: actionMode ? colors.borderFaint : colors.borderActive, paddingX: 1, children: [_jsx(Text, { color: colors.fgMoreSubtle, children: "CONEXIONES" }), connections.length === 0 ? (_jsx(Text, { color: colors.fgFaint, children: "(ninguna registrada \u2014 `n` para crear)" })) : (connections.map((c, i) => (_jsx(McpListRow, { conn: c, selected: i === cursor, dimmed: actionMode }, c.nombre))))] }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: actionMode ? colors.borderActive : colors.borderFaint, paddingX: 1, children: [_jsx(Text, { color: colors.fgMoreSubtle, children: "DETALLE" }), current ? (_jsx(McpDetail, { conn: current, actionMode: actionMode, actionCursor: actionCursor })) : (_jsx(Text, { color: colors.fgFaint, children: "(seleccion\u00E1 una)" }))] })] }));
219
- }
220
- function McpListRow({ conn, selected, dimmed, }) {
221
- // En actionMode (dimmed) la lista pierde foco — el cursor queda visible pero dim.
222
- const focused = selected && !dimmed;
223
- const cursorColor = focused ? colors.accent : colors.fgFaint;
224
- const nameColor = dimmed ? colors.fgSubtle : focused ? colors.fgBright : colors.fgSubtle;
225
- return (_jsxs(Box, { children: [_jsx(Text, { color: cursorColor, ...(focused ? { bold: true } : {}), children: selected ? "▸" : " " }), _jsx(Text, { children: " " }), _jsx(Box, { minWidth: 14, children: _jsx(Text, { color: nameColor, ...(focused ? { bold: true, inverse: true } : {}), children: focused ? ` ${conn.nombre} ` : conn.nombre }) }), _jsx(Box, { children: _jsx(Text, { color: colors.info, children: conn.dsn_var }) })] }));
226
- }
227
- function McpDetail({ conn, actionMode, actionCursor, }) {
228
- const driftAny = conn.instalado.claude_code === "drift" ||
229
- conn.instalado.codex === "drift" ||
230
- conn.instalado.warp === "drift";
231
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.fgBright, bold: true, children: conn.nombre }), driftAny ? (_jsx(Box, { marginLeft: 1, children: _jsx(Pill, { tone: "warn", children: "drift" }) })) : null] }), _jsxs(Text, { color: colors.fgMoreSubtle, children: ["DSN env var \u00B7 ", _jsx(Text, { color: colors.info, children: conn.dsn_var })] }), _jsxs(Text, { color: colors.fgMoreSubtle, children: ["server name \u00B7 ", _jsx(Text, { color: colors.info, children: conn.server_name })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(HostStatusLine, { id: "claude", status: conn.instalado.claude_code }), _jsx(HostStatusLine, { id: "codex", status: conn.instalado.codex }), _jsx(HostStatusLine, { id: "warp", status: conn.instalado.warp })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: ACTIONS.map((a, i) => (_jsx(ActionRow, { label: a.label, danger: a.danger === true, active: actionMode && i === actionCursor }, a.id))) })] }));
232
- }
233
- const MCP_HOST_LABELS = {
234
- claude: "Claude Code",
235
- codex: "Codex",
236
- warp: "Warp Terminal",
237
- };
238
- function HostStatusLine({ id, status }) {
239
- const label = status === "si" ? "instalado" : status === "drift" ? "drift de config" : "no instalado";
240
- const icon = status === "si" ? icons.check : status === "drift" ? "!" : icons.cross;
241
- const tone = status === "si" ? colors.success : status === "drift" ? colors.warning : colors.fgFaint;
242
- const hostLabel = MCP_HOST_LABELS[id] ?? id;
243
- return (_jsxs(Box, { children: [_jsx(Text, { color: tone, bold: true, children: icon }), _jsx(Text, { children: " " }), _jsx(Text, { color: status === "si" ? colors.fgBright : colors.fgSubtle, children: hostLabel }), _jsx(Text, { color: colors.fgFaint, children: " \u00B7 " }), _jsx(Text, { color: tone, children: label })] }));
244
- }
245
- function ActionRow({ label, danger, active, }) {
246
- const cursorColor = active ? (danger ? colors.error : colors.accent) : colors.fgFaint;
247
- const labelColor = danger ? colors.error : active ? colors.fgBright : colors.fgSubtle;
248
- return (_jsxs(Box, { children: [_jsx(Text, { color: cursorColor, ...(active ? { bold: true } : {}), children: active ? "▸" : " " }), _jsx(Text, { children: " " }), _jsx(Text, { color: labelColor, ...(active ? { bold: true, inverse: true } : {}), children: active ? ` ${label} ` : label })] }));
249
- }
250
- function handleNav(key, total, setCursor) {
251
- if (key.upArrow) {
252
- setCursor((c) => Math.max(0, c - 1));
253
- return true;
254
- }
255
- if (key.downArrow) {
256
- setCursor((c) => (total === 0 ? 0 : Math.min(total - 1, c + 1)));
257
- return true;
258
- }
259
- return false;
260
- }
261
- function WarpHintPanel({ hint }) {
262
- const steps = hint.lines.slice(1);
263
- return (_jsxs(Box, { marginTop: 1, flexDirection: "column", borderStyle: "round", borderColor: colors.info, paddingX: 1, children: [_jsxs(Text, { color: colors.info, bold: true, children: [icons.bullet, " Para que Warp lo spawnee:"] }), steps.map((line, idx) => (_jsx(Text, { color: colors.fg, children: ` ${idx + 1}. ${line}` }, line))), _jsxs(Text, { color: colors.fgMoreSubtle, children: ["Doc: ", hint.doc_url] })] }));
264
- }
265
251
  //# sourceMappingURL=mcp-tab.js.map