@burdenoff/microfe-vibecontrols 2026.527.6 → 2026.527.7

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.
@@ -2,274 +2,303 @@ import { useTr as e } from "../../shared/hooks/useTr.js";
2
2
  import { agentAiGet as t, agentAiMutate as n } from "../../services/aiApi.js";
3
3
  import { validateAliasName as ee } from "./aliasReservedNames.js";
4
4
  import { useCallback as te, useEffect as ne, useState as r } from "react";
5
- import { Check as re, Loader2 as i, PackageOpen as ie, Pencil as a, Play as o, Plus as s, Terminal as ae, Trash2 as c, X as l } from "lucide-react";
6
- import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
5
+ import { Check as re, Loader2 as i, PackageOpen as ie, Pencil as ae, Play as a, Plus as o, Terminal as oe, Trash2 as s, X as c } from "lucide-react";
6
+ import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
7
7
  //#region src/components/aliases/AliasManager.tsx
8
- var p = /(?:^|[\s"'(:\[])404(?=$|[\s"',.):;\]])/, m = /(?:^|[\s"'(:\[])not_found(?=$|[\s"',.):;\]])/;
9
- function oe(e) {
8
+ var f = /(?:^|[\s"'(:\[])404(?=$|[\s"',.):;\]])/, p = /(?:^|[\s"'(:\[])not_found(?=$|[\s"',.):;\]])/;
9
+ function se(e) {
10
10
  if (!e) return !1;
11
11
  let t = e.toLowerCase();
12
- return !!(m.test(t) || p.test(t) || t.includes("not installed on the agent"));
12
+ return !!(p.test(t) || f.test(t) || t.includes("not installed on the agent"));
13
13
  }
14
- var h = 80;
15
- function se(e, t = h) {
14
+ var m = 80;
15
+ function ce(e, t = m) {
16
16
  return e ? e.length > t ? `${e.slice(0, t)}…` : e : "";
17
17
  }
18
- function g({ agent: p }) {
19
- let m = e(), h = `/api/profiles/${encodeURIComponent(p.profile ?? "default")}/agent/aliases`, [g, ce] = r([]), [le, _] = r(!0), [v, y] = r(null), [ue, b] = r(!1), [x, S] = r(""), [C, w] = r(""), [T, E] = r(""), [D, O] = r(!1), [k, A] = r(null), [de, j] = r(null), [M, N] = r(""), [P, F] = r(""), [I, L] = r(!1), [R, z] = r(null), [B, V] = r(""), [H, U] = r(null), [W, G] = r(!1), [K, q] = r(null), [J, Y] = r(null), [X, Z] = r(!1), Q = te(async () => {
20
- _(!0), y(null), b(!1);
18
+ function h({ agent: f }) {
19
+ let p = e(), m = `/api/profiles/${encodeURIComponent(f.profile ?? "default")}/agent/aliases`, [h, le] = r([]), [ue, de] = r(!0), [g, _] = r(null), [fe, v] = r(!1), [y, b] = r(""), [x, S] = r(""), [C, w] = r(""), [T, E] = r(""), [D, O] = r(!1), [k, A] = r(null), [pe, j] = r(null), [M, N] = r(""), [P, F] = r(""), [I, L] = r(""), [R, z] = r(!1), [B, V] = r(null), [H, U] = r(""), [W, G] = r(null), [K, q] = r(!1), [J, Y] = r(null), [X, Z] = r(null), [Q, me] = r(!1), $ = te(async () => {
20
+ de(!0), _(null), v(!1);
21
21
  try {
22
- let e = await t(p.id, h);
23
- ce(Array.isArray(e) ? e : e.aliases ?? e.items ?? []);
22
+ let e = await t(f.id, m);
23
+ le(Array.isArray(e) ? e : e.aliases ?? e.items ?? []);
24
24
  } catch (e) {
25
25
  let t = e instanceof Error ? e.message : String(e);
26
- oe(t) ? b(!0) : y(t);
26
+ se(t) ? v(!0) : _(t);
27
27
  } finally {
28
- _(!1);
28
+ de(!1);
29
29
  }
30
- }, [p.id, h]);
30
+ }, [f.id, m]);
31
31
  ne(() => {
32
- Q();
33
- }, [Q]);
34
- let fe = async () => {
32
+ $();
33
+ }, [$]);
34
+ let he = async () => {
35
35
  A(null);
36
- let e = ee(x.trim());
36
+ let e = ee(y.trim());
37
37
  if (e) {
38
38
  A(e);
39
39
  return;
40
40
  }
41
- if (!C.trim()) {
42
- A(m("aliases.commandRequired", "Command is required"));
41
+ if (!x.trim()) {
42
+ A(p("aliases.commandRequired", "Command is required"));
43
43
  return;
44
44
  }
45
45
  O(!0);
46
46
  try {
47
- await n(p.id, h, "POST", {
48
- name: x.trim(),
49
- command: C,
50
- description: T || void 0
51
- }), S(""), w(""), E(""), await Q();
47
+ await n(f.id, m, "POST", {
48
+ name: y.trim(),
49
+ command: x,
50
+ description: C || void 0,
51
+ cwd: T.trim() || void 0
52
+ }), b(""), S(""), w(""), E(""), await $();
52
53
  } catch (e) {
53
54
  A(e instanceof Error ? e.message : String(e));
54
55
  } finally {
55
56
  O(!1);
56
57
  }
57
- }, pe = (e) => {
58
- j(e.name), N(e.command), F(e.description ?? "");
59
- }, $ = () => {
60
- j(null), N(""), F("");
61
- }, me = async (e) => {
62
- L(!0);
58
+ }, ge = (e) => {
59
+ j(e.name), N(e.command), F(e.description ?? ""), L(e.cwd ?? "");
60
+ }, _e = () => {
61
+ j(null), N(""), F(""), L("");
62
+ }, ve = async (e) => {
63
+ z(!0);
63
64
  try {
64
- await n(p.id, `${h}/${encodeURIComponent(e.name)}`, "PUT", {
65
+ await n(f.id, `${m}/${encodeURIComponent(e.name)}`, "PUT", {
65
66
  command: M,
66
- description: P || void 0
67
- }), $(), await Q();
67
+ description: P || void 0,
68
+ cwd: I.trim()
69
+ }), _e(), await $();
68
70
  } catch (e) {
69
- y(e instanceof Error ? e.message : String(e));
71
+ _(e instanceof Error ? e.message : String(e));
70
72
  } finally {
71
- L(!1);
73
+ z(!1);
72
74
  }
73
- }, he = async () => {
74
- if (J) {
75
- Z(!0);
75
+ }, ye = async () => {
76
+ if (X) {
77
+ me(!0);
76
78
  try {
77
- await n(p.id, `${h}/${encodeURIComponent(J.name)}`, "DELETE"), Y(null), await Q();
79
+ await n(f.id, `${m}/${encodeURIComponent(X.name)}`, "DELETE"), Z(null), await $();
78
80
  } catch (e) {
79
- y(e instanceof Error ? e.message : String(e));
81
+ _(e instanceof Error ? e.message : String(e));
80
82
  } finally {
81
- Z(!1);
83
+ me(!1);
82
84
  }
83
85
  }
84
- }, ge = async () => {
85
- if (R) {
86
- G(!0), q(null), U(null);
86
+ }, be = async () => {
87
+ if (B) {
88
+ q(!0), Y(null), G(null);
87
89
  try {
88
- let e = B.split(/\s+/).filter(Boolean);
89
- U(await n(p.id, `${h}/${encodeURIComponent(R.name)}/execute`, "POST", { args: e }));
90
+ let e = H.split(/\s+/).filter(Boolean);
91
+ G(await n(f.id, `${m}/${encodeURIComponent(B.name)}/execute`, "POST", { args: e }));
90
92
  } catch (e) {
91
- q(e instanceof Error ? e.message : String(e));
93
+ Y(e instanceof Error ? e.message : String(e));
92
94
  } finally {
93
- G(!1);
95
+ q(!1);
94
96
  }
95
97
  }
96
98
  };
97
- return ue ? /* @__PURE__ */ f("div", {
99
+ return fe ? /* @__PURE__ */ d("div", {
98
100
  className: "rounded-lg border border-border-default bg-bg-surface p-8 text-center space-y-3",
99
101
  children: [
100
- /* @__PURE__ */ d(ie, { className: "w-8 h-8 mx-auto text-text-muted" }),
101
- /* @__PURE__ */ d("h3", {
102
+ /* @__PURE__ */ u(ie, { className: "w-8 h-8 mx-auto text-text-muted" }),
103
+ /* @__PURE__ */ u("h3", {
102
104
  className: "text-base font-medium text-text-primary",
103
- children: m("aliases.unavailableTitle", "Aliases not available on this agent")
105
+ children: p("aliases.unavailableTitle", "Aliases not available on this agent")
104
106
  }),
105
- /* @__PURE__ */ d("p", {
107
+ /* @__PURE__ */ u("p", {
106
108
  className: "text-sm text-text-secondary max-w-md mx-auto",
107
- children: m("aliases.unavailableBody", "This agent version doesn't support shell aliases. Upgrade the agent to the latest @vibecontrols/agent release to enable per-agent shell aliases.")
109
+ children: p("aliases.unavailableBody", "This agent version doesn't support shell aliases. Upgrade the agent to the latest @vibecontrols/agent release to enable per-agent shell aliases.")
108
110
  }),
109
- /* @__PURE__ */ d("button", {
111
+ /* @__PURE__ */ u("button", {
110
112
  type: "button",
111
- onClick: Q,
113
+ onClick: $,
112
114
  className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-text-secondary border border-border-default rounded-md hover:bg-bg-sunken transition-colors",
113
- children: m("aliases.retry", "Retry")
115
+ children: p("aliases.retry", "Retry")
114
116
  })
115
117
  ]
116
- }) : /* @__PURE__ */ f("div", {
118
+ }) : /* @__PURE__ */ d("div", {
117
119
  className: "space-y-4",
118
120
  children: [
119
- /* @__PURE__ */ f("div", {
121
+ /* @__PURE__ */ d("div", {
120
122
  className: "rounded-lg border border-border-default bg-bg-sunken p-4 space-y-3",
121
123
  children: [
122
- /* @__PURE__ */ f("h3", {
124
+ /* @__PURE__ */ d("h3", {
123
125
  className: "text-sm font-medium text-text-primary flex items-center gap-2",
124
- children: [/* @__PURE__ */ d(s, { className: "w-4 h-4" }), m("aliases.createTitle", "New alias")]
126
+ children: [/* @__PURE__ */ u(o, { className: "w-4 h-4" }), p("aliases.createTitle", "New alias")]
125
127
  }),
126
- /* @__PURE__ */ f("div", {
128
+ /* @__PURE__ */ d("div", {
127
129
  className: "grid grid-cols-1 sm:grid-cols-2 gap-3",
128
- children: [/* @__PURE__ */ d("input", {
130
+ children: [/* @__PURE__ */ u("input", {
129
131
  type: "text",
130
- value: x,
131
- onChange: (e) => S(e.target.value),
132
- placeholder: m("aliases.namePlaceholder", "Name (a-z, 0-9, _, -)"),
132
+ value: y,
133
+ onChange: (e) => b(e.target.value),
134
+ placeholder: p("aliases.namePlaceholder", "Name (a-z, 0-9, _, -)"),
133
135
  className: "px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono"
134
- }), /* @__PURE__ */ d("input", {
136
+ }), /* @__PURE__ */ u("input", {
135
137
  type: "text",
136
- value: T,
137
- onChange: (e) => E(e.target.value),
138
- placeholder: m("aliases.descriptionPlaceholder", "Description (optional)"),
138
+ value: C,
139
+ onChange: (e) => w(e.target.value),
140
+ placeholder: p("aliases.descriptionPlaceholder", "Description (optional)"),
139
141
  className: "px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg"
140
142
  })]
141
143
  }),
142
- /* @__PURE__ */ d("textarea", {
143
- value: C,
144
- onChange: (e) => w(e.target.value),
145
- placeholder: m("aliases.commandPlaceholder", "Command (e.g. git status)"),
144
+ /* @__PURE__ */ u("input", {
145
+ type: "text",
146
+ value: T,
147
+ onChange: (e) => E(e.target.value),
148
+ placeholder: p("aliases.cwdPlaceholder", "Working directory (optional, defaults to ~). Examples: ~/code/myrepo, /tmp, products/microfe"),
149
+ className: "w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono"
150
+ }),
151
+ /* @__PURE__ */ u("textarea", {
152
+ value: x,
153
+ onChange: (e) => S(e.target.value),
154
+ placeholder: p("aliases.commandPlaceholder", "Command (e.g. git status)"),
146
155
  rows: 3,
147
156
  className: "w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono"
148
157
  }),
149
- k && /* @__PURE__ */ d("div", {
158
+ k && /* @__PURE__ */ u("div", {
150
159
  className: "text-xs text-status-error-text",
151
160
  children: k
152
161
  }),
153
- /* @__PURE__ */ d("div", {
162
+ /* @__PURE__ */ u("div", {
154
163
  className: "flex justify-end",
155
- children: /* @__PURE__ */ f("button", {
156
- onClick: fe,
157
- disabled: D || !x.trim() || !C.trim(),
164
+ children: /* @__PURE__ */ d("button", {
165
+ onClick: he,
166
+ disabled: D || !y.trim() || !x.trim(),
158
167
  className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50",
159
- children: [D ? /* @__PURE__ */ d(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ d(s, { className: "w-4 h-4" }), m("aliases.create", "Create")]
168
+ children: [D ? /* @__PURE__ */ u(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ u(o, { className: "w-4 h-4" }), p("aliases.create", "Create")]
160
169
  })
161
170
  })
162
171
  ]
163
172
  }),
164
- /* @__PURE__ */ d("div", {
173
+ /* @__PURE__ */ u("div", {
165
174
  className: "rounded-lg border border-border-default overflow-hidden",
166
- children: le ? /* @__PURE__ */ d("div", {
175
+ children: ue ? /* @__PURE__ */ u("div", {
167
176
  className: "p-8 text-center text-text-secondary",
168
- children: /* @__PURE__ */ d(i, { className: "w-5 h-5 animate-spin mx-auto" })
169
- }) : v ? /* @__PURE__ */ d("div", {
177
+ children: /* @__PURE__ */ u(i, { className: "w-5 h-5 animate-spin mx-auto" })
178
+ }) : g ? /* @__PURE__ */ u("div", {
170
179
  className: "p-4 text-sm text-status-error-text",
171
- children: v
172
- }) : g.length === 0 ? /* @__PURE__ */ d("div", {
180
+ children: g
181
+ }) : h.length === 0 ? /* @__PURE__ */ u("div", {
173
182
  className: "p-8 text-center text-sm text-text-secondary",
174
- children: m("aliases.empty", "No aliases yet. Create one above.")
175
- }) : /* @__PURE__ */ f("table", {
183
+ children: p("aliases.empty", "No aliases yet. Create one above.")
184
+ }) : /* @__PURE__ */ d("table", {
176
185
  className: "w-full text-sm",
177
- children: [/* @__PURE__ */ d("thead", {
186
+ children: [/* @__PURE__ */ u("thead", {
178
187
  className: "bg-bg-sunken text-text-secondary",
179
- children: /* @__PURE__ */ f("tr", { children: [
180
- /* @__PURE__ */ d("th", {
188
+ children: /* @__PURE__ */ d("tr", { children: [
189
+ /* @__PURE__ */ u("th", {
190
+ className: "text-left px-3 py-2 font-medium",
191
+ children: p("aliases.colName", "Name")
192
+ }),
193
+ /* @__PURE__ */ u("th", {
181
194
  className: "text-left px-3 py-2 font-medium",
182
- children: m("aliases.colName", "Name")
195
+ children: p("aliases.colCommand", "Command")
183
196
  }),
184
- /* @__PURE__ */ d("th", {
197
+ /* @__PURE__ */ u("th", {
185
198
  className: "text-left px-3 py-2 font-medium",
186
- children: m("aliases.colCommand", "Command")
199
+ children: p("aliases.colDescription", "Description")
187
200
  }),
188
- /* @__PURE__ */ d("th", {
201
+ /* @__PURE__ */ u("th", {
189
202
  className: "text-left px-3 py-2 font-medium",
190
- children: m("aliases.colDescription", "Description")
203
+ children: p("aliases.colCwd", "Cwd")
191
204
  }),
192
- /* @__PURE__ */ d("th", {
205
+ /* @__PURE__ */ u("th", {
193
206
  className: "text-left px-3 py-2 font-medium",
194
- children: m("aliases.colUpdatedAt", "Updated")
207
+ children: p("aliases.colUpdatedAt", "Updated")
195
208
  }),
196
- /* @__PURE__ */ d("th", {
209
+ /* @__PURE__ */ u("th", {
197
210
  className: "text-right px-3 py-2 font-medium",
198
- children: m("aliases.colActions", "Actions")
211
+ children: p("aliases.colActions", "Actions")
199
212
  })
200
213
  ] })
201
- }), /* @__PURE__ */ d("tbody", { children: g.map((e) => {
202
- let t = de === e.name;
203
- return /* @__PURE__ */ f("tr", {
214
+ }), /* @__PURE__ */ u("tbody", { children: h.map((e) => {
215
+ let t = pe === e.name;
216
+ return /* @__PURE__ */ d("tr", {
204
217
  className: "border-t border-border-default",
205
218
  children: [
206
- /* @__PURE__ */ d("td", {
219
+ /* @__PURE__ */ u("td", {
207
220
  className: "px-3 py-2 font-mono text-text-primary align-top",
208
221
  children: e.name
209
222
  }),
210
- /* @__PURE__ */ d("td", {
223
+ /* @__PURE__ */ u("td", {
211
224
  className: "px-3 py-2 align-top",
212
- children: t ? /* @__PURE__ */ d("textarea", {
225
+ children: t ? /* @__PURE__ */ u("textarea", {
213
226
  value: M,
214
227
  onChange: (e) => N(e.target.value),
215
228
  rows: 2,
216
229
  className: "w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary font-mono"
217
- }) : /* @__PURE__ */ d("code", {
230
+ }) : /* @__PURE__ */ u("code", {
218
231
  className: "text-xs text-text-primary",
219
232
  title: e.command,
220
- children: se(e.command)
233
+ children: ce(e.command)
221
234
  })
222
235
  }),
223
- /* @__PURE__ */ d("td", {
236
+ /* @__PURE__ */ u("td", {
224
237
  className: "px-3 py-2 align-top",
225
- children: t ? /* @__PURE__ */ d("input", {
238
+ children: t ? /* @__PURE__ */ u("input", {
226
239
  value: P,
227
240
  onChange: (e) => F(e.target.value),
228
241
  className: "w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary"
229
- }) : /* @__PURE__ */ d("span", {
242
+ }) : /* @__PURE__ */ u("span", {
230
243
  className: "text-xs text-text-secondary",
231
244
  children: e.description ?? "—"
232
245
  })
233
246
  }),
234
- /* @__PURE__ */ d("td", {
247
+ /* @__PURE__ */ u("td", {
248
+ className: "px-3 py-2 align-top",
249
+ children: t ? /* @__PURE__ */ u("input", {
250
+ value: I,
251
+ onChange: (e) => L(e.target.value),
252
+ placeholder: "~",
253
+ className: "w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary font-mono"
254
+ }) : /* @__PURE__ */ u("code", {
255
+ className: "text-xs text-text-secondary",
256
+ title: e.cwd ? e.cwd : p("aliases.cwdDefaultTitle", "No cwd set — runs in $HOME (the user home directory)."),
257
+ children: e.cwd ?? /* @__PURE__ */ u("span", {
258
+ className: "italic text-text-placeholder",
259
+ children: "~"
260
+ })
261
+ })
262
+ }),
263
+ /* @__PURE__ */ u("td", {
235
264
  className: "px-3 py-2 text-xs text-text-secondary align-top",
236
265
  children: e.updatedAt ? new Date(e.updatedAt).toLocaleString() : "—"
237
266
  }),
238
- /* @__PURE__ */ d("td", {
267
+ /* @__PURE__ */ u("td", {
239
268
  className: "px-3 py-2 align-top",
240
- children: /* @__PURE__ */ d("div", {
269
+ children: /* @__PURE__ */ u("div", {
241
270
  className: "flex items-center justify-end gap-1",
242
- children: t ? /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("button", {
243
- onClick: () => void me(e),
244
- disabled: I,
271
+ children: t ? /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u("button", {
272
+ onClick: () => void ve(e),
273
+ disabled: R,
245
274
  className: "p-1.5 rounded hover:bg-bg-sunken text-status-success-text",
246
- title: m("aliases.save", "Save"),
247
- children: I ? /* @__PURE__ */ d(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ d(re, { className: "w-4 h-4" })
248
- }), /* @__PURE__ */ d("button", {
249
- onClick: $,
275
+ title: p("aliases.save", "Save"),
276
+ children: R ? /* @__PURE__ */ u(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ u(re, { className: "w-4 h-4" })
277
+ }), /* @__PURE__ */ u("button", {
278
+ onClick: _e,
250
279
  className: "p-1.5 rounded hover:bg-bg-sunken text-text-secondary",
251
- title: m("common.cancel", "Cancel"),
252
- children: /* @__PURE__ */ d(l, { className: "w-4 h-4" })
253
- })] }) : /* @__PURE__ */ f(u, { children: [
254
- /* @__PURE__ */ d("button", {
280
+ title: p("common.cancel", "Cancel"),
281
+ children: /* @__PURE__ */ u(c, { className: "w-4 h-4" })
282
+ })] }) : /* @__PURE__ */ d(l, { children: [
283
+ /* @__PURE__ */ u("button", {
255
284
  onClick: () => {
256
- z(e), V(""), U(null), q(null);
285
+ V(e), U(""), G(null), Y(null);
257
286
  },
258
287
  className: "p-1.5 rounded hover:bg-bg-sunken text-action-primary-bg",
259
- title: m("aliases.run", "Run"),
260
- children: /* @__PURE__ */ d(o, { className: "w-4 h-4" })
288
+ title: p("aliases.run", "Run"),
289
+ children: /* @__PURE__ */ u(a, { className: "w-4 h-4" })
261
290
  }),
262
- /* @__PURE__ */ d("button", {
263
- onClick: () => pe(e),
291
+ /* @__PURE__ */ u("button", {
292
+ onClick: () => ge(e),
264
293
  className: "p-1.5 rounded hover:bg-bg-sunken text-text-secondary",
265
- title: m("aliases.edit", "Edit"),
266
- children: /* @__PURE__ */ d(a, { className: "w-4 h-4" })
294
+ title: p("aliases.edit", "Edit"),
295
+ children: /* @__PURE__ */ u(ae, { className: "w-4 h-4" })
267
296
  }),
268
- /* @__PURE__ */ d("button", {
269
- onClick: () => Y(e),
297
+ /* @__PURE__ */ u("button", {
298
+ onClick: () => Z(e),
270
299
  className: "p-1.5 rounded hover:bg-bg-sunken text-status-error-text",
271
- title: m("aliases.delete", "Delete"),
272
- children: /* @__PURE__ */ d(c, { className: "w-4 h-4" })
300
+ title: p("aliases.delete", "Delete"),
301
+ children: /* @__PURE__ */ u(s, { className: "w-4 h-4" })
273
302
  })
274
303
  ] })
275
304
  })
@@ -279,125 +308,133 @@ function g({ agent: p }) {
279
308
  }) })]
280
309
  })
281
310
  }),
282
- R && /* @__PURE__ */ d("div", {
311
+ B && /* @__PURE__ */ u("div", {
283
312
  className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay",
284
- children: /* @__PURE__ */ f("div", {
313
+ children: /* @__PURE__ */ d("div", {
285
314
  className: "w-full max-w-2xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] flex flex-col",
286
315
  children: [
287
- /* @__PURE__ */ f("div", {
316
+ /* @__PURE__ */ d("div", {
288
317
  className: "flex items-center justify-between px-6 py-4 border-b border-border-default",
289
- children: [/* @__PURE__ */ f("h2", {
318
+ children: [/* @__PURE__ */ d("h2", {
290
319
  className: "text-lg font-semibold text-text-primary flex items-center gap-2",
291
320
  children: [
292
- /* @__PURE__ */ d(ae, { className: "w-5 h-5" }),
293
- m("aliases.runTitle", "Run alias"),
321
+ /* @__PURE__ */ u(oe, { className: "w-5 h-5" }),
322
+ p("aliases.runTitle", "Run alias"),
294
323
  ": ",
295
- /* @__PURE__ */ d("code", { children: R.name })
324
+ /* @__PURE__ */ u("code", { children: B.name })
296
325
  ]
297
- }), /* @__PURE__ */ d("button", {
298
- onClick: () => z(null),
326
+ }), /* @__PURE__ */ u("button", {
327
+ onClick: () => V(null),
299
328
  className: "p-1 rounded hover:bg-bg-sunken",
300
- children: /* @__PURE__ */ d(l, { className: "w-5 h-5 text-text-secondary" })
329
+ children: /* @__PURE__ */ u(c, { className: "w-5 h-5 text-text-secondary" })
301
330
  })]
302
331
  }),
303
- /* @__PURE__ */ f("div", {
332
+ /* @__PURE__ */ d("div", {
304
333
  className: "flex-1 overflow-y-auto p-6 space-y-3",
305
334
  children: [
306
- /* @__PURE__ */ f("div", {
335
+ /* @__PURE__ */ d("div", {
307
336
  className: "text-xs text-text-secondary font-mono break-all",
308
- children: ["$ ", R.command]
337
+ children: ["$ ", B.command]
309
338
  }),
310
- /* @__PURE__ */ d("input", {
339
+ /* @__PURE__ */ u("input", {
311
340
  type: "text",
312
- value: B,
313
- onChange: (e) => V(e.target.value),
314
- placeholder: m("aliases.argsPlaceholder", "Args (space-separated, optional)"),
341
+ value: H,
342
+ onChange: (e) => U(e.target.value),
343
+ placeholder: p("aliases.argsPlaceholder", "Args (space-separated, optional)"),
315
344
  className: "w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary font-mono"
316
345
  }),
317
- K && /* @__PURE__ */ d("div", {
346
+ J && /* @__PURE__ */ u("div", {
318
347
  className: "text-sm text-status-error-text",
319
- children: K
348
+ children: J
320
349
  }),
321
- H && /* @__PURE__ */ f("div", {
350
+ W && /* @__PURE__ */ d("div", {
322
351
  className: "space-y-2",
323
352
  children: [
324
- /* @__PURE__ */ f("div", {
325
- className: "text-xs text-text-secondary",
326
- children: [
327
- m("aliases.exitCode", "Exit code"),
353
+ /* @__PURE__ */ d("div", {
354
+ className: "flex flex-wrap gap-x-4 gap-y-1 text-xs text-text-secondary",
355
+ children: [/* @__PURE__ */ d("span", { children: [
356
+ p("aliases.exitCode", "Exit code"),
328
357
  ":",
329
358
  " ",
330
- /* @__PURE__ */ d("span", {
331
- className: H.exit_code === 0 ? "text-status-success-text font-mono" : "text-status-error-text font-mono",
332
- children: H.exit_code
359
+ /* @__PURE__ */ u("span", {
360
+ className: W.exit_code === 0 ? "text-status-success-text font-mono" : "text-status-error-text font-mono",
361
+ children: W.exit_code
333
362
  })
334
- ]
363
+ ] }), W.cwd && /* @__PURE__ */ d("span", { children: [
364
+ p("aliases.runCwd", "Cwd"),
365
+ ":",
366
+ " ",
367
+ /* @__PURE__ */ u("code", {
368
+ className: "font-mono text-text-primary",
369
+ children: W.cwd
370
+ })
371
+ ] })]
335
372
  }),
336
- H.stdout && /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("div", {
373
+ W.stdout && /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("div", {
337
374
  className: "text-xs text-text-secondary mb-1",
338
375
  children: "stdout"
339
- }), /* @__PURE__ */ d("pre", {
376
+ }), /* @__PURE__ */ u("pre", {
340
377
  className: "text-xs bg-bg-sunken p-3 rounded font-mono whitespace-pre-wrap break-all max-h-64 overflow-y-auto text-text-primary",
341
- children: H.stdout
378
+ children: W.stdout
342
379
  })] }),
343
- H.stderr && /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("div", {
380
+ W.stderr && /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("div", {
344
381
  className: "text-xs text-text-secondary mb-1",
345
382
  children: "stderr"
346
- }), /* @__PURE__ */ d("pre", {
383
+ }), /* @__PURE__ */ u("pre", {
347
384
  className: "text-xs bg-bg-sunken p-3 rounded font-mono whitespace-pre-wrap break-all max-h-64 overflow-y-auto text-status-error-text",
348
- children: H.stderr
385
+ children: W.stderr
349
386
  })] })
350
387
  ]
351
388
  })
352
389
  ]
353
390
  }),
354
- /* @__PURE__ */ f("div", {
391
+ /* @__PURE__ */ d("div", {
355
392
  className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-border-default bg-bg-sunken",
356
- children: [/* @__PURE__ */ d("button", {
357
- onClick: () => z(null),
393
+ children: [/* @__PURE__ */ u("button", {
394
+ onClick: () => V(null),
358
395
  className: "px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated",
359
- children: m("common.close", "Close")
360
- }), /* @__PURE__ */ f("button", {
361
- onClick: () => void ge(),
362
- disabled: W,
396
+ children: p("common.close", "Close")
397
+ }), /* @__PURE__ */ d("button", {
398
+ onClick: () => void be(),
399
+ disabled: K,
363
400
  className: "inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50",
364
- children: [W ? /* @__PURE__ */ d(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ d(o, { className: "w-4 h-4" }), m("aliases.run", "Run")]
401
+ children: [K ? /* @__PURE__ */ u(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ u(a, { className: "w-4 h-4" }), p("aliases.run", "Run")]
365
402
  })]
366
403
  })
367
404
  ]
368
405
  })
369
406
  }),
370
- J && /* @__PURE__ */ d("div", {
407
+ X && /* @__PURE__ */ u("div", {
371
408
  className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay",
372
- children: /* @__PURE__ */ f("div", {
409
+ children: /* @__PURE__ */ d("div", {
373
410
  className: "w-full max-w-md bg-bg-surface rounded-lg shadow-xl p-6 space-y-4",
374
411
  children: [
375
- /* @__PURE__ */ d("h2", {
412
+ /* @__PURE__ */ u("h2", {
376
413
  className: "text-lg font-semibold text-text-primary",
377
- children: m("aliases.deleteTitle", "Delete alias?")
414
+ children: p("aliases.deleteTitle", "Delete alias?")
378
415
  }),
379
- /* @__PURE__ */ f("p", {
416
+ /* @__PURE__ */ d("p", {
380
417
  className: "text-sm text-text-secondary",
381
418
  children: [
382
- m("aliases.deleteConfirm", "This permanently removes the alias from this profile."),
419
+ p("aliases.deleteConfirm", "This permanently removes the alias from this profile."),
383
420
  " ",
384
- /* @__PURE__ */ d("code", {
421
+ /* @__PURE__ */ u("code", {
385
422
  className: "font-mono text-text-primary",
386
- children: J.name
423
+ children: X.name
387
424
  })
388
425
  ]
389
426
  }),
390
- /* @__PURE__ */ f("div", {
427
+ /* @__PURE__ */ d("div", {
391
428
  className: "flex justify-end gap-3",
392
- children: [/* @__PURE__ */ d("button", {
393
- onClick: () => Y(null),
429
+ children: [/* @__PURE__ */ u("button", {
430
+ onClick: () => Z(null),
394
431
  className: "px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary hover:bg-bg-elevated",
395
- children: m("common.cancel", "Cancel")
396
- }), /* @__PURE__ */ f("button", {
397
- onClick: () => void he(),
398
- disabled: X,
432
+ children: p("common.cancel", "Cancel")
433
+ }), /* @__PURE__ */ d("button", {
434
+ onClick: () => void ye(),
435
+ disabled: Q,
399
436
  className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-status-error-text bg-status-error-bg rounded-md hover:opacity-80 disabled:opacity-50",
400
- children: [X ? /* @__PURE__ */ d(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ d(c, { className: "w-4 h-4" }), m("aliases.delete", "Delete")]
437
+ children: [Q ? /* @__PURE__ */ u(i, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ u(s, { className: "w-4 h-4" }), p("aliases.delete", "Delete")]
401
438
  })]
402
439
  })
403
440
  ]
@@ -407,6 +444,6 @@ function g({ agent: p }) {
407
444
  });
408
445
  }
409
446
  //#endregion
410
- export { g as AliasManager };
447
+ export { h as AliasManager };
411
448
 
412
449
  //# sourceMappingURL=AliasManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AliasManager.js","names":[],"sources":["../../../src/components/aliases/AliasManager.tsx"],"sourcesContent":["/**\n * AliasManager — per-agent CRUDL for shell aliases exposed by\n * vibecontrols-agent under `/api/agent/aliases/*` (mounted by the core\n * `agent` plugin's route module, not a standalone aliases plugin).\n *\n * Endpoints (proxied through wspace-vibecontrols-svc → agent):\n * GET /api/agent/aliases → { aliases: Alias[] }\n * GET /api/agent/aliases/:name → Alias\n * POST /api/agent/aliases → Alias\n * PUT /api/agent/aliases/:name → Alias\n * DELETE /api/agent/aliases/:name\n * POST /api/agent/aliases/:name/execute → { exit_code, stdout, stderr, duration_ms }\n */\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { Plus, Trash2, Play, Pencil, Check, X, Loader2, Terminal, PackageOpen } from 'lucide-react';\nimport { agentAiGet, agentAiMutate } from '@/services/aiApi';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { validateAliasName } from './aliasReservedNames';\n\n// Anchor 404 by surrounding punctuation, not `\\b404\\b` — `\\b` matches\n// `v1.2.404`. Same shape used for `not_found` below so we don't match\n// inside `user_not_found` / `config_not_found` etc.\n// Escape `[` for `u`/`v` Unicode-mode forward-compat.\n// eslint-disable-next-line no-useless-escape -- forward-compat for Unicode regex mode\nconst HTTP_404_PATTERN = /(?:^|[\\s\"'(:\\[])404(?=$|[\\s\"',.):;\\]])/;\n// eslint-disable-next-line no-useless-escape -- forward-compat for Unicode regex mode\nconst NOT_FOUND_TOKEN_PATTERN = /(?:^|[\\s\"'(:\\[])not_found(?=$|[\\s\"',.):;\\]])/;\nfunction isAliasesRouteUnavailable(msg: string): boolean {\n if (!msg) return false;\n const m = msg.toLowerCase();\n if (NOT_FOUND_TOKEN_PATTERN.test(m)) return true;\n if (HTTP_404_PATTERN.test(m)) return true;\n if (m.includes('not installed on the agent')) return true;\n return false;\n}\n\ninterface Alias {\n name: string;\n command: string;\n description?: string | null;\n updatedAt?: string | null;\n createdAt?: string | null;\n}\n\n// The agent's `GET /api/agent/aliases` returns `{ aliases: Alias[] }`.\n// We also tolerate `{ items: Alias[] }` and a bare array for forward-\n// compat with any future plugin shipment that returns the older shape.\ninterface AliasListResponse {\n aliases?: Alias[];\n items?: Alias[];\n}\n\ninterface AliasExecuteResult {\n exit_code: number;\n stdout: string;\n stderr: string;\n /**\n * Wall-clock milliseconds the child took to exit. Matches the\n * agent's `RunCapturedResult.duration_ms`. Not surfaced in the run\n * modal yet — declared so the type matches the documented response\n * shape and so a future UI can show it without a second TS pass.\n */\n duration_ms?: number;\n}\n\ninterface AliasManagerProps {\n agent: { id: string; profile?: string };\n}\n\nconst TRUNCATE = 80;\n\nfunction truncate(str: string, n = TRUNCATE): string {\n if (!str) return '';\n return str.length > n ? `${str.slice(0, n)}…` : str;\n}\n\nexport function AliasManager({ agent }: AliasManagerProps) {\n const tr = useTr();\n // Canonical agent URL hierarchy: agent → profile → plugin → routes.\n // Alias CRUDL is owned by the core `agent` plugin, mounted at\n // `/api/profiles/<profile>/agent/aliases/*`. No client-side rewrites —\n // every consumer constructs the canonical path inline so the URL the\n // agent sees is the URL the FE wrote.\n const profile = encodeURIComponent(agent.profile ?? 'default');\n const aliasesBase = `/api/profiles/${profile}/agent/aliases`;\n const [aliases, setAliases] = useState<Alias[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n // Distinguish \"this agent build doesn't have the alias routes\" from a\n // generic error so we can show a clean empty-state with an actionable\n // hint instead of a scary stack-trace fragment. [BOFF-2613/2616]\n const [routeUnavailable, setRouteUnavailable] = useState(false);\n\n // Add-new form\n const [newName, setNewName] = useState('');\n const [newCommand, setNewCommand] = useState('');\n const [newDescription, setNewDescription] = useState('');\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n\n // Edit row\n const [editingName, setEditingName] = useState<string | null>(null);\n const [editCommand, setEditCommand] = useState('');\n const [editDescription, setEditDescription] = useState('');\n const [savingEdit, setSavingEdit] = useState(false);\n\n // Run modal\n const [runTarget, setRunTarget] = useState<Alias | null>(null);\n const [runArgs, setRunArgs] = useState('');\n const [runResult, setRunResult] = useState<AliasExecuteResult | null>(null);\n const [runRunning, setRunRunning] = useState(false);\n const [runError, setRunError] = useState<string | null>(null);\n\n // Delete confirm\n const [deleteTarget, setDeleteTarget] = useState<Alias | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n setError(null);\n setRouteUnavailable(false);\n try {\n const data = await agentAiGet<AliasListResponse | Alias[]>(agent.id, aliasesBase);\n const items = Array.isArray(data) ? data : (data.aliases ?? data.items ?? []);\n setAliases(items);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (isAliasesRouteUnavailable(msg)) {\n // Alias routes missing on this agent (or upstream context-required\n // error that we treat the same way for this tab) — show empty-state\n // instead of a scary error banner. [BOFF-2613/2616]\n setRouteUnavailable(true);\n } else {\n setError(msg);\n }\n } finally {\n setLoading(false);\n }\n }, [agent.id, aliasesBase]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n // ── Create ────────────────────────────────────────────────────────\n const handleCreate = async () => {\n setCreateError(null);\n const nameErr = validateAliasName(newName.trim());\n if (nameErr) {\n setCreateError(nameErr);\n return;\n }\n if (!newCommand.trim()) {\n setCreateError(tr('aliases.commandRequired', 'Command is required'));\n return;\n }\n setCreating(true);\n try {\n await agentAiMutate(agent.id, aliasesBase, 'POST', {\n name: newName.trim(),\n command: newCommand,\n description: newDescription || undefined,\n });\n setNewName('');\n setNewCommand('');\n setNewDescription('');\n await refresh();\n } catch (e) {\n setCreateError(e instanceof Error ? e.message : String(e));\n } finally {\n setCreating(false);\n }\n };\n\n // ── Edit ──────────────────────────────────────────────────────────\n const startEdit = (alias: Alias) => {\n setEditingName(alias.name);\n setEditCommand(alias.command);\n setEditDescription(alias.description ?? '');\n };\n\n const cancelEdit = () => {\n setEditingName(null);\n setEditCommand('');\n setEditDescription('');\n };\n\n const saveEdit = async (alias: Alias) => {\n setSavingEdit(true);\n try {\n await agentAiMutate(agent.id, `${aliasesBase}/${encodeURIComponent(alias.name)}`, 'PUT', {\n command: editCommand,\n description: editDescription || undefined,\n });\n cancelEdit();\n await refresh();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setSavingEdit(false);\n }\n };\n\n // ── Delete ────────────────────────────────────────────────────────\n const confirmDelete = async () => {\n if (!deleteTarget) return;\n setDeleting(true);\n try {\n await agentAiMutate(\n agent.id,\n `${aliasesBase}/${encodeURIComponent(deleteTarget.name)}`,\n 'DELETE'\n );\n setDeleteTarget(null);\n await refresh();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setDeleting(false);\n }\n };\n\n // ── Run ───────────────────────────────────────────────────────────\n const runAlias = async () => {\n if (!runTarget) return;\n setRunRunning(true);\n setRunError(null);\n setRunResult(null);\n try {\n const args = runArgs.split(/\\s+/).filter(Boolean);\n const result = await agentAiMutate<AliasExecuteResult>(\n agent.id,\n `${aliasesBase}/${encodeURIComponent(runTarget.name)}/execute`,\n 'POST',\n { args }\n );\n setRunResult(result);\n } catch (e) {\n setRunError(e instanceof Error ? e.message : String(e));\n } finally {\n setRunRunning(false);\n }\n };\n\n if (routeUnavailable) {\n // Alias routes not present on this agent build. Show a clean,\n // actionable empty-state instead of the form + the raw error string.\n // [BOFF-2613/2616]\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-8 text-center space-y-3\">\n <PackageOpen className=\"w-8 h-8 mx-auto text-text-muted\" />\n <h3 className=\"text-base font-medium text-text-primary\">\n {tr('aliases.unavailableTitle', 'Aliases not available on this agent')}\n </h3>\n <p className=\"text-sm text-text-secondary max-w-md mx-auto\">\n {tr(\n 'aliases.unavailableBody',\n \"This agent version doesn't support shell aliases. Upgrade the agent to the latest @vibecontrols/agent release to enable per-agent shell aliases.\"\n )}\n </p>\n <button\n type=\"button\"\n onClick={refresh}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-text-secondary border border-border-default rounded-md hover:bg-bg-sunken transition-colors\"\n >\n {tr('aliases.retry', 'Retry')}\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Add new alias form */}\n <div className=\"rounded-lg border border-border-default bg-bg-sunken p-4 space-y-3\">\n <h3 className=\"text-sm font-medium text-text-primary flex items-center gap-2\">\n <Plus className=\"w-4 h-4\" />\n {tr('aliases.createTitle', 'New alias')}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n placeholder={tr('aliases.namePlaceholder', 'Name (a-z, 0-9, _, -)')}\n className=\"px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <input\n type=\"text\"\n value={newDescription}\n onChange={(e) => setNewDescription(e.target.value)}\n placeholder={tr('aliases.descriptionPlaceholder', 'Description (optional)')}\n className=\"px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n <textarea\n value={newCommand}\n onChange={(e) => setNewCommand(e.target.value)}\n placeholder={tr('aliases.commandPlaceholder', 'Command (e.g. git status)')}\n rows={3}\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n {createError && <div className=\"text-xs text-status-error-text\">{createError}</div>}\n <div className=\"flex justify-end\">\n <button\n onClick={handleCreate}\n disabled={creating || !newName.trim() || !newCommand.trim()}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creating ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Plus className=\"w-4 h-4\" />}\n {tr('aliases.create', 'Create')}\n </button>\n </div>\n </div>\n\n {/* List */}\n <div className=\"rounded-lg border border-border-default overflow-hidden\">\n {loading ? (\n <div className=\"p-8 text-center text-text-secondary\">\n <Loader2 className=\"w-5 h-5 animate-spin mx-auto\" />\n </div>\n ) : error ? (\n <div className=\"p-4 text-sm text-status-error-text\">{error}</div>\n ) : aliases.length === 0 ? (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n {tr('aliases.empty', 'No aliases yet. Create one above.')}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead className=\"bg-bg-sunken text-text-secondary\">\n <tr>\n <th className=\"text-left px-3 py-2 font-medium\">{tr('aliases.colName', 'Name')}</th>\n <th className=\"text-left px-3 py-2 font-medium\">\n {tr('aliases.colCommand', 'Command')}\n </th>\n <th className=\"text-left px-3 py-2 font-medium\">\n {tr('aliases.colDescription', 'Description')}\n </th>\n <th className=\"text-left px-3 py-2 font-medium\">\n {tr('aliases.colUpdatedAt', 'Updated')}\n </th>\n <th className=\"text-right px-3 py-2 font-medium\">\n {tr('aliases.colActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {aliases.map((alias) => {\n const isEditing = editingName === alias.name;\n return (\n <tr key={alias.name} className=\"border-t border-border-default\">\n <td className=\"px-3 py-2 font-mono text-text-primary align-top\">\n {alias.name}\n </td>\n <td className=\"px-3 py-2 align-top\">\n {isEditing ? (\n <textarea\n value={editCommand}\n onChange={(e) => setEditCommand(e.target.value)}\n rows={2}\n className=\"w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary font-mono\"\n />\n ) : (\n <code className=\"text-xs text-text-primary\" title={alias.command}>\n {truncate(alias.command)}\n </code>\n )}\n </td>\n <td className=\"px-3 py-2 align-top\">\n {isEditing ? (\n <input\n value={editDescription}\n onChange={(e) => setEditDescription(e.target.value)}\n className=\"w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary\"\n />\n ) : (\n <span className=\"text-xs text-text-secondary\">\n {alias.description ?? '—'}\n </span>\n )}\n </td>\n <td className=\"px-3 py-2 text-xs text-text-secondary align-top\">\n {alias.updatedAt ? new Date(alias.updatedAt).toLocaleString() : '—'}\n </td>\n <td className=\"px-3 py-2 align-top\">\n <div className=\"flex items-center justify-end gap-1\">\n {isEditing ? (\n <>\n <button\n onClick={() => void saveEdit(alias)}\n disabled={savingEdit}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-status-success-text\"\n title={tr('aliases.save', 'Save')}\n >\n {savingEdit ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Check className=\"w-4 h-4\" />\n )}\n </button>\n <button\n onClick={cancelEdit}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-text-secondary\"\n title={tr('common.cancel', 'Cancel')}\n >\n <X className=\"w-4 h-4\" />\n </button>\n </>\n ) : (\n <>\n <button\n onClick={() => {\n setRunTarget(alias);\n setRunArgs('');\n setRunResult(null);\n setRunError(null);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-action-primary-bg\"\n title={tr('aliases.run', 'Run')}\n >\n <Play className=\"w-4 h-4\" />\n </button>\n <button\n onClick={() => startEdit(alias)}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-text-secondary\"\n title={tr('aliases.edit', 'Edit')}\n >\n <Pencil className=\"w-4 h-4\" />\n </button>\n <button\n onClick={() => setDeleteTarget(alias)}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-status-error-text\"\n title={tr('aliases.delete', 'Delete')}\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </>\n )}\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n )}\n </div>\n\n {/* Run modal */}\n {runTarget && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-2xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] flex flex-col\">\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"w-5 h-5\" />\n {tr('aliases.runTitle', 'Run alias')}: <code>{runTarget.name}</code>\n </h2>\n <button onClick={() => setRunTarget(null)} className=\"p-1 rounded hover:bg-bg-sunken\">\n <X className=\"w-5 h-5 text-text-secondary\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-y-auto p-6 space-y-3\">\n <div className=\"text-xs text-text-secondary font-mono break-all\">\n $ {runTarget.command}\n </div>\n <input\n type=\"text\"\n value={runArgs}\n onChange={(e) => setRunArgs(e.target.value)}\n placeholder={tr('aliases.argsPlaceholder', 'Args (space-separated, optional)')}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary font-mono\"\n />\n {runError && <div className=\"text-sm text-status-error-text\">{runError}</div>}\n {runResult && (\n <div className=\"space-y-2\">\n <div className=\"text-xs text-text-secondary\">\n {tr('aliases.exitCode', 'Exit code')}:{' '}\n <span\n className={\n runResult.exit_code === 0\n ? 'text-status-success-text font-mono'\n : 'text-status-error-text font-mono'\n }\n >\n {runResult.exit_code}\n </span>\n </div>\n {runResult.stdout && (\n <div>\n <div className=\"text-xs text-text-secondary mb-1\">stdout</div>\n <pre className=\"text-xs bg-bg-sunken p-3 rounded font-mono whitespace-pre-wrap break-all max-h-64 overflow-y-auto text-text-primary\">\n {runResult.stdout}\n </pre>\n </div>\n )}\n {runResult.stderr && (\n <div>\n <div className=\"text-xs text-text-secondary mb-1\">stderr</div>\n <pre className=\"text-xs bg-bg-sunken p-3 rounded font-mono whitespace-pre-wrap break-all max-h-64 overflow-y-auto text-status-error-text\">\n {runResult.stderr}\n </pre>\n </div>\n )}\n </div>\n )}\n </div>\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t border-border-default bg-bg-sunken\">\n <button\n onClick={() => setRunTarget(null)}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated\"\n >\n {tr('common.close', 'Close')}\n </button>\n <button\n onClick={() => void runAlias()}\n disabled={runRunning}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n {runRunning ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Play className=\"w-4 h-4\" />\n )}\n {tr('aliases.run', 'Run')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Delete confirm */}\n {deleteTarget && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-md bg-bg-surface rounded-lg shadow-xl p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('aliases.deleteTitle', 'Delete alias?')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr('aliases.deleteConfirm', 'This permanently removes the alias from this profile.')}{' '}\n <code className=\"font-mono text-text-primary\">{deleteTarget.name}</code>\n </p>\n <div className=\"flex justify-end gap-3\">\n <button\n onClick={() => setDeleteTarget(null)}\n className=\"px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary hover:bg-bg-elevated\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n onClick={() => void confirmDelete()}\n disabled={deleting}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-status-error-text bg-status-error-bg rounded-md hover:opacity-80 disabled:opacity-50\"\n >\n {deleting ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Trash2 className=\"w-4 h-4\" />\n )}\n {tr('aliases.delete', 'Delete')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAyBA,IAAM,IAAmB,0CAEnB,IAA0B;AAChC,SAAS,GAA0B,GAAsB;AACvD,KAAI,CAAC,EAAK,QAAO;CACjB,IAAM,IAAI,EAAI,aAAa;AAI3B,QADA,GAFI,EAAwB,KAAK,EAAE,IAC/B,EAAiB,KAAK,EAAE,IACxB,EAAE,SAAS,6BAA6B;;AAqC9C,IAAM,IAAW;AAEjB,SAAS,GAAS,GAAa,IAAI,GAAkB;AAEnD,QADK,IACE,EAAI,SAAS,IAAI,GAAG,EAAI,MAAM,GAAG,EAAE,CAAC,KAAK,IAD/B;;AAInB,SAAgB,EAAa,EAAE,YAA4B;CACzD,IAAM,IAAK,GAAO,EAOZ,IAAc,iBADJ,mBAAmB,EAAM,WAAW,UAAU,CACjB,iBACvC,CAAC,GAAS,MAAc,EAAkB,EAAE,CAAC,EAC7C,CAAC,IAAS,KAAc,EAAS,GAAK,EACtC,CAAC,GAAO,KAAY,EAAwB,KAAK,EAIjD,CAAC,IAAkB,KAAuB,EAAS,GAAM,EAGzD,CAAC,GAAS,KAAc,EAAS,GAAG,EACpC,CAAC,GAAY,KAAiB,EAAS,GAAG,EAC1C,CAAC,GAAgB,KAAqB,EAAS,GAAG,EAClD,CAAC,GAAU,KAAe,EAAS,GAAM,EACzC,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAG7D,CAAC,IAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAY,KAAiB,EAAS,GAAM,EAG7C,CAAC,GAAW,KAAgB,EAAuB,KAAK,EACxD,CAAC,GAAS,KAAc,EAAS,GAAG,EACpC,CAAC,GAAW,KAAgB,EAAoC,KAAK,EACrE,CAAC,GAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAU,KAAe,EAAwB,KAAK,EAGvD,CAAC,GAAc,KAAmB,EAAuB,KAAK,EAC9D,CAAC,GAAU,KAAe,EAAS,GAAM,EAEzC,IAAU,GAAY,YAAY;AAGtC,EAFA,EAAW,GAAK,EAChB,EAAS,KAAK,EACd,EAAoB,GAAM;AAC1B,MAAI;GACF,IAAM,IAAO,MAAM,EAAwC,EAAM,IAAI,EAAY;AAEjF,MADc,MAAM,QAAQ,EAAK,GAAG,IAAQ,EAAK,WAAW,EAAK,SAAS,EAAE,CAC3D;WACV,GAAG;GACV,IAAM,IAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,GAAI,GAA0B,EAAI,GAIhC,EAAoB,GAAK,GAEzB,EAAS,EAAI;YAEP;AACR,KAAW,GAAM;;IAElB,CAAC,EAAM,IAAI,EAAY,CAAC;AAE3B,UAAgB;AACT,KAAS;IACb,CAAC,EAAQ,CAAC;CAGb,IAAM,KAAe,YAAY;AAC/B,IAAe,KAAK;EACpB,IAAM,IAAU,GAAkB,EAAQ,MAAM,CAAC;AACjD,MAAI,GAAS;AACX,KAAe,EAAQ;AACvB;;AAEF,MAAI,CAAC,EAAW,MAAM,EAAE;AACtB,KAAe,EAAG,2BAA2B,sBAAsB,CAAC;AACpE;;AAEF,IAAY,GAAK;AACjB,MAAI;AASF,GARA,MAAM,EAAc,EAAM,IAAI,GAAa,QAAQ;IACjD,MAAM,EAAQ,MAAM;IACpB,SAAS;IACT,aAAa,KAAkB,KAAA;IAChC,CAAC,EACF,EAAW,GAAG,EACd,EAAc,GAAG,EACjB,EAAkB,GAAG,EACrB,MAAM,GAAS;WACR,GAAG;AACV,KAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAAC;YAClD;AACR,KAAY,GAAM;;IAKhB,MAAa,MAAiB;AAGlC,EAFA,EAAe,EAAM,KAAK,EAC1B,EAAe,EAAM,QAAQ,EAC7B,EAAmB,EAAM,eAAe,GAAG;IAGvC,UAAmB;AAGvB,EAFA,EAAe,KAAK,EACpB,EAAe,GAAG,EAClB,EAAmB,GAAG;IAGlB,KAAW,OAAO,MAAiB;AACvC,IAAc,GAAK;AACnB,MAAI;AAMF,GALA,MAAM,EAAc,EAAM,IAAI,GAAG,EAAY,GAAG,mBAAmB,EAAM,KAAK,IAAI,OAAO;IACvF,SAAS;IACT,aAAa,KAAmB,KAAA;IACjC,CAAC,EACF,GAAY,EACZ,MAAM,GAAS;WACR,GAAG;AACV,KAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAAC;YAC5C;AACR,KAAc,GAAM;;IAKlB,KAAgB,YAAY;AAC3B,SACL;KAAY,GAAK;AACjB,OAAI;AAOF,IANA,MAAM,EACJ,EAAM,IACN,GAAG,EAAY,GAAG,mBAAmB,EAAa,KAAK,IACvD,SACD,EACD,EAAgB,KAAK,EACrB,MAAM,GAAS;YACR,GAAG;AACV,MAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAAC;aAC5C;AACR,MAAY,GAAM;;;IAKhB,KAAW,YAAY;AACtB,SAGL;GAFA,EAAc,GAAK,EACnB,EAAY,KAAK,EACjB,EAAa,KAAK;AAClB,OAAI;IACF,IAAM,IAAO,EAAQ,MAAM,MAAM,CAAC,OAAO,QAAQ;AAOjD,MANe,MAAM,EACnB,EAAM,IACN,GAAG,EAAY,GAAG,mBAAmB,EAAU,KAAK,CAAC,WACrD,QACA,EAAE,SAAM,CACT,CACmB;YACb,GAAG;AACV,MAAY,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAAC;aAC/C;AACR,MAAc,GAAM;;;;AA+BxB,QA3BI,KAKA,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,IAAD,EAAa,WAAU,mCAAoC,CAAA;GAC3D,kBAAC,MAAD;IAAI,WAAU;cACX,EAAG,4BAA4B,sCAAsC;IACnE,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,2BACA,mJACD;IACC,CAAA;GACJ,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;cAET,EAAG,iBAAiB,QAAQ;IACtB,CAAA;GACL;MAKR,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,MAAD;MAAI,WAAU;gBAAd,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAG,uBAAuB,YAAY,CACpC;;KACL,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OACE,MAAK;OACL,OAAO;OACP,WAAW,MAAM,EAAW,EAAE,OAAO,MAAM;OAC3C,aAAa,EAAG,2BAA2B,wBAAwB;OACnE,WAAU;OACV,CAAA,EACF,kBAAC,SAAD;OACE,MAAK;OACL,OAAO;OACP,WAAW,MAAM,EAAkB,EAAE,OAAO,MAAM;OAClD,aAAa,EAAG,kCAAkC,yBAAyB;OAC3E,WAAU;OACV,CAAA,CACE;;KACN,kBAAC,YAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;MAC9C,aAAa,EAAG,8BAA8B,4BAA4B;MAC1E,MAAM;MACN,WAAU;MACV,CAAA;KACD,KAAe,kBAAC,OAAD;MAAK,WAAU;gBAAkC;MAAkB,CAAA;KACnF,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,UAAD;OACE,SAAS;OACT,UAAU,KAAY,CAAC,EAAQ,MAAM,IAAI,CAAC,EAAW,MAAM;OAC3D,WAAU;iBAHZ,CAKG,IAAW,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,GAAG,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EACtF,EAAG,kBAAkB,SAAS,CACxB;;MACL,CAAA;KACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cACZ,KACC,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAS,WAAU,gCAAiC,CAAA;KAChD,CAAA,GACJ,IACF,kBAAC,OAAD;KAAK,WAAU;eAAsC;KAAY,CAAA,GAC/D,EAAQ,WAAW,IACrB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAG,iBAAiB,oCAAoC;KACrD,CAAA,GAEN,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,SAAD;MAAO,WAAU;gBACf,kBAAC,MAAD,EAAA,UAAA;OACE,kBAAC,MAAD;QAAI,WAAU;kBAAmC,EAAG,mBAAmB,OAAO;QAAM,CAAA;OACpF,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,sBAAsB,UAAU;QACjC,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,0BAA0B,cAAc;QACzC,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,wBAAwB,UAAU;QACnC,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAG,sBAAsB,UAAU;QACjC,CAAA;OACF,EAAA,CAAA;MACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAQ,KAAK,MAAU;MACtB,IAAM,IAAY,OAAgB,EAAM;AACxC,aACE,kBAAC,MAAD;OAAqB,WAAU;iBAA/B;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAM;SACJ,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,IACC,kBAAC,YAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;UAC/C,MAAM;UACN,WAAU;UACV,CAAA,GAEF,kBAAC,QAAD;UAAM,WAAU;UAA4B,OAAO,EAAM;oBACtD,GAAS,EAAM,QAAQ;UACnB,CAAA;SAEN,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,IACC,kBAAC,SAAD;UACE,OAAO;UACP,WAAW,MAAM,EAAmB,EAAE,OAAO,MAAM;UACnD,WAAU;UACV,CAAA,GAEF,kBAAC,QAAD;UAAM,WAAU;oBACb,EAAM,eAAe;UACjB,CAAA;SAEN,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAM,YAAY,IAAI,KAAK,EAAM,UAAU,CAAC,gBAAgB,GAAG;SAC7D,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,OAAD;UAAK,WAAU;oBACZ,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,UAAD;WACE,eAAe,KAAK,GAAS,EAAM;WACnC,UAAU;WACV,WAAU;WACV,OAAO,EAAG,gBAAgB,OAAO;qBAEhC,IACC,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,GAE5C,kBAAC,IAAD,EAAO,WAAU,WAAY,CAAA;WAExB,CAAA,EACT,kBAAC,UAAD;WACE,SAAS;WACT,WAAU;WACV,OAAO,EAAG,iBAAiB,SAAS;qBAEpC,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;WAClB,CAAA,CACR,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA;WACE,kBAAC,UAAD;YACE,eAAe;AAIb,aAHA,EAAa,EAAM,EACnB,EAAW,GAAG,EACd,EAAa,KAAK,EAClB,EAAY,KAAK;;YAEnB,WAAU;YACV,OAAO,EAAG,eAAe,MAAM;sBAE/B,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;YACrB,CAAA;WACT,kBAAC,UAAD;YACE,eAAe,GAAU,EAAM;YAC/B,WAAU;YACV,OAAO,EAAG,gBAAgB,OAAO;sBAEjC,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;YACvB,CAAA;WACT,kBAAC,UAAD;YACE,eAAe,EAAgB,EAAM;YACrC,WAAU;YACV,OAAO,EAAG,kBAAkB,SAAS;sBAErC,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;YACvB,CAAA;WACR,EAAA,CAAA;UAED,CAAA;SACH,CAAA;QACF;SA1FI,EAAM,KA0FV;OAEP,EACI,CAAA,CACF;;IAEN,CAAA;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAd;SACE,kBAAC,IAAD,EAAU,WAAU,WAAY,CAAA;SAC/B,EAAG,oBAAoB,YAAY;SAAC;SAAE,kBAAC,QAAD,EAAA,UAAO,EAAU,MAAY,CAAA;SACjE;WACL,kBAAC,UAAD;QAAQ,eAAe,EAAa,KAAK;QAAE,WAAU;kBACnD,kBAAC,GAAD,EAAG,WAAU,+BAAgC,CAAA;QACtC,CAAA,CACL;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CAAiE,MAC5D,EAAU,QACT;;QACN,kBAAC,SAAD;SACE,MAAK;SACL,OAAO;SACP,WAAW,MAAM,EAAW,EAAE,OAAO,MAAM;SAC3C,aAAa,EAAG,2BAA2B,mCAAmC;SAC9E,WAAU;SACV,CAAA;QACD,KAAY,kBAAC,OAAD;SAAK,WAAU;mBAAkC;SAAe,CAAA;QAC5E,KACC,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf;YACG,EAAG,oBAAoB,YAAY;YAAC;YAAE;YACvC,kBAAC,QAAD;aACE,WACE,EAAU,cAAc,IACpB,uCACA;uBAGL,EAAU;aACN,CAAA;YACH;;UACL,EAAU,UACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAmC;WAAY,CAAA,EAC9D,kBAAC,OAAD;WAAK,WAAU;qBACZ,EAAU;WACP,CAAA,CACF,EAAA,CAAA;UAEP,EAAU,UACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAmC;WAAY,CAAA,EAC9D,kBAAC,OAAD;WAAK,WAAU;qBACZ,EAAU;WACP,CAAA,CACF,EAAA,CAAA;UAEJ;;QAEJ;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,eAAe,EAAa,KAAK;QACjC,WAAU;kBAET,EAAG,gBAAgB,QAAQ;QACrB,CAAA,EACT,kBAAC,UAAD;QACE,eAAe,KAAK,IAAU;QAC9B,UAAU;QACV,WAAU;kBAHZ,CAKG,IACC,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,GAE5C,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAE7B,EAAG,eAAe,MAAM,CAClB;UACL;;MACF;;IACF,CAAA;GAIP,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,uBAAuB,gBAAgB;OACxC,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBAAb;QACG,EAAG,yBAAyB,wDAAwD;QAAE;QACvF,kBAAC,QAAD;SAAM,WAAU;mBAA+B,EAAa;SAAY,CAAA;QACtE;;MACJ,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,eAAe,EAAgB,KAAK;QACpC,WAAU;kBAET,EAAG,iBAAiB,SAAS;QACvB,CAAA,EACT,kBAAC,UAAD;QACE,eAAe,KAAK,IAAe;QACnC,UAAU;QACV,WAAU;kBAHZ,CAKG,IACC,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,GAE5C,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAE/B,EAAG,kBAAkB,SAAS,CACxB;UACL;;MACF;;IACF,CAAA;GAEJ"}
1
+ {"version":3,"file":"AliasManager.js","names":[],"sources":["../../../src/components/aliases/AliasManager.tsx"],"sourcesContent":["/**\n * AliasManager — per-agent CRUDL for shell aliases exposed by\n * vibecontrols-agent under `/api/agent/aliases/*` (mounted by the core\n * `agent` plugin's route module, not a standalone aliases plugin).\n *\n * Endpoints (proxied through wspace-vibecontrols-svc → agent):\n * GET /api/agent/aliases → { aliases: Alias[] }\n * GET /api/agent/aliases/:name → Alias\n * POST /api/agent/aliases → Alias\n * PUT /api/agent/aliases/:name → Alias\n * DELETE /api/agent/aliases/:name\n * POST /api/agent/aliases/:name/execute → { exit_code, stdout, stderr, duration_ms }\n */\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { Plus, Trash2, Play, Pencil, Check, X, Loader2, Terminal, PackageOpen } from 'lucide-react';\nimport { agentAiGet, agentAiMutate } from '@/services/aiApi';\nimport { useTr } from '@/shared/hooks/useTr';\nimport { validateAliasName } from './aliasReservedNames';\n\n// Anchor 404 by surrounding punctuation, not `\\b404\\b` — `\\b` matches\n// `v1.2.404`. Same shape used for `not_found` below so we don't match\n// inside `user_not_found` / `config_not_found` etc.\n// Escape `[` for `u`/`v` Unicode-mode forward-compat.\n// eslint-disable-next-line no-useless-escape -- forward-compat for Unicode regex mode\nconst HTTP_404_PATTERN = /(?:^|[\\s\"'(:\\[])404(?=$|[\\s\"',.):;\\]])/;\n// eslint-disable-next-line no-useless-escape -- forward-compat for Unicode regex mode\nconst NOT_FOUND_TOKEN_PATTERN = /(?:^|[\\s\"'(:\\[])not_found(?=$|[\\s\"',.):;\\]])/;\nfunction isAliasesRouteUnavailable(msg: string): boolean {\n if (!msg) return false;\n const m = msg.toLowerCase();\n if (NOT_FOUND_TOKEN_PATTERN.test(m)) return true;\n if (HTTP_404_PATTERN.test(m)) return true;\n if (m.includes('not installed on the agent')) return true;\n return false;\n}\n\ninterface Alias {\n name: string;\n command: string;\n description?: string | null;\n /**\n * Per-alias working directory. The agent resolves `~/...` against\n * `$HOME` at execution time and falls back to `$HOME` when this is\n * null / undefined. Stored as the user typed it (portable across\n * hosts with different `$HOME`).\n */\n cwd?: string | null;\n updatedAt?: string | null;\n createdAt?: string | null;\n}\n\n// The agent's `GET /api/agent/aliases` returns `{ aliases: Alias[] }`.\n// We also tolerate `{ items: Alias[] }` and a bare array for forward-\n// compat with any future plugin shipment that returns the older shape.\ninterface AliasListResponse {\n aliases?: Alias[];\n items?: Alias[];\n}\n\ninterface AliasExecuteResult {\n exit_code: number;\n stdout: string;\n stderr: string;\n /**\n * Wall-clock milliseconds the child took to exit. Matches the\n * agent's `RunCapturedResult.duration_ms`. Not surfaced in the run\n * modal yet — declared so the type matches the documented response\n * shape and so a future UI can show it without a second TS pass.\n */\n duration_ms?: number;\n /**\n * Absolute path the command actually ran in (post `~`/HOME resolution).\n * Surfaced by the agent so the UI can show the user where the side\n * effects landed — particularly useful when the alias relied on the\n * `$HOME` default.\n */\n cwd?: string;\n}\n\ninterface AliasManagerProps {\n agent: { id: string; profile?: string };\n}\n\nconst TRUNCATE = 80;\n\nfunction truncate(str: string, n = TRUNCATE): string {\n if (!str) return '';\n return str.length > n ? `${str.slice(0, n)}…` : str;\n}\n\nexport function AliasManager({ agent }: AliasManagerProps) {\n const tr = useTr();\n // Canonical agent URL hierarchy: agent → profile → plugin → routes.\n // Alias CRUDL is owned by the core `agent` plugin, mounted at\n // `/api/profiles/<profile>/agent/aliases/*`. No client-side rewrites —\n // every consumer constructs the canonical path inline so the URL the\n // agent sees is the URL the FE wrote.\n const profile = encodeURIComponent(agent.profile ?? 'default');\n const aliasesBase = `/api/profiles/${profile}/agent/aliases`;\n const [aliases, setAliases] = useState<Alias[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n // Distinguish \"this agent build doesn't have the alias routes\" from a\n // generic error so we can show a clean empty-state with an actionable\n // hint instead of a scary stack-trace fragment. [BOFF-2613/2616]\n const [routeUnavailable, setRouteUnavailable] = useState(false);\n\n // Add-new form\n const [newName, setNewName] = useState('');\n const [newCommand, setNewCommand] = useState('');\n const [newDescription, setNewDescription] = useState('');\n const [newCwd, setNewCwd] = useState('');\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n\n // Edit row\n const [editingName, setEditingName] = useState<string | null>(null);\n const [editCommand, setEditCommand] = useState('');\n const [editDescription, setEditDescription] = useState('');\n const [editCwd, setEditCwd] = useState('');\n const [savingEdit, setSavingEdit] = useState(false);\n\n // Run modal\n const [runTarget, setRunTarget] = useState<Alias | null>(null);\n const [runArgs, setRunArgs] = useState('');\n const [runResult, setRunResult] = useState<AliasExecuteResult | null>(null);\n const [runRunning, setRunRunning] = useState(false);\n const [runError, setRunError] = useState<string | null>(null);\n\n // Delete confirm\n const [deleteTarget, setDeleteTarget] = useState<Alias | null>(null);\n const [deleting, setDeleting] = useState(false);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n setError(null);\n setRouteUnavailable(false);\n try {\n const data = await agentAiGet<AliasListResponse | Alias[]>(agent.id, aliasesBase);\n const items = Array.isArray(data) ? data : (data.aliases ?? data.items ?? []);\n setAliases(items);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (isAliasesRouteUnavailable(msg)) {\n // Alias routes missing on this agent (or upstream context-required\n // error that we treat the same way for this tab) — show empty-state\n // instead of a scary error banner. [BOFF-2613/2616]\n setRouteUnavailable(true);\n } else {\n setError(msg);\n }\n } finally {\n setLoading(false);\n }\n }, [agent.id, aliasesBase]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n // ── Create ────────────────────────────────────────────────────────\n const handleCreate = async () => {\n setCreateError(null);\n const nameErr = validateAliasName(newName.trim());\n if (nameErr) {\n setCreateError(nameErr);\n return;\n }\n if (!newCommand.trim()) {\n setCreateError(tr('aliases.commandRequired', 'Command is required'));\n return;\n }\n setCreating(true);\n try {\n await agentAiMutate(agent.id, aliasesBase, 'POST', {\n name: newName.trim(),\n command: newCommand,\n description: newDescription || undefined,\n // Pass the trimmed cwd verbatim — the agent normalizes empty\n // → null and defers `~/...` expansion to execution time so the\n // stored value remains portable across machines.\n cwd: newCwd.trim() || undefined,\n });\n setNewName('');\n setNewCommand('');\n setNewDescription('');\n setNewCwd('');\n await refresh();\n } catch (e) {\n setCreateError(e instanceof Error ? e.message : String(e));\n } finally {\n setCreating(false);\n }\n };\n\n // ── Edit ──────────────────────────────────────────────────────────\n const startEdit = (alias: Alias) => {\n setEditingName(alias.name);\n setEditCommand(alias.command);\n setEditDescription(alias.description ?? '');\n setEditCwd(alias.cwd ?? '');\n };\n\n const cancelEdit = () => {\n setEditingName(null);\n setEditCommand('');\n setEditDescription('');\n setEditCwd('');\n };\n\n const saveEdit = async (alias: Alias) => {\n setSavingEdit(true);\n try {\n // Always send `cwd` (including empty string) so users can reset\n // an alias back to the `$HOME` default by clearing the field.\n // The agent maps \"\" → null at the storage layer.\n await agentAiMutate(agent.id, `${aliasesBase}/${encodeURIComponent(alias.name)}`, 'PUT', {\n command: editCommand,\n description: editDescription || undefined,\n cwd: editCwd.trim(),\n });\n cancelEdit();\n await refresh();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setSavingEdit(false);\n }\n };\n\n // ── Delete ────────────────────────────────────────────────────────\n const confirmDelete = async () => {\n if (!deleteTarget) return;\n setDeleting(true);\n try {\n await agentAiMutate(\n agent.id,\n `${aliasesBase}/${encodeURIComponent(deleteTarget.name)}`,\n 'DELETE'\n );\n setDeleteTarget(null);\n await refresh();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setDeleting(false);\n }\n };\n\n // ── Run ───────────────────────────────────────────────────────────\n const runAlias = async () => {\n if (!runTarget) return;\n setRunRunning(true);\n setRunError(null);\n setRunResult(null);\n try {\n const args = runArgs.split(/\\s+/).filter(Boolean);\n const result = await agentAiMutate<AliasExecuteResult>(\n agent.id,\n `${aliasesBase}/${encodeURIComponent(runTarget.name)}/execute`,\n 'POST',\n { args }\n );\n setRunResult(result);\n } catch (e) {\n setRunError(e instanceof Error ? e.message : String(e));\n } finally {\n setRunRunning(false);\n }\n };\n\n if (routeUnavailable) {\n // Alias routes not present on this agent build. Show a clean,\n // actionable empty-state instead of the form + the raw error string.\n // [BOFF-2613/2616]\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-8 text-center space-y-3\">\n <PackageOpen className=\"w-8 h-8 mx-auto text-text-muted\" />\n <h3 className=\"text-base font-medium text-text-primary\">\n {tr('aliases.unavailableTitle', 'Aliases not available on this agent')}\n </h3>\n <p className=\"text-sm text-text-secondary max-w-md mx-auto\">\n {tr(\n 'aliases.unavailableBody',\n \"This agent version doesn't support shell aliases. Upgrade the agent to the latest @vibecontrols/agent release to enable per-agent shell aliases.\"\n )}\n </p>\n <button\n type=\"button\"\n onClick={refresh}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-text-secondary border border-border-default rounded-md hover:bg-bg-sunken transition-colors\"\n >\n {tr('aliases.retry', 'Retry')}\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4\">\n {/* Add new alias form */}\n <div className=\"rounded-lg border border-border-default bg-bg-sunken p-4 space-y-3\">\n <h3 className=\"text-sm font-medium text-text-primary flex items-center gap-2\">\n <Plus className=\"w-4 h-4\" />\n {tr('aliases.createTitle', 'New alias')}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n placeholder={tr('aliases.namePlaceholder', 'Name (a-z, 0-9, _, -)')}\n className=\"px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <input\n type=\"text\"\n value={newDescription}\n onChange={(e) => setNewDescription(e.target.value)}\n placeholder={tr('aliases.descriptionPlaceholder', 'Description (optional)')}\n className=\"px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg\"\n />\n </div>\n <input\n type=\"text\"\n value={newCwd}\n onChange={(e) => setNewCwd(e.target.value)}\n placeholder={tr(\n 'aliases.cwdPlaceholder',\n 'Working directory (optional, defaults to ~). Examples: ~/code/myrepo, /tmp, products/microfe'\n )}\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n <textarea\n value={newCommand}\n onChange={(e) => setNewCommand(e.target.value)}\n placeholder={tr('aliases.commandPlaceholder', 'Command (e.g. git status)')}\n rows={3}\n className=\"w-full px-3 py-2 text-sm bg-bg-surface border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-action-primary-bg font-mono\"\n />\n {createError && <div className=\"text-xs text-status-error-text\">{createError}</div>}\n <div className=\"flex justify-end\">\n <button\n onClick={handleCreate}\n disabled={creating || !newName.trim() || !newCommand.trim()}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creating ? <Loader2 className=\"w-4 h-4 animate-spin\" /> : <Plus className=\"w-4 h-4\" />}\n {tr('aliases.create', 'Create')}\n </button>\n </div>\n </div>\n\n {/* List */}\n <div className=\"rounded-lg border border-border-default overflow-hidden\">\n {loading ? (\n <div className=\"p-8 text-center text-text-secondary\">\n <Loader2 className=\"w-5 h-5 animate-spin mx-auto\" />\n </div>\n ) : error ? (\n <div className=\"p-4 text-sm text-status-error-text\">{error}</div>\n ) : aliases.length === 0 ? (\n <div className=\"p-8 text-center text-sm text-text-secondary\">\n {tr('aliases.empty', 'No aliases yet. Create one above.')}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead className=\"bg-bg-sunken text-text-secondary\">\n <tr>\n <th className=\"text-left px-3 py-2 font-medium\">{tr('aliases.colName', 'Name')}</th>\n <th className=\"text-left px-3 py-2 font-medium\">\n {tr('aliases.colCommand', 'Command')}\n </th>\n <th className=\"text-left px-3 py-2 font-medium\">\n {tr('aliases.colDescription', 'Description')}\n </th>\n <th className=\"text-left px-3 py-2 font-medium\">{tr('aliases.colCwd', 'Cwd')}</th>\n <th className=\"text-left px-3 py-2 font-medium\">\n {tr('aliases.colUpdatedAt', 'Updated')}\n </th>\n <th className=\"text-right px-3 py-2 font-medium\">\n {tr('aliases.colActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {aliases.map((alias) => {\n const isEditing = editingName === alias.name;\n return (\n <tr key={alias.name} className=\"border-t border-border-default\">\n <td className=\"px-3 py-2 font-mono text-text-primary align-top\">\n {alias.name}\n </td>\n <td className=\"px-3 py-2 align-top\">\n {isEditing ? (\n <textarea\n value={editCommand}\n onChange={(e) => setEditCommand(e.target.value)}\n rows={2}\n className=\"w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary font-mono\"\n />\n ) : (\n <code className=\"text-xs text-text-primary\" title={alias.command}>\n {truncate(alias.command)}\n </code>\n )}\n </td>\n <td className=\"px-3 py-2 align-top\">\n {isEditing ? (\n <input\n value={editDescription}\n onChange={(e) => setEditDescription(e.target.value)}\n className=\"w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary\"\n />\n ) : (\n <span className=\"text-xs text-text-secondary\">\n {alias.description ?? '—'}\n </span>\n )}\n </td>\n <td className=\"px-3 py-2 align-top\">\n {isEditing ? (\n <input\n value={editCwd}\n onChange={(e) => setEditCwd(e.target.value)}\n placeholder=\"~\"\n className=\"w-full px-2 py-1 text-xs bg-bg-surface border border-border-default rounded text-text-primary font-mono\"\n />\n ) : (\n <code\n className=\"text-xs text-text-secondary\"\n // Italicize the default fallback so users can tell\n // at a glance which aliases have an explicit cwd\n // vs. those riding the `$HOME` default.\n title={\n alias.cwd\n ? alias.cwd\n : tr(\n 'aliases.cwdDefaultTitle',\n 'No cwd set — runs in $HOME (the user home directory).'\n )\n }\n >\n {alias.cwd ?? <span className=\"italic text-text-placeholder\">~</span>}\n </code>\n )}\n </td>\n <td className=\"px-3 py-2 text-xs text-text-secondary align-top\">\n {alias.updatedAt ? new Date(alias.updatedAt).toLocaleString() : '—'}\n </td>\n <td className=\"px-3 py-2 align-top\">\n <div className=\"flex items-center justify-end gap-1\">\n {isEditing ? (\n <>\n <button\n onClick={() => void saveEdit(alias)}\n disabled={savingEdit}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-status-success-text\"\n title={tr('aliases.save', 'Save')}\n >\n {savingEdit ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Check className=\"w-4 h-4\" />\n )}\n </button>\n <button\n onClick={cancelEdit}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-text-secondary\"\n title={tr('common.cancel', 'Cancel')}\n >\n <X className=\"w-4 h-4\" />\n </button>\n </>\n ) : (\n <>\n <button\n onClick={() => {\n setRunTarget(alias);\n setRunArgs('');\n setRunResult(null);\n setRunError(null);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-action-primary-bg\"\n title={tr('aliases.run', 'Run')}\n >\n <Play className=\"w-4 h-4\" />\n </button>\n <button\n onClick={() => startEdit(alias)}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-text-secondary\"\n title={tr('aliases.edit', 'Edit')}\n >\n <Pencil className=\"w-4 h-4\" />\n </button>\n <button\n onClick={() => setDeleteTarget(alias)}\n className=\"p-1.5 rounded hover:bg-bg-sunken text-status-error-text\"\n title={tr('aliases.delete', 'Delete')}\n >\n <Trash2 className=\"w-4 h-4\" />\n </button>\n </>\n )}\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n )}\n </div>\n\n {/* Run modal */}\n {runTarget && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-2xl bg-bg-surface rounded-lg shadow-xl max-h-[90vh] flex flex-col\">\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"w-5 h-5\" />\n {tr('aliases.runTitle', 'Run alias')}: <code>{runTarget.name}</code>\n </h2>\n <button onClick={() => setRunTarget(null)} className=\"p-1 rounded hover:bg-bg-sunken\">\n <X className=\"w-5 h-5 text-text-secondary\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-y-auto p-6 space-y-3\">\n <div className=\"text-xs text-text-secondary font-mono break-all\">\n $ {runTarget.command}\n </div>\n <input\n type=\"text\"\n value={runArgs}\n onChange={(e) => setRunArgs(e.target.value)}\n placeholder={tr('aliases.argsPlaceholder', 'Args (space-separated, optional)')}\n className=\"w-full px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary font-mono\"\n />\n {runError && <div className=\"text-sm text-status-error-text\">{runError}</div>}\n {runResult && (\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <span>\n {tr('aliases.exitCode', 'Exit code')}:{' '}\n <span\n className={\n runResult.exit_code === 0\n ? 'text-status-success-text font-mono'\n : 'text-status-error-text font-mono'\n }\n >\n {runResult.exit_code}\n </span>\n </span>\n {runResult.cwd && (\n <span>\n {tr('aliases.runCwd', 'Cwd')}:{' '}\n <code className=\"font-mono text-text-primary\">{runResult.cwd}</code>\n </span>\n )}\n </div>\n {runResult.stdout && (\n <div>\n <div className=\"text-xs text-text-secondary mb-1\">stdout</div>\n <pre className=\"text-xs bg-bg-sunken p-3 rounded font-mono whitespace-pre-wrap break-all max-h-64 overflow-y-auto text-text-primary\">\n {runResult.stdout}\n </pre>\n </div>\n )}\n {runResult.stderr && (\n <div>\n <div className=\"text-xs text-text-secondary mb-1\">stderr</div>\n <pre className=\"text-xs bg-bg-sunken p-3 rounded font-mono whitespace-pre-wrap break-all max-h-64 overflow-y-auto text-status-error-text\">\n {runResult.stderr}\n </pre>\n </div>\n )}\n </div>\n )}\n </div>\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t border-border-default bg-bg-sunken\">\n <button\n onClick={() => setRunTarget(null)}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated\"\n >\n {tr('common.close', 'Close')}\n </button>\n <button\n onClick={() => void runAlias()}\n disabled={runRunning}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover disabled:opacity-50\"\n >\n {runRunning ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Play className=\"w-4 h-4\" />\n )}\n {tr('aliases.run', 'Run')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Delete confirm */}\n {deleteTarget && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay\">\n <div className=\"w-full max-w-md bg-bg-surface rounded-lg shadow-xl p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('aliases.deleteTitle', 'Delete alias?')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr('aliases.deleteConfirm', 'This permanently removes the alias from this profile.')}{' '}\n <code className=\"font-mono text-text-primary\">{deleteTarget.name}</code>\n </p>\n <div className=\"flex justify-end gap-3\">\n <button\n onClick={() => setDeleteTarget(null)}\n className=\"px-3 py-1.5 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary hover:bg-bg-elevated\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n onClick={() => void confirmDelete()}\n disabled={deleting}\n className=\"inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-status-error-text bg-status-error-bg rounded-md hover:opacity-80 disabled:opacity-50\"\n >\n {deleting ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : (\n <Trash2 className=\"w-4 h-4\" />\n )}\n {tr('aliases.delete', 'Delete')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-vibecontrols",
3
- "version": "2026.527.6",
3
+ "version": "2026.527.7",
4
4
  "description": "VibeControls microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [