@polterware/polter 0.2.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +30 -4
- package/dist/{chunk-2B2UWOVQ.js → chunk-7MIUDIAI.js} +711 -46
- package/dist/index.js +2112 -566
- package/dist/mcp.js +394 -9
- package/package.json +1 -1
- /package/dist/{chunk-EB76TTZL.js → chunk-AGVTFYXU.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -3,37 +3,49 @@ import {
|
|
|
3
3
|
allCommands,
|
|
4
4
|
applyActions,
|
|
5
5
|
commandExists,
|
|
6
|
+
detectPkgManager,
|
|
6
7
|
executePipeline,
|
|
7
8
|
features,
|
|
8
9
|
findCommandByValue,
|
|
9
10
|
findNearestPackageRoot,
|
|
10
11
|
findPipelineByName,
|
|
12
|
+
findPolterYaml,
|
|
11
13
|
getAllPipelines,
|
|
12
14
|
getCommandById,
|
|
13
15
|
getCommandValue,
|
|
14
16
|
getCurrentStatus,
|
|
15
17
|
getFeatureById,
|
|
16
18
|
getFlagsForTool,
|
|
19
|
+
getMcpStatusInfo,
|
|
17
20
|
getOrCreateProjectConfig,
|
|
21
|
+
getProcessOutput,
|
|
18
22
|
getProjectConfigPath,
|
|
19
23
|
getToolInfo,
|
|
20
24
|
getToolLinkInfo,
|
|
25
|
+
installMcpServer,
|
|
26
|
+
installMcpServerSilent,
|
|
27
|
+
listProcesses,
|
|
28
|
+
mcpStatus,
|
|
21
29
|
parsePolterYaml,
|
|
22
30
|
planChanges,
|
|
31
|
+
removeMcpServer,
|
|
32
|
+
removeMcpServerSilent,
|
|
33
|
+
removeProcess,
|
|
23
34
|
resolveToolCommand,
|
|
24
35
|
runCommand,
|
|
25
36
|
runInteractiveCommand,
|
|
26
37
|
runSupabaseCommand,
|
|
27
38
|
savePipeline,
|
|
39
|
+
stopProcess,
|
|
28
40
|
writeProjectConfig
|
|
29
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-7MIUDIAI.js";
|
|
30
42
|
|
|
31
43
|
// src/index.tsx
|
|
32
|
-
import
|
|
44
|
+
import React27 from "react";
|
|
33
45
|
import { render } from "ink";
|
|
34
46
|
|
|
35
47
|
// src/app.tsx
|
|
36
|
-
import { Box as
|
|
48
|
+
import { Box as Box28, Text as Text32, useApp } from "ink";
|
|
37
49
|
|
|
38
50
|
// src/hooks/useNavigation.ts
|
|
39
51
|
import { useState, useCallback } from "react";
|
|
@@ -99,7 +111,7 @@ function useTerminalHeight() {
|
|
|
99
111
|
|
|
100
112
|
// src/components/GhostBanner.tsx
|
|
101
113
|
import React from "react";
|
|
102
|
-
import { Box, Text } from "ink";
|
|
114
|
+
import { Box, Text as Text2 } from "ink";
|
|
103
115
|
|
|
104
116
|
// src/theme.ts
|
|
105
117
|
import { createRequire } from "module";
|
|
@@ -175,56 +187,93 @@ var ghost = {
|
|
|
175
187
|
]
|
|
176
188
|
};
|
|
177
189
|
|
|
190
|
+
// src/components/ToolBadge.tsx
|
|
191
|
+
import { Text } from "ink";
|
|
192
|
+
import { jsx } from "react/jsx-runtime";
|
|
193
|
+
var toolColors = {
|
|
194
|
+
supabase: "#3ECF8E",
|
|
195
|
+
gh: "#58A6FF",
|
|
196
|
+
vercel: "#FFFFFF",
|
|
197
|
+
git: "#F05032",
|
|
198
|
+
pkg: "#CB3837"
|
|
199
|
+
};
|
|
200
|
+
var toolLabels = {
|
|
201
|
+
supabase: "supabase",
|
|
202
|
+
gh: "github",
|
|
203
|
+
vercel: "vercel",
|
|
204
|
+
git: "git",
|
|
205
|
+
pkg: "pkg"
|
|
206
|
+
};
|
|
207
|
+
function ToolBadge({ tool }) {
|
|
208
|
+
return /* @__PURE__ */ jsx(Text, { color: toolColors[tool], dimColor: true, children: toolLabels[tool] });
|
|
209
|
+
}
|
|
210
|
+
|
|
178
211
|
// src/components/GhostBanner.tsx
|
|
179
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
212
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
213
|
+
var McpBadge = React.memo(function McpBadge2() {
|
|
214
|
+
const info = getMcpStatusInfo();
|
|
215
|
+
const registered = info.scopes.some((s) => s.registered);
|
|
216
|
+
const color = registered ? "#3ECF8E" : "red";
|
|
217
|
+
return /* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: color, children: /* @__PURE__ */ jsxs(Text2, { color, dimColor: !registered, children: [
|
|
218
|
+
"mcp:",
|
|
219
|
+
registered ? "ok" : "x"
|
|
220
|
+
] }) });
|
|
221
|
+
});
|
|
180
222
|
var ToolStatusBadges = React.memo(function ToolStatusBadges2() {
|
|
181
223
|
const tools = ["supabase", "gh", "vercel"].map((id) => getToolLinkInfo(id));
|
|
182
|
-
return /* @__PURE__ */
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
color:
|
|
186
|
-
dimColor: !t.installed,
|
|
187
|
-
children: [
|
|
224
|
+
return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
|
|
225
|
+
tools.map((t) => {
|
|
226
|
+
const color = t.linked ? toolColors[t.id] : t.installed ? "yellow" : "red";
|
|
227
|
+
return /* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: color, children: /* @__PURE__ */ jsxs(Text2, { color, dimColor: !t.installed, children: [
|
|
188
228
|
t.id,
|
|
189
229
|
":",
|
|
190
230
|
t.linked ? "linked" : t.installed ? "ok" : "x"
|
|
191
|
-
]
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
|
|
231
|
+
] }) }, t.id);
|
|
232
|
+
}),
|
|
233
|
+
/* @__PURE__ */ jsx2(McpBadge, {})
|
|
234
|
+
] });
|
|
195
235
|
});
|
|
196
236
|
function GhostBanner({ width = 80, compact = false }) {
|
|
197
237
|
if (compact) {
|
|
198
238
|
if (width < 60) {
|
|
199
|
-
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
200
|
-
/* @__PURE__ */
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
239
|
+
return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: inkColors.accent, flexDirection: "column", alignItems: "flex-start", children: [
|
|
240
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, gap: 2, children: [
|
|
241
|
+
/* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, bold: true, children: "POLTER" }),
|
|
242
|
+
/* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
|
|
243
|
+
"v",
|
|
244
|
+
VERSION
|
|
245
|
+
] }),
|
|
246
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "alpha" })
|
|
205
247
|
] }),
|
|
206
|
-
/* @__PURE__ */
|
|
248
|
+
/* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, children: /* @__PURE__ */ jsx2(ToolStatusBadges, {}) })
|
|
207
249
|
] });
|
|
208
250
|
}
|
|
209
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap:
|
|
210
|
-
/* @__PURE__ */
|
|
211
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column",
|
|
212
|
-
/* @__PURE__ */
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
251
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", borderStyle: "round", borderColor: inkColors.accent, gap: 1, alignItems: "flex-start", children: [
|
|
252
|
+
/* @__PURE__ */ jsx2(Box, { flexDirection: "column", children: ghost.art.map((line, i) => /* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, children: line }, i)) }),
|
|
253
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "flex-start", children: [
|
|
254
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, gap: 2, children: [
|
|
255
|
+
/* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, bold: true, children: "POLTER" }),
|
|
256
|
+
/* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
|
|
257
|
+
"v",
|
|
258
|
+
VERSION
|
|
259
|
+
] }),
|
|
260
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "alpha" })
|
|
216
261
|
] }),
|
|
217
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, children: /* @__PURE__ */ jsx2(ToolStatusBadges, {}) })
|
|
218
263
|
] })
|
|
219
264
|
] });
|
|
220
265
|
}
|
|
221
266
|
if (width < 50) {
|
|
222
|
-
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
223
|
-
/* @__PURE__ */
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
267
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, borderStyle: "round", borderColor: inkColors.accent, flexDirection: "column", alignItems: "flex-start", children: [
|
|
268
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, gap: 2, children: [
|
|
269
|
+
/* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, bold: true, children: "POLTER" }),
|
|
270
|
+
/* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
|
|
271
|
+
"v",
|
|
272
|
+
VERSION
|
|
273
|
+
] }),
|
|
274
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "alpha" })
|
|
275
|
+
] }),
|
|
276
|
+
/* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, children: /* @__PURE__ */ jsx2(ToolStatusBadges, {}) })
|
|
228
277
|
] });
|
|
229
278
|
}
|
|
230
279
|
if (width < 80) {
|
|
@@ -232,76 +281,59 @@ function GhostBanner({ width = 80, compact = false }) {
|
|
|
232
281
|
Box,
|
|
233
282
|
{
|
|
234
283
|
flexDirection: "column",
|
|
235
|
-
|
|
284
|
+
alignItems: "flex-start",
|
|
285
|
+
borderStyle: "round",
|
|
236
286
|
borderColor: inkColors.accent,
|
|
237
|
-
paddingX: 1,
|
|
238
287
|
marginBottom: 1,
|
|
239
288
|
children: [
|
|
240
|
-
/* @__PURE__ */
|
|
241
|
-
|
|
242
|
-
{
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
),
|
|
249
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
250
|
-
"Version: ",
|
|
251
|
-
VERSION
|
|
289
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, gap: 2, children: [
|
|
290
|
+
/* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, bold: true, children: "POLTER" }),
|
|
291
|
+
/* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
|
|
292
|
+
"v",
|
|
293
|
+
VERSION
|
|
294
|
+
] }),
|
|
295
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "alpha" })
|
|
252
296
|
] }),
|
|
253
|
-
/* @__PURE__ */
|
|
297
|
+
/* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, children: /* @__PURE__ */ jsx2(ToolStatusBadges, {}) }),
|
|
298
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Project & infrastructure orchestrator" })
|
|
254
299
|
]
|
|
255
300
|
}
|
|
256
301
|
);
|
|
257
302
|
}
|
|
258
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", alignItems: "flex-start", gap:
|
|
259
|
-
/* @__PURE__ */
|
|
260
|
-
/* @__PURE__ */ jsxs(
|
|
261
|
-
Box,
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
children:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
color: inkColors.accentContrast,
|
|
273
|
-
bold: true,
|
|
274
|
-
children: " POLTER "
|
|
275
|
-
}
|
|
276
|
-
),
|
|
277
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
278
|
-
"Version: ",
|
|
279
|
-
VERSION
|
|
280
|
-
] }),
|
|
281
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Project & infrastructure orchestrator" })
|
|
282
|
-
]
|
|
283
|
-
}
|
|
284
|
-
)
|
|
303
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", alignItems: "flex-start", borderStyle: "round", borderColor: inkColors.accent, gap: 1, marginBottom: 1, children: [
|
|
304
|
+
/* @__PURE__ */ jsx2(Box, { flexDirection: "column", children: ghost.art.map((line, i) => /* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, children: line }, i)) }),
|
|
305
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "flex-start", children: [
|
|
306
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, gap: 2, children: [
|
|
307
|
+
/* @__PURE__ */ jsx2(Text2, { color: inkColors.accent, bold: true, children: "POLTER" }),
|
|
308
|
+
/* @__PURE__ */ jsxs(Text2, { dimColor: true, children: [
|
|
309
|
+
"v",
|
|
310
|
+
VERSION
|
|
311
|
+
] }),
|
|
312
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "alpha" })
|
|
313
|
+
] }),
|
|
314
|
+
/* @__PURE__ */ jsx2(Box, { borderStyle: "round", borderColor: inkColors.accent, paddingX: 1, children: /* @__PURE__ */ jsx2(ToolStatusBadges, {}) }),
|
|
315
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " Project & infrastructure orchestrator" })
|
|
316
|
+
] })
|
|
285
317
|
] });
|
|
286
318
|
}
|
|
287
319
|
|
|
288
320
|
// src/screens/Home.tsx
|
|
289
321
|
import { useEffect as useEffect3, useMemo as useMemo2, useState as useState4 } from "react";
|
|
290
|
-
import { Box as Box5, Text as
|
|
322
|
+
import { Box as Box5, Text as Text6, useInput as useInput2 } from "ink";
|
|
291
323
|
|
|
292
324
|
// src/components/TabBar.tsx
|
|
293
|
-
import { Box as Box2, Text as
|
|
294
|
-
import { jsx as
|
|
325
|
+
import { Box as Box2, Text as Text3 } from "ink";
|
|
326
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
295
327
|
function TabBar({ tabs, activeIndex, width = 80 }) {
|
|
296
328
|
const narrow = width < 50;
|
|
297
329
|
const medium = width < 80;
|
|
298
|
-
return /* @__PURE__ */
|
|
330
|
+
return /* @__PURE__ */ jsx3(Box2, { gap: 1, children: tabs.map((tab, i) => {
|
|
299
331
|
const isActive = i === activeIndex;
|
|
300
332
|
const showLabel = narrow ? false : medium ? isActive : true;
|
|
301
333
|
const displayText = showLabel ? `${tab.icon} ${tab.label}` : tab.icon;
|
|
302
334
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
303
|
-
/* @__PURE__ */
|
|
304
|
-
|
|
335
|
+
/* @__PURE__ */ jsx3(
|
|
336
|
+
Text3,
|
|
305
337
|
{
|
|
306
338
|
color: isActive ? inkColors.accent : void 0,
|
|
307
339
|
bold: isActive,
|
|
@@ -309,14 +341,14 @@ function TabBar({ tabs, activeIndex, width = 80 }) {
|
|
|
309
341
|
children: displayText
|
|
310
342
|
}
|
|
311
343
|
),
|
|
312
|
-
isActive && !narrow && /* @__PURE__ */
|
|
344
|
+
isActive && !narrow && /* @__PURE__ */ jsx3(Text3, { color: inkColors.accent, children: "\u2550".repeat(displayText.length) })
|
|
313
345
|
] }, tab.id);
|
|
314
346
|
}) });
|
|
315
347
|
}
|
|
316
348
|
|
|
317
349
|
// src/components/SelectList.tsx
|
|
318
350
|
import { useEffect as useEffect2, useMemo, useState as useState3 } from "react";
|
|
319
|
-
import { Box as Box3, Text as
|
|
351
|
+
import { Box as Box3, Text as Text4, useInput } from "ink";
|
|
320
352
|
|
|
321
353
|
// src/components/selectListSections.ts
|
|
322
354
|
function isHeader(item) {
|
|
@@ -394,7 +426,7 @@ function countBoxedSectionLines(sections) {
|
|
|
394
426
|
}
|
|
395
427
|
|
|
396
428
|
// src/components/SelectList.tsx
|
|
397
|
-
import { jsx as
|
|
429
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
398
430
|
function SelectList({
|
|
399
431
|
items,
|
|
400
432
|
onSelect,
|
|
@@ -534,9 +566,9 @@ function SelectList({
|
|
|
534
566
|
const renderSelectableRow = (item, globalIdx) => {
|
|
535
567
|
const isSelected = globalIdx === selectedItemIndex;
|
|
536
568
|
return /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
|
|
537
|
-
/* @__PURE__ */
|
|
538
|
-
/* @__PURE__ */
|
|
539
|
-
|
|
569
|
+
/* @__PURE__ */ jsx4(Text4, { color: isSelected ? inkColors.accent : void 0, children: isSelected ? "\u276F" : " " }),
|
|
570
|
+
/* @__PURE__ */ jsx4(Box3, { width: labelWidth, children: /* @__PURE__ */ jsxs3(
|
|
571
|
+
Text4,
|
|
540
572
|
{
|
|
541
573
|
color: isSelected ? inkColors.accent : isPinnedRow(item) ? "white" : void 0,
|
|
542
574
|
bold: isSelected || isPinnedRow(item),
|
|
@@ -547,14 +579,14 @@ function SelectList({
|
|
|
547
579
|
]
|
|
548
580
|
}
|
|
549
581
|
) }),
|
|
550
|
-
!isNarrow && item.hint && /* @__PURE__ */
|
|
582
|
+
!isNarrow && item.hint && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: item.hint })
|
|
551
583
|
] }, item.id ?? `${item.value}-${globalIdx}`);
|
|
552
584
|
};
|
|
553
585
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
554
|
-
showScrollUp && /* @__PURE__ */
|
|
586
|
+
showScrollUp && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " \u2191 more" }),
|
|
555
587
|
boxedSections ? boxedLayout.map((section) => {
|
|
556
588
|
if (section.type === "heading") {
|
|
557
|
-
return /* @__PURE__ */
|
|
589
|
+
return /* @__PURE__ */ jsx4(Box3, { children: /* @__PURE__ */ jsx4(Text4, { color: inkColors.accent, bold: true, children: section.label }) }, section.key);
|
|
558
590
|
}
|
|
559
591
|
const hasSelectedRow = section.rows.some(
|
|
560
592
|
(row) => row.globalIndex === selectedItemIndex
|
|
@@ -571,8 +603,8 @@ function SelectList({
|
|
|
571
603
|
borderDimColor: !hasSelectedRow && !isPinnedSection,
|
|
572
604
|
paddingX: 1,
|
|
573
605
|
children: [
|
|
574
|
-
section.title && /* @__PURE__ */
|
|
575
|
-
/* @__PURE__ */
|
|
606
|
+
section.title && /* @__PURE__ */ jsx4(Text4, { color: inkColors.accent, bold: true, children: section.title }),
|
|
607
|
+
/* @__PURE__ */ jsx4(Box3, { flexDirection: "column", children: section.rows.map(
|
|
576
608
|
(row) => renderSelectableRow(row.item, row.globalIndex)
|
|
577
609
|
) })
|
|
578
610
|
]
|
|
@@ -583,28 +615,28 @@ function SelectList({
|
|
|
583
615
|
const globalIdx = windowStart + i;
|
|
584
616
|
const selectable = isSelectable(item);
|
|
585
617
|
if (!selectable) {
|
|
586
|
-
return /* @__PURE__ */
|
|
618
|
+
return /* @__PURE__ */ jsx4(
|
|
587
619
|
Box3,
|
|
588
620
|
{
|
|
589
621
|
marginTop: i === 0 ? 0 : 1,
|
|
590
|
-
children: /* @__PURE__ */
|
|
622
|
+
children: /* @__PURE__ */ jsx4(Text4, { color: inkColors.accent, bold: true, children: item.label })
|
|
591
623
|
},
|
|
592
624
|
item.id ?? `${item.value}-${globalIdx}`
|
|
593
625
|
);
|
|
594
626
|
}
|
|
595
627
|
return renderSelectableRow(item, globalIdx);
|
|
596
628
|
}),
|
|
597
|
-
showScrollDown && /* @__PURE__ */
|
|
629
|
+
showScrollDown && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: " \u2193 more" })
|
|
598
630
|
] });
|
|
599
631
|
}
|
|
600
632
|
|
|
601
633
|
// src/components/StatusBar.tsx
|
|
602
|
-
import { Box as Box4, Text as
|
|
603
|
-
import { jsx as
|
|
634
|
+
import { Box as Box4, Text as Text5 } from "ink";
|
|
635
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
604
636
|
function StatusBar({ hint, width = 80 }) {
|
|
605
637
|
return /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, justifyContent: "space-between", children: [
|
|
606
|
-
/* @__PURE__ */
|
|
607
|
-
width >= 60 && /* @__PURE__ */ jsxs4(
|
|
638
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: hint || "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc back" }),
|
|
639
|
+
width >= 60 && /* @__PURE__ */ jsxs4(Text5, { dimColor: true, children: [
|
|
608
640
|
"polter v",
|
|
609
641
|
VERSION
|
|
610
642
|
] })
|
|
@@ -673,13 +705,6 @@ function getFeatures() {
|
|
|
673
705
|
function buildPinnedOnlyItems(pinnedCommands, pinnedRuns) {
|
|
674
706
|
const items = [];
|
|
675
707
|
if (pinnedCommands.length > 0) {
|
|
676
|
-
items.push({
|
|
677
|
-
id: "pinned-commands-header",
|
|
678
|
-
value: "__pinned_commands_header__",
|
|
679
|
-
label: "\u{1F4CC} Commands",
|
|
680
|
-
kind: "header",
|
|
681
|
-
selectable: false
|
|
682
|
-
});
|
|
683
708
|
for (const command of pinnedCommands) {
|
|
684
709
|
const cmdDef = findCommandByValue(command);
|
|
685
710
|
const toolHint = cmdDef ? cmdDef.tool : "supabase";
|
|
@@ -687,7 +712,7 @@ function buildPinnedOnlyItems(pinnedCommands, pinnedRuns) {
|
|
|
687
712
|
items.push({
|
|
688
713
|
id: `command:${command}`,
|
|
689
714
|
value: command,
|
|
690
|
-
label: command,
|
|
715
|
+
label: cmdDef ? `${cmdDef.tool} ${command}` : command,
|
|
691
716
|
hint: [toolHint, labelHint].filter(Boolean).join(" \xB7 "),
|
|
692
717
|
icon: "\u{1F4CC}",
|
|
693
718
|
kind: "command",
|
|
@@ -697,13 +722,6 @@ function buildPinnedOnlyItems(pinnedCommands, pinnedRuns) {
|
|
|
697
722
|
}
|
|
698
723
|
}
|
|
699
724
|
if (pinnedRuns.length > 0) {
|
|
700
|
-
items.push({
|
|
701
|
-
id: "pinned-runs-header",
|
|
702
|
-
value: "__pinned_runs_header__",
|
|
703
|
-
label: "\u25B6 Pipelines",
|
|
704
|
-
kind: "header",
|
|
705
|
-
selectable: false
|
|
706
|
-
});
|
|
707
725
|
for (const runCommand2 of pinnedRuns) {
|
|
708
726
|
const baseCommand = runCommand2.split(" ").filter(Boolean)[0] ?? "";
|
|
709
727
|
const cmdDef = findCommandByValue(baseCommand);
|
|
@@ -711,7 +729,7 @@ function buildPinnedOnlyItems(pinnedCommands, pinnedRuns) {
|
|
|
711
729
|
items.push({
|
|
712
730
|
id: `run:${runCommand2}`,
|
|
713
731
|
value: runCommand2,
|
|
714
|
-
label: runCommand2,
|
|
732
|
+
label: cmdDef ? `${cmdDef.tool} ${runCommand2}` : runCommand2,
|
|
715
733
|
hint: toolHint,
|
|
716
734
|
icon: "\u25B6",
|
|
717
735
|
kind: "run",
|
|
@@ -785,11 +803,79 @@ function buildHomeItems({
|
|
|
785
803
|
});
|
|
786
804
|
}
|
|
787
805
|
}
|
|
806
|
+
items.push({
|
|
807
|
+
id: "section-system",
|
|
808
|
+
value: "__section_system__",
|
|
809
|
+
label: "\u2699\uFE0F System",
|
|
810
|
+
kind: "header",
|
|
811
|
+
selectable: false
|
|
812
|
+
});
|
|
813
|
+
items.push({
|
|
814
|
+
id: "action-declarative-plan",
|
|
815
|
+
value: "__action_declarative_plan__",
|
|
816
|
+
label: "Plan / Apply",
|
|
817
|
+
hint: "Declarative infrastructure",
|
|
818
|
+
kind: "action"
|
|
819
|
+
});
|
|
820
|
+
items.push({
|
|
821
|
+
id: "action-declarative-status",
|
|
822
|
+
value: "__action_declarative_status__",
|
|
823
|
+
label: "Infra Status",
|
|
824
|
+
hint: "Live state from CLI tools",
|
|
825
|
+
kind: "action"
|
|
826
|
+
});
|
|
827
|
+
items.push({
|
|
828
|
+
id: "action-init-scaffold",
|
|
829
|
+
value: "__action_init_scaffold__",
|
|
830
|
+
label: "Init polter.yaml",
|
|
831
|
+
hint: "Generate from detected state",
|
|
832
|
+
kind: "action"
|
|
833
|
+
});
|
|
834
|
+
items.push({
|
|
835
|
+
id: "action-pipelines",
|
|
836
|
+
value: "__action_pipelines__",
|
|
837
|
+
label: "Pipelines",
|
|
838
|
+
hint: "Multi-step workflows",
|
|
839
|
+
kind: "action"
|
|
840
|
+
});
|
|
841
|
+
items.push({
|
|
842
|
+
id: "action-tools",
|
|
843
|
+
value: "__action_tools__",
|
|
844
|
+
label: "Tool Status",
|
|
845
|
+
hint: "Check installed CLI tools",
|
|
846
|
+
kind: "action"
|
|
847
|
+
});
|
|
848
|
+
items.push({
|
|
849
|
+
id: "action-config",
|
|
850
|
+
value: "__action_config__",
|
|
851
|
+
label: "Project Config",
|
|
852
|
+
hint: "Tool refs and settings",
|
|
853
|
+
kind: "action"
|
|
854
|
+
});
|
|
855
|
+
items.push({
|
|
856
|
+
id: "action-custom",
|
|
857
|
+
value: "__action_custom__",
|
|
858
|
+
label: "Custom Command",
|
|
859
|
+
hint: "Free-form args",
|
|
860
|
+
kind: "action"
|
|
861
|
+
});
|
|
862
|
+
items.push({
|
|
863
|
+
id: "action-update",
|
|
864
|
+
value: "__action_update__",
|
|
865
|
+
label: "Update Polter",
|
|
866
|
+
kind: "action"
|
|
867
|
+
});
|
|
868
|
+
items.push({
|
|
869
|
+
id: "action-exit",
|
|
870
|
+
value: "__action_exit__",
|
|
871
|
+
label: "Exit",
|
|
872
|
+
kind: "action"
|
|
873
|
+
});
|
|
788
874
|
return items;
|
|
789
875
|
}
|
|
790
876
|
|
|
791
877
|
// src/screens/Home.tsx
|
|
792
|
-
import { jsx as
|
|
878
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
793
879
|
function Home({
|
|
794
880
|
onNavigate,
|
|
795
881
|
onExit,
|
|
@@ -890,6 +976,15 @@ function Home({
|
|
|
890
976
|
case "__action_update__":
|
|
891
977
|
onNavigate("self-update");
|
|
892
978
|
break;
|
|
979
|
+
case "__action_declarative_plan__":
|
|
980
|
+
onNavigate("declarative-plan");
|
|
981
|
+
break;
|
|
982
|
+
case "__action_declarative_status__":
|
|
983
|
+
onNavigate("declarative-status");
|
|
984
|
+
break;
|
|
985
|
+
case "__action_init_scaffold__":
|
|
986
|
+
onNavigate("init-scaffold");
|
|
987
|
+
break;
|
|
893
988
|
case "__action_exit__":
|
|
894
989
|
onExit();
|
|
895
990
|
break;
|
|
@@ -915,12 +1010,12 @@ function Home({
|
|
|
915
1010
|
}
|
|
916
1011
|
};
|
|
917
1012
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
918
|
-
/* @__PURE__ */
|
|
919
|
-
pinFeedback && /* @__PURE__ */
|
|
1013
|
+
/* @__PURE__ */ jsx6(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsx6(TabBar, { tabs, activeIndex: activeTabIndex, width }) }),
|
|
1014
|
+
pinFeedback && /* @__PURE__ */ jsx6(Box5, { marginBottom: 1, children: /* @__PURE__ */ jsxs5(Text6, { color: inkColors.accent, children: [
|
|
920
1015
|
"\u2713 ",
|
|
921
1016
|
pinFeedback
|
|
922
1017
|
] }) }),
|
|
923
|
-
/* @__PURE__ */
|
|
1018
|
+
/* @__PURE__ */ jsx6(
|
|
924
1019
|
SelectList,
|
|
925
1020
|
{
|
|
926
1021
|
items,
|
|
@@ -931,7 +1026,7 @@ function Home({
|
|
|
931
1026
|
maxVisible: Math.max(8, height - 14)
|
|
932
1027
|
}
|
|
933
1028
|
),
|
|
934
|
-
/* @__PURE__ */
|
|
1029
|
+
/* @__PURE__ */ jsx6(StatusBar, { hint: "\u2190\u2192 tab \xB7 \u2191\u2193 navigate \xB7 Enter select \xB7 p pin", width })
|
|
935
1030
|
] });
|
|
936
1031
|
}
|
|
937
1032
|
|
|
@@ -941,9 +1036,9 @@ import { Box as Box7, Text as Text8, useInput as useInput4 } from "ink";
|
|
|
941
1036
|
|
|
942
1037
|
// src/components/TextPrompt.tsx
|
|
943
1038
|
import { useState as useState5 } from "react";
|
|
944
|
-
import { Box as Box6, Text as
|
|
1039
|
+
import { Box as Box6, Text as Text7, useInput as useInput3 } from "ink";
|
|
945
1040
|
import TextInputComponent from "ink-text-input";
|
|
946
|
-
import { jsx as
|
|
1041
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
947
1042
|
function TextPrompt({
|
|
948
1043
|
label,
|
|
949
1044
|
placeholder,
|
|
@@ -964,6 +1059,9 @@ function TextPrompt({
|
|
|
964
1059
|
if (arrowNavigation && key.leftArrow && value === "" && onCancel) {
|
|
965
1060
|
onCancel();
|
|
966
1061
|
}
|
|
1062
|
+
if (arrowNavigation && key.rightArrow) {
|
|
1063
|
+
handleSubmit(value);
|
|
1064
|
+
}
|
|
967
1065
|
}, { isActive: isInputActive });
|
|
968
1066
|
const handleSubmit = (val) => {
|
|
969
1067
|
if (validate) {
|
|
@@ -978,12 +1076,12 @@ function TextPrompt({
|
|
|
978
1076
|
};
|
|
979
1077
|
const content = /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
980
1078
|
/* @__PURE__ */ jsxs6(Box6, { gap: 1, children: [
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
/* @__PURE__ */
|
|
1079
|
+
/* @__PURE__ */ jsx7(Text7, { color: inkColors.accent, bold: true, children: "?" }),
|
|
1080
|
+
/* @__PURE__ */ jsx7(Text7, { children: label })
|
|
983
1081
|
] }),
|
|
984
1082
|
/* @__PURE__ */ jsxs6(Box6, { gap: 1, marginLeft: 2, children: [
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ jsx7(Text7, { color: inkColors.accent, children: "\u276F" }),
|
|
1084
|
+
/* @__PURE__ */ jsx7(
|
|
987
1085
|
TextInputComponent,
|
|
988
1086
|
{
|
|
989
1087
|
value,
|
|
@@ -996,36 +1094,17 @@ function TextPrompt({
|
|
|
996
1094
|
}
|
|
997
1095
|
)
|
|
998
1096
|
] }),
|
|
999
|
-
error && /* @__PURE__ */
|
|
1097
|
+
error && /* @__PURE__ */ jsx7(Box6, { marginLeft: 2, children: /* @__PURE__ */ jsxs6(Text7, { color: "red", children: [
|
|
1000
1098
|
"\u2717 ",
|
|
1001
1099
|
error
|
|
1002
1100
|
] }) })
|
|
1003
1101
|
] });
|
|
1004
1102
|
if (boxed) {
|
|
1005
|
-
return /* @__PURE__ */
|
|
1103
|
+
return /* @__PURE__ */ jsx7(Box6, { borderStyle: "round", borderColor: focused ? inkColors.accent : panel.borderDim, paddingX: 1, children: content });
|
|
1006
1104
|
}
|
|
1007
1105
|
return content;
|
|
1008
1106
|
}
|
|
1009
1107
|
|
|
1010
|
-
// src/components/ToolBadge.tsx
|
|
1011
|
-
import { Text as Text7 } from "ink";
|
|
1012
|
-
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1013
|
-
var toolColors = {
|
|
1014
|
-
supabase: "#3ECF8E",
|
|
1015
|
-
gh: "#58A6FF",
|
|
1016
|
-
vercel: "#FFFFFF",
|
|
1017
|
-
git: "#F05032"
|
|
1018
|
-
};
|
|
1019
|
-
var toolLabels = {
|
|
1020
|
-
supabase: "supabase",
|
|
1021
|
-
gh: "github",
|
|
1022
|
-
vercel: "vercel",
|
|
1023
|
-
git: "git"
|
|
1024
|
-
};
|
|
1025
|
-
function ToolBadge({ tool }) {
|
|
1026
|
-
return /* @__PURE__ */ jsx7(Text7, { color: toolColors[tool], dimColor: true, children: toolLabels[tool] });
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
1108
|
// src/screens/commandArgsModel.ts
|
|
1030
1109
|
function buildRunCommand(command, extraArgs) {
|
|
1031
1110
|
return [command, ...extraArgs].join(" ");
|
|
@@ -1490,8 +1569,8 @@ function FlagSelection({
|
|
|
1490
1569
|
}
|
|
1491
1570
|
|
|
1492
1571
|
// src/screens/CommandExecution.tsx
|
|
1493
|
-
import { useState as useState11, useEffect as
|
|
1494
|
-
import { Box as Box13, Text as Text17 } from "ink";
|
|
1572
|
+
import { useState as useState11, useEffect as useEffect7 } from "react";
|
|
1573
|
+
import { Box as Box13, Text as Text17, useInput as useInput8 } from "ink";
|
|
1495
1574
|
|
|
1496
1575
|
// src/components/Spinner.tsx
|
|
1497
1576
|
import { Text as Text12 } from "ink";
|
|
@@ -1636,10 +1715,17 @@ function CommandOutput({
|
|
|
1636
1715
|
}
|
|
1637
1716
|
|
|
1638
1717
|
// src/hooks/useCommand.ts
|
|
1639
|
-
import { useState as useState10, useCallback as useCallback2 } from "react";
|
|
1718
|
+
import { useState as useState10, useCallback as useCallback2, useRef, useEffect as useEffect5 } from "react";
|
|
1640
1719
|
function useCommand(execution = "supabase", cwd = process.cwd(), options) {
|
|
1641
1720
|
const [status, setStatus] = useState10("idle");
|
|
1642
1721
|
const [result, setResult] = useState10(null);
|
|
1722
|
+
const abortRef = useRef(null);
|
|
1723
|
+
useEffect5(() => {
|
|
1724
|
+
return () => {
|
|
1725
|
+
abortRef.current?.();
|
|
1726
|
+
abortRef.current = null;
|
|
1727
|
+
};
|
|
1728
|
+
}, []);
|
|
1643
1729
|
const run = useCallback2(async (args) => {
|
|
1644
1730
|
setStatus("running");
|
|
1645
1731
|
setResult(null);
|
|
@@ -1656,7 +1742,10 @@ function useCommand(execution = "supabase", cwd = process.cwd(), options) {
|
|
|
1656
1742
|
resolvedExecution = execution;
|
|
1657
1743
|
}
|
|
1658
1744
|
const runOpts = options?.quiet ? { quiet: true } : void 0;
|
|
1659
|
-
const
|
|
1745
|
+
const handle = runCommand(resolvedExecution, args, cwd, runOpts);
|
|
1746
|
+
abortRef.current = handle.abort;
|
|
1747
|
+
const res = await handle.promise;
|
|
1748
|
+
abortRef.current = null;
|
|
1660
1749
|
setResult(res);
|
|
1661
1750
|
if (res.spawnError || res.exitCode !== null && res.exitCode !== 0) {
|
|
1662
1751
|
setStatus("error");
|
|
@@ -1665,24 +1754,28 @@ function useCommand(execution = "supabase", cwd = process.cwd(), options) {
|
|
|
1665
1754
|
}
|
|
1666
1755
|
return res;
|
|
1667
1756
|
}, [cwd, execution, options?.quiet]);
|
|
1757
|
+
const abort = useCallback2(() => {
|
|
1758
|
+
abortRef.current?.();
|
|
1759
|
+
abortRef.current = null;
|
|
1760
|
+
}, []);
|
|
1668
1761
|
const reset = useCallback2(() => {
|
|
1669
1762
|
setStatus("idle");
|
|
1670
1763
|
setResult(null);
|
|
1671
1764
|
}, []);
|
|
1672
|
-
return { status, result, run, reset };
|
|
1765
|
+
return { status, result, run, reset, abort };
|
|
1673
1766
|
}
|
|
1674
1767
|
|
|
1675
1768
|
// src/hooks/useInteractiveRun.ts
|
|
1676
1769
|
import { useCallback as useCallback3 } from "react";
|
|
1677
1770
|
|
|
1678
1771
|
// src/hooks/useFullscreen.ts
|
|
1679
|
-
import { useEffect as
|
|
1772
|
+
import { useEffect as useEffect6 } from "react";
|
|
1680
1773
|
var ENTER_ALT_SCREEN = "\x1B[?1049h";
|
|
1681
1774
|
var LEAVE_ALT_SCREEN = "\x1B[?1049l";
|
|
1682
1775
|
var HIDE_CURSOR = "\x1B[?25l";
|
|
1683
1776
|
var SHOW_CURSOR = "\x1B[?25h";
|
|
1684
1777
|
function useFullscreen() {
|
|
1685
|
-
|
|
1778
|
+
useEffect6(() => {
|
|
1686
1779
|
process.stdout.write(ENTER_ALT_SCREEN + HIDE_CURSOR);
|
|
1687
1780
|
return () => {
|
|
1688
1781
|
process.stdout.write(SHOW_CURSOR + LEAVE_ALT_SCREEN);
|
|
@@ -1800,13 +1893,35 @@ function CommandExecution({
|
|
|
1800
1893
|
const [phase, setPhase] = useState11("confirm");
|
|
1801
1894
|
const [currentArgs, setCurrentArgs] = useState11(initialArgs);
|
|
1802
1895
|
const [pinMessage, setPinMessage] = useState11();
|
|
1803
|
-
const { status, result, run, reset } = useCommand(tool, process.cwd(), {
|
|
1896
|
+
const { status, result, run, reset, abort } = useCommand(tool, process.cwd(), {
|
|
1804
1897
|
quiet: panelMode
|
|
1805
1898
|
});
|
|
1806
1899
|
const { runInteractive } = useInteractiveRun();
|
|
1900
|
+
const [outputFocused, setOutputFocused] = useState11(false);
|
|
1901
|
+
const [copyMessage, setCopyMessage] = useState11();
|
|
1807
1902
|
const cmdDisplay = `${tool} ${currentArgs.join(" ")}`;
|
|
1808
1903
|
const runCommand2 = currentArgs.join(" ");
|
|
1809
|
-
|
|
1904
|
+
useInput8(
|
|
1905
|
+
(_input, key) => {
|
|
1906
|
+
if (key.escape) {
|
|
1907
|
+
abort();
|
|
1908
|
+
onBack();
|
|
1909
|
+
}
|
|
1910
|
+
},
|
|
1911
|
+
{ isActive: isInputActive && phase === "running" }
|
|
1912
|
+
);
|
|
1913
|
+
useInput8(
|
|
1914
|
+
(input2, key) => {
|
|
1915
|
+
if (input2 === "o" && !outputFocused) {
|
|
1916
|
+
setOutputFocused(true);
|
|
1917
|
+
}
|
|
1918
|
+
if (key.escape && outputFocused) {
|
|
1919
|
+
setOutputFocused(false);
|
|
1920
|
+
}
|
|
1921
|
+
},
|
|
1922
|
+
{ isActive: isInputActive && phase === "error-menu" }
|
|
1923
|
+
);
|
|
1924
|
+
useEffect7(() => {
|
|
1810
1925
|
if (phase === "running" && status === "idle") {
|
|
1811
1926
|
if (panelMode && interactive) {
|
|
1812
1927
|
const interactiveResult = runInteractive(tool, currentArgs);
|
|
@@ -1820,7 +1935,7 @@ function CommandExecution({
|
|
|
1820
1935
|
}
|
|
1821
1936
|
}
|
|
1822
1937
|
}, [phase, status, run, currentArgs, panelMode, interactive, tool, runInteractive]);
|
|
1823
|
-
|
|
1938
|
+
useEffect7(() => {
|
|
1824
1939
|
if (phase === "running" && status === "success") {
|
|
1825
1940
|
if (isPinnedRun(runCommand2)) {
|
|
1826
1941
|
setPhase("success");
|
|
@@ -1833,6 +1948,16 @@ function CommandExecution({
|
|
|
1833
1948
|
}
|
|
1834
1949
|
}, [phase, runCommand2, status]);
|
|
1835
1950
|
if (phase === "confirm") {
|
|
1951
|
+
const pinned = isPinnedRun(runCommand2);
|
|
1952
|
+
const confirmItems = [
|
|
1953
|
+
{ value: "execute", label: "\u25B6 Execute command" },
|
|
1954
|
+
{
|
|
1955
|
+
value: "pin",
|
|
1956
|
+
label: pinned ? "\u{1F4CC} Unpin command" : "\u{1F4CC} Pin command",
|
|
1957
|
+
hint: "Save to quick access"
|
|
1958
|
+
},
|
|
1959
|
+
{ value: "cancel", label: "\u2190 Cancel" }
|
|
1960
|
+
];
|
|
1836
1961
|
const confirmContent = /* @__PURE__ */ jsxs15(Box13, { flexDirection: "column", children: [
|
|
1837
1962
|
/* @__PURE__ */ jsxs15(Box13, { marginBottom: 1, gap: 1, children: [
|
|
1838
1963
|
/* @__PURE__ */ jsxs15(Text17, { color: inkColors.accent, bold: true, children: [
|
|
@@ -1842,24 +1967,36 @@ function CommandExecution({
|
|
|
1842
1967
|
] }),
|
|
1843
1968
|
/* @__PURE__ */ jsx17(ToolBadge, { tool })
|
|
1844
1969
|
] }),
|
|
1970
|
+
pinMessage && /* @__PURE__ */ jsx17(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx17(Text17, { color: inkColors.accent, children: pinMessage }) }),
|
|
1845
1971
|
/* @__PURE__ */ jsx17(
|
|
1846
|
-
|
|
1972
|
+
SelectList,
|
|
1847
1973
|
{
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1974
|
+
items: confirmItems,
|
|
1975
|
+
onSelect: (action) => {
|
|
1976
|
+
switch (action) {
|
|
1977
|
+
case "execute":
|
|
1978
|
+
setPinMessage(void 0);
|
|
1979
|
+
setPhase("running");
|
|
1980
|
+
break;
|
|
1981
|
+
case "pin":
|
|
1982
|
+
togglePinnedRun(runCommand2);
|
|
1983
|
+
setPinMessage(
|
|
1984
|
+
isPinnedRun(runCommand2) ? "\u2713 Command pinned" : "\u2713 Command unpinned"
|
|
1985
|
+
);
|
|
1986
|
+
break;
|
|
1987
|
+
case "cancel":
|
|
1988
|
+
onBack();
|
|
1989
|
+
break;
|
|
1855
1990
|
}
|
|
1856
1991
|
},
|
|
1857
1992
|
onCancel: onBack,
|
|
1993
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
1858
1994
|
isInputActive,
|
|
1859
|
-
arrowNavigation: panelMode
|
|
1995
|
+
arrowNavigation: panelMode,
|
|
1996
|
+
boxedSections: panelMode,
|
|
1997
|
+
panelFocused: isInputActive
|
|
1860
1998
|
}
|
|
1861
|
-
)
|
|
1862
|
-
/* @__PURE__ */ jsx17(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Enter to execute \xB7 n to cancel" }) })
|
|
1999
|
+
)
|
|
1863
2000
|
] });
|
|
1864
2001
|
return /* @__PURE__ */ jsx17(Box13, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: panelMode ? /* @__PURE__ */ jsx17(
|
|
1865
2002
|
Box13,
|
|
@@ -1883,7 +2020,12 @@ function CommandExecution({
|
|
|
1883
2020
|
/* @__PURE__ */ jsx17(ToolBadge, { tool })
|
|
1884
2021
|
] }),
|
|
1885
2022
|
/* @__PURE__ */ jsx17(Divider, { width: panelMode ? width - 4 : width }),
|
|
1886
|
-
/* @__PURE__ */ jsx17(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx17(Spinner, { label: `Executing ${cmdDisplay}...` }) })
|
|
2023
|
+
/* @__PURE__ */ jsx17(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx17(Spinner, { label: `Executing ${cmdDisplay}...` }) }),
|
|
2024
|
+
/* @__PURE__ */ jsxs15(Box13, { marginTop: 1, children: [
|
|
2025
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "Press " }),
|
|
2026
|
+
/* @__PURE__ */ jsx17(Text17, { color: inkColors.accent, children: "Esc" }),
|
|
2027
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " to abort" })
|
|
2028
|
+
] })
|
|
1887
2029
|
] });
|
|
1888
2030
|
}
|
|
1889
2031
|
if (phase === "success-pin-offer") {
|
|
@@ -1994,6 +2136,15 @@ function CommandExecution({
|
|
|
1994
2136
|
value: "copy",
|
|
1995
2137
|
label: "\u{1F4CB} Copy command to clipboard"
|
|
1996
2138
|
});
|
|
2139
|
+
errorItems.push({
|
|
2140
|
+
value: "copy-output",
|
|
2141
|
+
label: "\u{1F4C4} Copy output to clipboard"
|
|
2142
|
+
});
|
|
2143
|
+
errorItems.push({
|
|
2144
|
+
value: "__nav_header__",
|
|
2145
|
+
label: "",
|
|
2146
|
+
kind: "header"
|
|
2147
|
+
});
|
|
1997
2148
|
errorItems.push({
|
|
1998
2149
|
value: "menu",
|
|
1999
2150
|
label: "\u2190 Back to menu"
|
|
@@ -2041,11 +2192,21 @@ function CommandExecution({
|
|
|
2041
2192
|
{
|
|
2042
2193
|
stdout: result?.stdout,
|
|
2043
2194
|
stderr: result?.stderr,
|
|
2044
|
-
height: Math.max(3, height -
|
|
2045
|
-
isActive:
|
|
2195
|
+
height: Math.max(3, height - 14 - errorItems.length - (suggestions.length > 0 ? suggestions.length + 4 : 0) - (copyMessage ? 1 : 0)),
|
|
2196
|
+
isActive: isInputActive && outputFocused
|
|
2046
2197
|
}
|
|
2047
2198
|
),
|
|
2048
|
-
/* @__PURE__ */ jsx17(Box13, { marginTop: 1,
|
|
2199
|
+
copyMessage && /* @__PURE__ */ jsx17(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx17(Text17, { color: inkColors.accent, children: copyMessage }) }),
|
|
2200
|
+
outputFocused ? /* @__PURE__ */ jsxs15(Box13, { marginTop: 1, children: [
|
|
2201
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "j/k scroll \xB7 " }),
|
|
2202
|
+
/* @__PURE__ */ jsx17(Text17, { color: inkColors.accent, children: "Esc" }),
|
|
2203
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " back to menu" })
|
|
2204
|
+
] }) : /* @__PURE__ */ jsxs15(Box13, { marginTop: 1, marginBottom: 1, children: [
|
|
2205
|
+
/* @__PURE__ */ jsx17(Text17, { bold: true, children: "What would you like to do?" }),
|
|
2206
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " (press " }),
|
|
2207
|
+
/* @__PURE__ */ jsx17(Text17, { color: inkColors.accent, children: "o" }),
|
|
2208
|
+
/* @__PURE__ */ jsx17(Text17, { dimColor: true, children: " to scroll output)" })
|
|
2209
|
+
] }),
|
|
2049
2210
|
/* @__PURE__ */ jsx17(
|
|
2050
2211
|
SelectList,
|
|
2051
2212
|
{
|
|
@@ -2069,6 +2230,7 @@ function CommandExecution({
|
|
|
2069
2230
|
switch (action) {
|
|
2070
2231
|
case "retry":
|
|
2071
2232
|
setPinMessage(void 0);
|
|
2233
|
+
setCopyMessage(void 0);
|
|
2072
2234
|
reset();
|
|
2073
2235
|
setPhase("running");
|
|
2074
2236
|
break;
|
|
@@ -2076,6 +2238,7 @@ function CommandExecution({
|
|
|
2076
2238
|
const newArgs = [...currentArgs, "--debug"];
|
|
2077
2239
|
setCurrentArgs(newArgs);
|
|
2078
2240
|
setPinMessage(void 0);
|
|
2241
|
+
setCopyMessage(void 0);
|
|
2079
2242
|
reset();
|
|
2080
2243
|
setPhase("running");
|
|
2081
2244
|
break;
|
|
@@ -2089,7 +2252,14 @@ function CommandExecution({
|
|
|
2089
2252
|
}
|
|
2090
2253
|
case "copy":
|
|
2091
2254
|
await copyToClipboard(cmdDisplay);
|
|
2255
|
+
setCopyMessage("\u2713 Command copied to clipboard");
|
|
2092
2256
|
break;
|
|
2257
|
+
case "copy-output": {
|
|
2258
|
+
const output2 = [result?.stdout, result?.stderr].filter(Boolean).join("\n");
|
|
2259
|
+
await copyToClipboard(output2);
|
|
2260
|
+
setCopyMessage("\u2713 Output copied to clipboard");
|
|
2261
|
+
break;
|
|
2262
|
+
}
|
|
2093
2263
|
case "menu":
|
|
2094
2264
|
(onHome ?? onBack)();
|
|
2095
2265
|
break;
|
|
@@ -2102,9 +2272,9 @@ function CommandExecution({
|
|
|
2102
2272
|
boxedSections: panelMode,
|
|
2103
2273
|
width: panelMode ? Math.max(20, width - 4) : width,
|
|
2104
2274
|
maxVisible: panelMode ? Math.max(errorItems.length + (suggestions.length > 0 ? 4 : 0), height - 6) : void 0,
|
|
2105
|
-
isInputActive,
|
|
2275
|
+
isInputActive: isInputActive && !outputFocused,
|
|
2106
2276
|
arrowNavigation: panelMode,
|
|
2107
|
-
panelFocused: isInputActive
|
|
2277
|
+
panelFocused: isInputActive && !outputFocused
|
|
2108
2278
|
}
|
|
2109
2279
|
),
|
|
2110
2280
|
!panelMode && /* @__PURE__ */ jsx17(StatusBar, { width })
|
|
@@ -2112,7 +2282,7 @@ function CommandExecution({
|
|
|
2112
2282
|
}
|
|
2113
2283
|
|
|
2114
2284
|
// src/screens/SelfUpdate.tsx
|
|
2115
|
-
import { useEffect as
|
|
2285
|
+
import { useEffect as useEffect8, useState as useState12 } from "react";
|
|
2116
2286
|
import { Box as Box14, Text as Text18 } from "ink";
|
|
2117
2287
|
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2118
2288
|
var packageName = "@polterware/polter";
|
|
@@ -2142,12 +2312,12 @@ function SelfUpdate({
|
|
|
2142
2312
|
const { status, result, run, reset } = useCommand("npm", updateCwd, {
|
|
2143
2313
|
quiet: panelMode
|
|
2144
2314
|
});
|
|
2145
|
-
|
|
2315
|
+
useEffect8(() => {
|
|
2146
2316
|
if (phase === "running" && status === "idle") {
|
|
2147
2317
|
run(updateArgs);
|
|
2148
2318
|
}
|
|
2149
2319
|
}, [phase, run, status, updateArgs]);
|
|
2150
|
-
|
|
2320
|
+
useEffect8(() => {
|
|
2151
2321
|
if (phase === "running" && status === "success") {
|
|
2152
2322
|
setPhase("success");
|
|
2153
2323
|
}
|
|
@@ -2388,13 +2558,33 @@ function SelfUpdate({
|
|
|
2388
2558
|
}
|
|
2389
2559
|
|
|
2390
2560
|
// src/screens/ToolStatus.tsx
|
|
2391
|
-
import {
|
|
2561
|
+
import { useEffect as useEffect9, useState as useState13 } from "react";
|
|
2392
2562
|
import { Box as Box15, Text as Text19 } from "ink";
|
|
2393
2563
|
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2394
|
-
var toolIds = ["supabase", "gh", "vercel", "git"];
|
|
2395
|
-
var linkableTools = /* @__PURE__ */ new Set(["supabase", "gh", "vercel"]);
|
|
2396
|
-
function ToolStatus({ onBack, width = 80, height = 24, panelMode = false, isInputActive = true }) {
|
|
2397
|
-
const tools =
|
|
2564
|
+
var toolIds = ["supabase", "gh", "vercel", "git", "pkg"];
|
|
2565
|
+
var linkableTools = /* @__PURE__ */ new Set(["supabase", "gh", "vercel", "pkg"]);
|
|
2566
|
+
function ToolStatus({ onBack, onNavigate, width = 80, height = 24, panelMode = false, isInputActive = true }) {
|
|
2567
|
+
const [tools, setTools] = useState13(null);
|
|
2568
|
+
const [mcpInfo, setMcpInfo] = useState13(null);
|
|
2569
|
+
useEffect9(() => {
|
|
2570
|
+
const t = setTimeout(() => {
|
|
2571
|
+
setTools(toolIds.map((id) => getToolLinkInfo(id)));
|
|
2572
|
+
setMcpInfo(getMcpStatusInfo());
|
|
2573
|
+
}, 0);
|
|
2574
|
+
return () => clearTimeout(t);
|
|
2575
|
+
}, []);
|
|
2576
|
+
if (!tools || !mcpInfo) {
|
|
2577
|
+
return /* @__PURE__ */ jsx19(Box15, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx19(Text19, { color: inkColors.accent, children: "Loading tool status..." }) });
|
|
2578
|
+
}
|
|
2579
|
+
const mcpRegistered = mcpInfo.scopes.some((s) => s.registered);
|
|
2580
|
+
const mcpScopeHint = mcpInfo.scopes.filter((s) => s.registered).map((s) => s.scope).join(", ");
|
|
2581
|
+
const handleSelect = (value) => {
|
|
2582
|
+
if (value === "mcp-manage" && onNavigate) {
|
|
2583
|
+
onNavigate("mcp-manage");
|
|
2584
|
+
} else if (value === "__back__") {
|
|
2585
|
+
onBack();
|
|
2586
|
+
}
|
|
2587
|
+
};
|
|
2398
2588
|
if (panelMode) {
|
|
2399
2589
|
const statusItems = [
|
|
2400
2590
|
{ value: "__section__", label: "Installed Tools", kind: "header", selectable: false },
|
|
@@ -2403,14 +2593,20 @@ function ToolStatus({ onBack, width = 80, height = 24, panelMode = false, isInpu
|
|
|
2403
2593
|
label: `${tool.installed ? "\u2713" : "\u2717"} ${tool.label}`,
|
|
2404
2594
|
hint: tool.installed ? `${tool.version ?? "installed"}${linkableTools.has(tool.id) ? tool.linked ? ` \u2192 ${tool.project ? `linked (${tool.project})` : "linked"}` : " \u2192 not linked" : ""}` : "not found",
|
|
2405
2595
|
kind: "action"
|
|
2406
|
-
}))
|
|
2596
|
+
})),
|
|
2597
|
+
{ value: "__mcp_section__", label: "MCP Server", kind: "header", selectable: false },
|
|
2598
|
+
{
|
|
2599
|
+
value: "mcp-manage",
|
|
2600
|
+
label: `${mcpRegistered ? "\u2713" : "\u2717"} polter-mcp`,
|
|
2601
|
+
hint: `v${mcpInfo.installedVersion}${mcpRegistered ? ` \u2192 ${mcpScopeHint}` : " \u2192 not registered"}`,
|
|
2602
|
+
kind: "action"
|
|
2603
|
+
}
|
|
2407
2604
|
];
|
|
2408
2605
|
return /* @__PURE__ */ jsx19(Box15, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx19(
|
|
2409
2606
|
SelectList,
|
|
2410
2607
|
{
|
|
2411
2608
|
items: statusItems,
|
|
2412
|
-
onSelect:
|
|
2413
|
-
},
|
|
2609
|
+
onSelect: handleSelect,
|
|
2414
2610
|
onCancel: onBack,
|
|
2415
2611
|
boxedSections: true,
|
|
2416
2612
|
width: Math.max(20, width - 4),
|
|
@@ -2422,32 +2618,45 @@ function ToolStatus({ onBack, width = 80, height = 24, panelMode = false, isInpu
|
|
|
2422
2618
|
) });
|
|
2423
2619
|
}
|
|
2424
2620
|
return /* @__PURE__ */ jsxs17(Box15, { flexDirection: "column", children: [
|
|
2425
|
-
/* @__PURE__ */ jsx19(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { bold: true, color: inkColors.accent, children: "
|
|
2621
|
+
/* @__PURE__ */ jsx19(Box15, { marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { bold: true, color: inkColors.accent, children: "Tool Status" }) }),
|
|
2426
2622
|
tools.map((tool) => /* @__PURE__ */ jsxs17(Box15, { gap: 1, marginLeft: 2, children: [
|
|
2427
2623
|
/* @__PURE__ */ jsx19(Text19, { color: tool.installed ? inkColors.accent : "red", children: tool.installed ? "\u2713" : "\u2717" }),
|
|
2428
2624
|
/* @__PURE__ */ jsx19(Box15, { width: 16, children: /* @__PURE__ */ jsx19(Text19, { bold: true, children: tool.label }) }),
|
|
2429
2625
|
/* @__PURE__ */ jsx19(Text19, { dimColor: true, children: tool.installed ? `${tool.version ?? "installed"}${linkableTools.has(tool.id) ? tool.linked ? ` \u2192 ${tool.project ?? "linked"}` : " \u2192 not linked" : ""}` : "not found" })
|
|
2430
2626
|
] }, tool.id)),
|
|
2627
|
+
/* @__PURE__ */ jsx19(Box15, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsx19(Text19, { bold: true, color: inkColors.accent, children: " MCP Server" }) }),
|
|
2628
|
+
/* @__PURE__ */ jsxs17(Box15, { gap: 1, marginLeft: 2, children: [
|
|
2629
|
+
/* @__PURE__ */ jsx19(Text19, { color: mcpRegistered ? inkColors.accent : "red", children: mcpRegistered ? "\u2713" : "\u2717" }),
|
|
2630
|
+
/* @__PURE__ */ jsx19(Box15, { width: 16, children: /* @__PURE__ */ jsx19(Text19, { bold: true, children: "polter-mcp" }) }),
|
|
2631
|
+
/* @__PURE__ */ jsxs17(Text19, { dimColor: true, children: [
|
|
2632
|
+
"v",
|
|
2633
|
+
mcpInfo.installedVersion,
|
|
2634
|
+
mcpRegistered ? ` \u2192 ${mcpScopeHint}` : " \u2192 not registered"
|
|
2635
|
+
] })
|
|
2636
|
+
] }),
|
|
2431
2637
|
/* @__PURE__ */ jsx19(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
2432
2638
|
SelectList,
|
|
2433
2639
|
{
|
|
2434
|
-
items: [
|
|
2435
|
-
|
|
2640
|
+
items: [
|
|
2641
|
+
{ value: "mcp-manage", label: "Manage MCP Server \u2192" },
|
|
2642
|
+
{ value: "__back__", label: "\u2190 Back" }
|
|
2643
|
+
],
|
|
2644
|
+
onSelect: handleSelect,
|
|
2436
2645
|
onCancel: onBack,
|
|
2437
2646
|
width,
|
|
2438
2647
|
isInputActive
|
|
2439
2648
|
}
|
|
2440
2649
|
) }),
|
|
2441
|
-
/* @__PURE__ */ jsx19(StatusBar, { hint: "Enter to
|
|
2650
|
+
/* @__PURE__ */ jsx19(StatusBar, { hint: "Enter to select \\u00B7 Esc back", width })
|
|
2442
2651
|
] });
|
|
2443
2652
|
}
|
|
2444
2653
|
|
|
2445
2654
|
// src/screens/ProjectConfig.tsx
|
|
2446
|
-
import { useMemo as
|
|
2655
|
+
import { useMemo as useMemo4, useState as useState15 } from "react";
|
|
2447
2656
|
import { Box as Box16, Text as Text20 } from "ink";
|
|
2448
2657
|
|
|
2449
2658
|
// src/hooks/useEditor.ts
|
|
2450
|
-
import { useState as
|
|
2659
|
+
import { useState as useState14, useCallback as useCallback4 } from "react";
|
|
2451
2660
|
import { useStdin } from "ink";
|
|
2452
2661
|
|
|
2453
2662
|
// src/lib/editor.ts
|
|
@@ -2498,7 +2707,7 @@ function openInEditor(filePath) {
|
|
|
2498
2707
|
// src/hooks/useEditor.ts
|
|
2499
2708
|
function useEditor() {
|
|
2500
2709
|
const { setRawMode } = useStdin();
|
|
2501
|
-
const [isEditing, setIsEditing] =
|
|
2710
|
+
const [isEditing, setIsEditing] = useState14(false);
|
|
2502
2711
|
const openEditor = useCallback4(async (filePath) => {
|
|
2503
2712
|
const editor = resolveEditor();
|
|
2504
2713
|
const terminal = isTerminalEditor(editor.command);
|
|
@@ -2519,7 +2728,7 @@ function useEditor() {
|
|
|
2519
2728
|
}
|
|
2520
2729
|
|
|
2521
2730
|
// src/screens/ProjectConfig.tsx
|
|
2522
|
-
import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2731
|
+
import { Fragment, jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2523
2732
|
function ProjectConfig({
|
|
2524
2733
|
onBack,
|
|
2525
2734
|
width = 80,
|
|
@@ -2527,11 +2736,14 @@ function ProjectConfig({
|
|
|
2527
2736
|
panelMode = false,
|
|
2528
2737
|
isInputActive = true
|
|
2529
2738
|
}) {
|
|
2530
|
-
const configPath =
|
|
2531
|
-
const [config2, setConfig] =
|
|
2532
|
-
const [phase, setPhase] =
|
|
2533
|
-
const [feedback, setFeedback] =
|
|
2739
|
+
const configPath = useMemo4(() => getProjectConfigPath(), []);
|
|
2740
|
+
const [config2, setConfig] = useState15(() => getOrCreateProjectConfig());
|
|
2741
|
+
const [phase, setPhase] = useState15("overview");
|
|
2742
|
+
const [feedback, setFeedback] = useState15();
|
|
2743
|
+
const [envKey, setEnvKey] = useState15("");
|
|
2744
|
+
const [selectedEnvKey, setSelectedEnvKey] = useState15("");
|
|
2534
2745
|
const { openEditor, isEditing } = useEditor();
|
|
2746
|
+
const detectedPkg = useMemo4(() => detectPkgManager(), []);
|
|
2535
2747
|
if (!configPath) {
|
|
2536
2748
|
return /* @__PURE__ */ jsxs18(Box16, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
2537
2749
|
/* @__PURE__ */ jsx20(Text20, { color: "red", children: "No package.json found. Run from a project directory." }),
|
|
@@ -2628,15 +2840,158 @@ function ProjectConfig({
|
|
|
2628
2840
|
}
|
|
2629
2841
|
) });
|
|
2630
2842
|
}
|
|
2843
|
+
if (phase === "edit-pkg-manager") {
|
|
2844
|
+
const pkgOptions = [
|
|
2845
|
+
{ value: "npm", label: "npm" },
|
|
2846
|
+
{ value: "pnpm", label: "pnpm" },
|
|
2847
|
+
{ value: "yarn", label: "yarn" },
|
|
2848
|
+
{ value: "bun", label: "bun" },
|
|
2849
|
+
{ value: "__auto__", label: `auto-detect (${detectedPkg.id})` },
|
|
2850
|
+
{ value: "__cancel__", label: "\u2190 Cancel" }
|
|
2851
|
+
];
|
|
2852
|
+
return /* @__PURE__ */ jsxs18(Box16, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
2853
|
+
/* @__PURE__ */ jsx20(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsx20(Text20, { bold: true, children: "Select package manager:" }) }),
|
|
2854
|
+
/* @__PURE__ */ jsx20(
|
|
2855
|
+
SelectList,
|
|
2856
|
+
{
|
|
2857
|
+
items: pkgOptions,
|
|
2858
|
+
onSelect: (value) => {
|
|
2859
|
+
if (value === "__cancel__") {
|
|
2860
|
+
setPhase("overview");
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2863
|
+
const manager = value === "__auto__" ? void 0 : value;
|
|
2864
|
+
const updated = {
|
|
2865
|
+
...config2,
|
|
2866
|
+
tools: {
|
|
2867
|
+
...config2.tools,
|
|
2868
|
+
pkg: manager ? { ...config2.tools.pkg, manager } : {}
|
|
2869
|
+
}
|
|
2870
|
+
};
|
|
2871
|
+
writeProjectConfig(updated);
|
|
2872
|
+
setConfig(updated);
|
|
2873
|
+
setFeedback(manager ? `Package manager set to ${manager}` : "Package manager cleared (auto-detect)");
|
|
2874
|
+
setPhase("overview");
|
|
2875
|
+
},
|
|
2876
|
+
onCancel: () => setPhase("overview"),
|
|
2877
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
2878
|
+
isInputActive,
|
|
2879
|
+
arrowNavigation: panelMode,
|
|
2880
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
2881
|
+
}
|
|
2882
|
+
)
|
|
2883
|
+
] });
|
|
2884
|
+
}
|
|
2885
|
+
if (phase === "add-env-var") {
|
|
2886
|
+
return /* @__PURE__ */ jsx20(Box16, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx20(
|
|
2887
|
+
TextPrompt,
|
|
2888
|
+
{
|
|
2889
|
+
label: "Environment variable name:",
|
|
2890
|
+
placeholder: "e.g. API_KEY",
|
|
2891
|
+
onSubmit: (val) => {
|
|
2892
|
+
const key = val.trim();
|
|
2893
|
+
if (!key) {
|
|
2894
|
+
setPhase("overview");
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2897
|
+
setEnvKey(key);
|
|
2898
|
+
setPhase("add-env-value");
|
|
2899
|
+
},
|
|
2900
|
+
onCancel: () => setPhase("overview"),
|
|
2901
|
+
arrowNavigation: panelMode,
|
|
2902
|
+
isInputActive,
|
|
2903
|
+
boxed: panelMode,
|
|
2904
|
+
focused: isInputActive
|
|
2905
|
+
}
|
|
2906
|
+
) });
|
|
2907
|
+
}
|
|
2908
|
+
if (phase === "add-env-value") {
|
|
2909
|
+
return /* @__PURE__ */ jsx20(Box16, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx20(
|
|
2910
|
+
TextPrompt,
|
|
2911
|
+
{
|
|
2912
|
+
label: `Value for ${envKey}:`,
|
|
2913
|
+
placeholder: "Enter value",
|
|
2914
|
+
onSubmit: (val) => {
|
|
2915
|
+
const updated = {
|
|
2916
|
+
...config2,
|
|
2917
|
+
env: { ...config2.env, [envKey]: val }
|
|
2918
|
+
};
|
|
2919
|
+
writeProjectConfig(updated);
|
|
2920
|
+
setConfig(updated);
|
|
2921
|
+
setFeedback(`Set ${envKey}`);
|
|
2922
|
+
setEnvKey("");
|
|
2923
|
+
setPhase("overview");
|
|
2924
|
+
},
|
|
2925
|
+
onCancel: () => {
|
|
2926
|
+
setEnvKey("");
|
|
2927
|
+
setPhase("overview");
|
|
2928
|
+
},
|
|
2929
|
+
arrowNavigation: panelMode,
|
|
2930
|
+
isInputActive,
|
|
2931
|
+
boxed: panelMode,
|
|
2932
|
+
focused: isInputActive
|
|
2933
|
+
}
|
|
2934
|
+
) });
|
|
2935
|
+
}
|
|
2936
|
+
if (phase === "manage-env-entry") {
|
|
2937
|
+
const currentVal = config2.env?.[selectedEnvKey] ?? "";
|
|
2938
|
+
const items = [
|
|
2939
|
+
{ value: "__info__", label: `${selectedEnvKey} = ${currentVal}`, kind: "header", selectable: false },
|
|
2940
|
+
{ value: "edit", label: "Edit value", kind: "action" },
|
|
2941
|
+
{ value: "remove", label: "Remove", kind: "action" },
|
|
2942
|
+
{ value: "__cancel__", label: "\u2190 Cancel" }
|
|
2943
|
+
];
|
|
2944
|
+
return /* @__PURE__ */ jsx20(Box16, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx20(
|
|
2945
|
+
SelectList,
|
|
2946
|
+
{
|
|
2947
|
+
items,
|
|
2948
|
+
onSelect: (value) => {
|
|
2949
|
+
if (value === "edit") {
|
|
2950
|
+
setEnvKey(selectedEnvKey);
|
|
2951
|
+
setPhase("add-env-value");
|
|
2952
|
+
} else if (value === "remove") {
|
|
2953
|
+
const newEnv = { ...config2.env };
|
|
2954
|
+
delete newEnv[selectedEnvKey];
|
|
2955
|
+
const updated = { ...config2, env: newEnv };
|
|
2956
|
+
writeProjectConfig(updated);
|
|
2957
|
+
setConfig(updated);
|
|
2958
|
+
setFeedback(`Removed ${selectedEnvKey}`);
|
|
2959
|
+
setPhase("overview");
|
|
2960
|
+
} else {
|
|
2961
|
+
setPhase("overview");
|
|
2962
|
+
}
|
|
2963
|
+
},
|
|
2964
|
+
onCancel: () => setPhase("overview"),
|
|
2965
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
2966
|
+
isInputActive,
|
|
2967
|
+
arrowNavigation: panelMode,
|
|
2968
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
2969
|
+
}
|
|
2970
|
+
) });
|
|
2971
|
+
}
|
|
2972
|
+
const envEntries = Object.entries(config2.env ?? {});
|
|
2973
|
+
const pkgDisplay = config2.tools.pkg?.manager ?? `auto-detect (${detectedPkg.id})`;
|
|
2631
2974
|
const configItems = [
|
|
2632
2975
|
{ value: "__section_current__", label: "\u{1F4CB} Current Values", kind: "header", selectable: false },
|
|
2633
2976
|
{ value: "__info_supabase__", label: `Supabase ref: ${config2.tools.supabase?.projectRef ?? "not set"}`, kind: "header", selectable: false },
|
|
2634
2977
|
{ value: "__info_vercel__", label: `Vercel ID: ${config2.tools.vercel?.projectId ?? "not set"}`, kind: "header", selectable: false },
|
|
2635
2978
|
{ value: "__info_gh__", label: `GitHub repo: ${config2.tools.gh?.repo ?? "not set"}`, kind: "header", selectable: false },
|
|
2979
|
+
{ value: "__info_pkg__", label: `Pkg manager: ${pkgDisplay}`, kind: "header", selectable: false },
|
|
2980
|
+
{ value: "__info_pipelines__", label: `Pipelines: ${config2.pipelines.length}`, kind: "header", selectable: false },
|
|
2981
|
+
...envEntries.length > 0 ? [
|
|
2982
|
+
{ value: "__section_env__", label: "\u{1F510} Environment Variables", kind: "header", selectable: false },
|
|
2983
|
+
...envEntries.map(([k, v]) => ({
|
|
2984
|
+
value: `env:${k}`,
|
|
2985
|
+
label: `${k} = ${v}`,
|
|
2986
|
+
kind: "action"
|
|
2987
|
+
}))
|
|
2988
|
+
] : [],
|
|
2636
2989
|
{ value: "__section_actions__", label: "\u26A1 Actions", kind: "header", selectable: false },
|
|
2637
2990
|
{ value: "supabase", label: "Set Supabase project ref", kind: "action" },
|
|
2638
2991
|
{ value: "vercel", label: "Set Vercel project ID", kind: "action" },
|
|
2639
2992
|
{ value: "gh", label: "Set GitHub repo", kind: "action" },
|
|
2993
|
+
{ value: "pkg-manager", label: "Set package manager", kind: "action" },
|
|
2994
|
+
{ value: "add-env", label: "Add environment variable", kind: "action" },
|
|
2640
2995
|
{ value: "editor", label: "Open config in editor", kind: "action" },
|
|
2641
2996
|
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
2642
2997
|
];
|
|
@@ -2644,10 +2999,17 @@ function ProjectConfig({
|
|
|
2644
2999
|
{ value: "supabase", label: "Set Supabase project ref" },
|
|
2645
3000
|
{ value: "vercel", label: "Set Vercel project ID" },
|
|
2646
3001
|
{ value: "gh", label: "Set GitHub repo" },
|
|
3002
|
+
{ value: "pkg-manager", label: "Set package manager" },
|
|
3003
|
+
{ value: "add-env", label: "Add environment variable" },
|
|
2647
3004
|
{ value: "editor", label: "Open config in editor" },
|
|
2648
3005
|
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
2649
3006
|
];
|
|
2650
3007
|
const handleSelect = (value) => {
|
|
3008
|
+
if (value.startsWith("env:")) {
|
|
3009
|
+
setSelectedEnvKey(value.slice(4));
|
|
3010
|
+
setPhase("manage-env-entry");
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
2651
3013
|
switch (value) {
|
|
2652
3014
|
case "supabase":
|
|
2653
3015
|
setPhase("edit-supabase-ref");
|
|
@@ -2658,6 +3020,12 @@ function ProjectConfig({
|
|
|
2658
3020
|
case "gh":
|
|
2659
3021
|
setPhase("edit-gh-repo");
|
|
2660
3022
|
break;
|
|
3023
|
+
case "pkg-manager":
|
|
3024
|
+
setPhase("edit-pkg-manager");
|
|
3025
|
+
break;
|
|
3026
|
+
case "add-env":
|
|
3027
|
+
setPhase("add-env-var");
|
|
3028
|
+
break;
|
|
2661
3029
|
case "editor":
|
|
2662
3030
|
openEditor(configPath.file).then(() => {
|
|
2663
3031
|
try {
|
|
@@ -2717,6 +3085,26 @@ function ProjectConfig({
|
|
|
2717
3085
|
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
2718
3086
|
"GitHub repo: ",
|
|
2719
3087
|
config2.tools.gh?.repo ?? /* @__PURE__ */ jsx20(Text20, { dimColor: true, children: "not set" })
|
|
3088
|
+
] }),
|
|
3089
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
3090
|
+
"Pkg manager: ",
|
|
3091
|
+
pkgDisplay
|
|
3092
|
+
] }),
|
|
3093
|
+
/* @__PURE__ */ jsxs18(Text20, { children: [
|
|
3094
|
+
"Pipelines: ",
|
|
3095
|
+
config2.pipelines.length
|
|
3096
|
+
] }),
|
|
3097
|
+
envEntries.length > 0 && /* @__PURE__ */ jsxs18(Fragment, { children: [
|
|
3098
|
+
/* @__PURE__ */ jsxs18(Text20, { bold: true, children: [
|
|
3099
|
+
"\n",
|
|
3100
|
+
"Environment Variables:"
|
|
3101
|
+
] }),
|
|
3102
|
+
envEntries.map(([k, v]) => /* @__PURE__ */ jsxs18(Text20, { children: [
|
|
3103
|
+
" ",
|
|
3104
|
+
k,
|
|
3105
|
+
" = ",
|
|
3106
|
+
v
|
|
3107
|
+
] }, k))
|
|
2720
3108
|
] })
|
|
2721
3109
|
] }),
|
|
2722
3110
|
feedback && /* @__PURE__ */ jsx20(Box16, { marginBottom: 1, children: /* @__PURE__ */ jsxs18(Text20, { color: inkColors.accent, children: [
|
|
@@ -2739,7 +3127,7 @@ function ProjectConfig({
|
|
|
2739
3127
|
}
|
|
2740
3128
|
|
|
2741
3129
|
// src/screens/PipelineList.tsx
|
|
2742
|
-
import { useMemo as
|
|
3130
|
+
import { useMemo as useMemo5 } from "react";
|
|
2743
3131
|
import { Box as Box17, Text as Text21 } from "ink";
|
|
2744
3132
|
import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2745
3133
|
function PipelineList({
|
|
@@ -2750,8 +3138,8 @@ function PipelineList({
|
|
|
2750
3138
|
panelMode = false,
|
|
2751
3139
|
isInputActive = true
|
|
2752
3140
|
}) {
|
|
2753
|
-
const pipelines =
|
|
2754
|
-
const items =
|
|
3141
|
+
const pipelines = useMemo5(() => getAllPipelines(), []);
|
|
3142
|
+
const items = useMemo5(() => {
|
|
2755
3143
|
const list = [];
|
|
2756
3144
|
if (pipelines.length === 0) {
|
|
2757
3145
|
list.push({
|
|
@@ -2835,7 +3223,7 @@ function PipelineList({
|
|
|
2835
3223
|
}
|
|
2836
3224
|
|
|
2837
3225
|
// src/screens/PipelineBuilder.tsx
|
|
2838
|
-
import { useState as
|
|
3226
|
+
import { useState as useState16 } from "react";
|
|
2839
3227
|
import { Box as Box18, Text as Text22 } from "ink";
|
|
2840
3228
|
import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2841
3229
|
var stepCounter = 0;
|
|
@@ -2850,9 +3238,9 @@ function PipelineBuilder({
|
|
|
2850
3238
|
panelMode = false,
|
|
2851
3239
|
isInputActive = true
|
|
2852
3240
|
}) {
|
|
2853
|
-
const [phase, setPhase] =
|
|
2854
|
-
const [name, setName] =
|
|
2855
|
-
const [steps, setSteps] =
|
|
3241
|
+
const [phase, setPhase] = useState16("name");
|
|
3242
|
+
const [name, setName] = useState16("");
|
|
3243
|
+
const [steps, setSteps] = useState16([]);
|
|
2856
3244
|
if (phase === "name") {
|
|
2857
3245
|
return /* @__PURE__ */ jsxs20(Box18, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
2858
3246
|
/* @__PURE__ */ jsx22(Box18, { marginBottom: 1, children: /* @__PURE__ */ jsx22(Text22, { bold: true, color: inkColors.accent, children: "\u{1F517} New Pipeline" }) }),
|
|
@@ -3038,7 +3426,7 @@ function PipelineBuilder({
|
|
|
3038
3426
|
}
|
|
3039
3427
|
|
|
3040
3428
|
// src/screens/PipelineExecution.tsx
|
|
3041
|
-
import { useState as
|
|
3429
|
+
import { useState as useState17, useEffect as useEffect10, useMemo as useMemo6 } from "react";
|
|
3042
3430
|
import { Box as Box21, Text as Text25 } from "ink";
|
|
3043
3431
|
|
|
3044
3432
|
// src/components/StepIndicator.tsx
|
|
@@ -3118,7 +3506,7 @@ function PipelineProgressBar({
|
|
|
3118
3506
|
}
|
|
3119
3507
|
|
|
3120
3508
|
// src/screens/PipelineExecution.tsx
|
|
3121
|
-
import { Fragment, jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3509
|
+
import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3122
3510
|
function PipelineExecution({
|
|
3123
3511
|
pipelineId,
|
|
3124
3512
|
onBack,
|
|
@@ -3127,14 +3515,14 @@ function PipelineExecution({
|
|
|
3127
3515
|
panelMode = false,
|
|
3128
3516
|
isInputActive = true
|
|
3129
3517
|
}) {
|
|
3130
|
-
const pipeline =
|
|
3518
|
+
const pipeline = useMemo6(
|
|
3131
3519
|
() => getAllPipelines().find((p) => p.id === pipelineId),
|
|
3132
3520
|
[pipelineId]
|
|
3133
3521
|
);
|
|
3134
|
-
const [phase, setPhase] =
|
|
3135
|
-
const [progress, setProgress] =
|
|
3136
|
-
const [results, setResults] =
|
|
3137
|
-
|
|
3522
|
+
const [phase, setPhase] = useState17("running");
|
|
3523
|
+
const [progress, setProgress] = useState17(null);
|
|
3524
|
+
const [results, setResults] = useState17([]);
|
|
3525
|
+
useEffect10(() => {
|
|
3138
3526
|
if (!pipeline) return;
|
|
3139
3527
|
executePipeline(pipeline, (p) => {
|
|
3140
3528
|
setProgress({ ...p });
|
|
@@ -3204,7 +3592,7 @@ function PipelineExecution({
|
|
|
3204
3592
|
},
|
|
3205
3593
|
step.id
|
|
3206
3594
|
)) }),
|
|
3207
|
-
phase === "done" && /* @__PURE__ */ jsxs23(
|
|
3595
|
+
phase === "done" && /* @__PURE__ */ jsxs23(Fragment2, { children: [
|
|
3208
3596
|
/* @__PURE__ */ jsx24(Divider, { width }),
|
|
3209
3597
|
/* @__PURE__ */ jsx24(Box21, { marginY: 1, children: /* @__PURE__ */ jsx24(
|
|
3210
3598
|
Text25,
|
|
@@ -3247,25 +3635,1180 @@ function PipelineExecution({
|
|
|
3247
3635
|
] });
|
|
3248
3636
|
}
|
|
3249
3637
|
|
|
3250
|
-
// src/
|
|
3638
|
+
// src/screens/McpManage.tsx
|
|
3639
|
+
import { useState as useState18, useCallback as useCallback5 } from "react";
|
|
3640
|
+
import { Box as Box22, Text as Text26 } from "ink";
|
|
3251
3641
|
import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
3252
|
-
function
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3642
|
+
function McpManage({
|
|
3643
|
+
onBack,
|
|
3644
|
+
width = 80,
|
|
3645
|
+
height = 24,
|
|
3646
|
+
panelMode = false,
|
|
3647
|
+
isInputActive = true
|
|
3648
|
+
}) {
|
|
3649
|
+
const [status, setStatus] = useState18(() => getMcpStatusInfo());
|
|
3650
|
+
const [phase, setPhase] = useState18("overview");
|
|
3651
|
+
const [action, setAction] = useState18(null);
|
|
3652
|
+
const [result, setResult] = useState18(null);
|
|
3653
|
+
const refreshStatus = useCallback5(() => {
|
|
3654
|
+
setStatus(getMcpStatusInfo());
|
|
3655
|
+
}, []);
|
|
3656
|
+
const executeAction = useCallback5(async (act) => {
|
|
3657
|
+
setAction(act);
|
|
3658
|
+
setPhase("executing");
|
|
3659
|
+
try {
|
|
3660
|
+
const res = act.type === "install" ? await installMcpServerSilent(act.scope) : await removeMcpServerSilent(act.scope);
|
|
3661
|
+
setResult(res);
|
|
3662
|
+
} catch (err) {
|
|
3663
|
+
setResult({ success: false, message: err instanceof Error ? err.message : "Unknown error" });
|
|
3664
|
+
}
|
|
3665
|
+
setPhase("result");
|
|
3666
|
+
}, []);
|
|
3667
|
+
if (phase === "executing") {
|
|
3668
|
+
return /* @__PURE__ */ jsx25(Box22, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx25(Box22, { marginBottom: 1, children: /* @__PURE__ */ jsxs24(Text26, { color: inkColors.accent, children: [
|
|
3669
|
+
action?.type === "install" ? "Installing" : "Removing",
|
|
3670
|
+
" MCP server (",
|
|
3671
|
+
action?.scope,
|
|
3672
|
+
")..."
|
|
3673
|
+
] }) }) });
|
|
3674
|
+
}
|
|
3675
|
+
if (phase === "result" && result) {
|
|
3676
|
+
const resultItems = [
|
|
3677
|
+
{ value: "back-overview", label: "\u2190 Back to overview" },
|
|
3678
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back to Tool Status" }] : []
|
|
3679
|
+
];
|
|
3680
|
+
return /* @__PURE__ */ jsxs24(Box22, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
3681
|
+
/* @__PURE__ */ jsx25(Box22, { marginBottom: 1, children: /* @__PURE__ */ jsxs24(Text26, { color: result.success ? inkColors.accent : "red", children: [
|
|
3682
|
+
result.success ? "\u2713" : "\u2717",
|
|
3683
|
+
" ",
|
|
3684
|
+
result.message
|
|
3685
|
+
] }) }),
|
|
3686
|
+
/* @__PURE__ */ jsx25(
|
|
3687
|
+
SelectList,
|
|
3688
|
+
{
|
|
3689
|
+
items: resultItems,
|
|
3690
|
+
onSelect: (val) => {
|
|
3691
|
+
if (val === "back-overview") {
|
|
3692
|
+
refreshStatus();
|
|
3693
|
+
setPhase("overview");
|
|
3694
|
+
} else {
|
|
3695
|
+
onBack();
|
|
3696
|
+
}
|
|
3697
|
+
},
|
|
3698
|
+
onCancel: () => {
|
|
3699
|
+
refreshStatus();
|
|
3700
|
+
setPhase("overview");
|
|
3701
|
+
},
|
|
3702
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
3703
|
+
isInputActive,
|
|
3704
|
+
arrowNavigation: panelMode,
|
|
3705
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
3706
|
+
}
|
|
3707
|
+
),
|
|
3708
|
+
!panelMode && /* @__PURE__ */ jsx25(StatusBar, { hint: "Enter select . Esc back", width })
|
|
3709
|
+
] });
|
|
3710
|
+
}
|
|
3711
|
+
const projectScope = status.scopes.find((s) => s.scope === "project");
|
|
3712
|
+
const userScope = status.scopes.find((s) => s.scope === "user");
|
|
3713
|
+
const items = panelMode ? [
|
|
3714
|
+
{ value: "__info__", label: `Version: v${status.installedVersion}`, kind: "header", selectable: false },
|
|
3715
|
+
{ value: "__proj__", label: `Project: ${projectScope?.registered ? "registered" : "not registered"}`, kind: "header", selectable: false },
|
|
3716
|
+
{ value: "__user__", label: `User: ${userScope?.registered ? "registered" : "not registered"}`, kind: "header", selectable: false },
|
|
3717
|
+
{ value: "__actions__", label: "Actions", kind: "header", selectable: false },
|
|
3718
|
+
{ value: "install-project", label: "Install (project scope)", kind: "action" },
|
|
3719
|
+
{ value: "install-user", label: "Install (user scope)", kind: "action" },
|
|
3720
|
+
{ value: "remove-project", label: "Remove (project scope)", kind: "action" },
|
|
3721
|
+
{ value: "remove-user", label: "Remove (user scope)", kind: "action" }
|
|
3722
|
+
] : [
|
|
3723
|
+
{ value: "install-project", label: "Install (project scope)" },
|
|
3724
|
+
{ value: "install-user", label: "Install (user scope)" },
|
|
3725
|
+
{ value: "remove-project", label: "Remove (project scope)" },
|
|
3726
|
+
{ value: "remove-user", label: "Remove (user scope)" },
|
|
3727
|
+
{ value: "__back__", label: "\u2190 Back" }
|
|
3728
|
+
];
|
|
3729
|
+
const handleSelect = (value) => {
|
|
3730
|
+
switch (value) {
|
|
3731
|
+
case "install-project":
|
|
3732
|
+
executeAction({ type: "install", scope: "project" });
|
|
3733
|
+
break;
|
|
3734
|
+
case "install-user":
|
|
3735
|
+
executeAction({ type: "install", scope: "user" });
|
|
3736
|
+
break;
|
|
3737
|
+
case "remove-project":
|
|
3738
|
+
executeAction({ type: "remove", scope: "project" });
|
|
3739
|
+
break;
|
|
3740
|
+
case "remove-user":
|
|
3741
|
+
executeAction({ type: "remove", scope: "user" });
|
|
3742
|
+
break;
|
|
3743
|
+
default:
|
|
3744
|
+
onBack();
|
|
3745
|
+
}
|
|
3746
|
+
};
|
|
3747
|
+
if (panelMode) {
|
|
3748
|
+
return /* @__PURE__ */ jsx25(Box22, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx25(
|
|
3749
|
+
SelectList,
|
|
3750
|
+
{
|
|
3751
|
+
items,
|
|
3752
|
+
onSelect: handleSelect,
|
|
3753
|
+
onCancel: onBack,
|
|
3754
|
+
boxedSections: true,
|
|
3755
|
+
width: Math.max(20, width - 4),
|
|
3756
|
+
maxVisible: Math.max(6, height - 6),
|
|
3757
|
+
isInputActive,
|
|
3758
|
+
arrowNavigation: true,
|
|
3759
|
+
panelFocused: isInputActive
|
|
3760
|
+
}
|
|
3761
|
+
) });
|
|
3762
|
+
}
|
|
3763
|
+
return /* @__PURE__ */ jsxs24(Box22, { flexDirection: "column", children: [
|
|
3764
|
+
/* @__PURE__ */ jsx25(Box22, { marginBottom: 1, children: /* @__PURE__ */ jsx25(Text26, { bold: true, color: inkColors.accent, children: "MCP Server Management" }) }),
|
|
3765
|
+
/* @__PURE__ */ jsxs24(Box22, { marginLeft: 2, marginBottom: 1, flexDirection: "column", children: [
|
|
3766
|
+
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
3767
|
+
"Version: v",
|
|
3768
|
+
status.installedVersion
|
|
3769
|
+
] }),
|
|
3770
|
+
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
3771
|
+
"Project: ",
|
|
3772
|
+
/* @__PURE__ */ jsx25(Text26, { color: projectScope?.registered ? inkColors.accent : void 0, dimColor: !projectScope?.registered, children: projectScope?.registered ? "registered" : "not registered" })
|
|
3773
|
+
] }),
|
|
3774
|
+
/* @__PURE__ */ jsxs24(Text26, { children: [
|
|
3775
|
+
"User: ",
|
|
3776
|
+
/* @__PURE__ */ jsx25(Text26, { color: userScope?.registered ? inkColors.accent : void 0, dimColor: !userScope?.registered, children: userScope?.registered ? "registered" : "not registered" })
|
|
3777
|
+
] })
|
|
3778
|
+
] }),
|
|
3779
|
+
/* @__PURE__ */ jsx25(
|
|
3780
|
+
SelectList,
|
|
3781
|
+
{
|
|
3782
|
+
items,
|
|
3783
|
+
onSelect: handleSelect,
|
|
3784
|
+
onCancel: onBack,
|
|
3785
|
+
width,
|
|
3786
|
+
isInputActive
|
|
3787
|
+
}
|
|
3788
|
+
),
|
|
3789
|
+
/* @__PURE__ */ jsx25(StatusBar, { hint: "Enter select . Esc back", width })
|
|
3790
|
+
] });
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
// src/screens/ProcessList.tsx
|
|
3794
|
+
import { useState as useState19, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
3795
|
+
import { Box as Box23, Text as Text27, useInput as useInput9 } from "ink";
|
|
3796
|
+
import { homedir } from "os";
|
|
3797
|
+
import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3798
|
+
function formatUptime(ms) {
|
|
3799
|
+
const seconds = Math.floor(ms / 1e3);
|
|
3800
|
+
const minutes = Math.floor(seconds / 60);
|
|
3801
|
+
const hours = Math.floor(minutes / 60);
|
|
3802
|
+
if (hours > 0) return `${hours}h ${minutes % 60}m`;
|
|
3803
|
+
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
|
|
3804
|
+
return `${seconds}s`;
|
|
3805
|
+
}
|
|
3806
|
+
function formatDuration(startedAt, exitedAt) {
|
|
3807
|
+
if (!exitedAt) return "\u2014";
|
|
3808
|
+
const ms = new Date(exitedAt).getTime() - new Date(startedAt).getTime();
|
|
3809
|
+
return formatUptime(ms);
|
|
3810
|
+
}
|
|
3811
|
+
function statusIcon(status) {
|
|
3812
|
+
switch (status) {
|
|
3813
|
+
case "running":
|
|
3814
|
+
return { icon: "\u25CF", color: "green" };
|
|
3815
|
+
case "exited":
|
|
3816
|
+
return { icon: "\u25CB", color: "gray" };
|
|
3817
|
+
case "errored":
|
|
3818
|
+
return { icon: "\u25CF", color: "red" };
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
function shortenPath(p) {
|
|
3822
|
+
const home = homedir();
|
|
3823
|
+
return p.startsWith(home) ? "~" + p.slice(home.length) : p;
|
|
3824
|
+
}
|
|
3825
|
+
var CARD_HEIGHT = 6;
|
|
3826
|
+
function ProcessList({
|
|
3827
|
+
onNavigate,
|
|
3828
|
+
onBack,
|
|
3829
|
+
width = 80,
|
|
3830
|
+
height = 24,
|
|
3831
|
+
panelMode = false,
|
|
3832
|
+
isInputActive = true
|
|
3833
|
+
}) {
|
|
3834
|
+
const [processes, setProcesses] = useState19(() => listProcesses());
|
|
3835
|
+
const [selectedIndex, setSelectedIndex] = useState19(0);
|
|
3836
|
+
const [feedback, setFeedback] = useState19();
|
|
3837
|
+
useEffect11(() => {
|
|
3838
|
+
const interval = setInterval(() => {
|
|
3839
|
+
setProcesses(listProcesses());
|
|
3840
|
+
}, 2e3);
|
|
3841
|
+
return () => clearInterval(interval);
|
|
3842
|
+
}, []);
|
|
3843
|
+
useEffect11(() => {
|
|
3844
|
+
if (feedback) {
|
|
3845
|
+
const timer = setTimeout(() => setFeedback(void 0), 2e3);
|
|
3846
|
+
return () => clearTimeout(timer);
|
|
3847
|
+
}
|
|
3848
|
+
}, [feedback]);
|
|
3849
|
+
useEffect11(() => {
|
|
3850
|
+
if (selectedIndex >= processes.length && processes.length > 0) {
|
|
3851
|
+
setSelectedIndex(processes.length - 1);
|
|
3852
|
+
}
|
|
3853
|
+
}, [processes.length, selectedIndex]);
|
|
3854
|
+
const handleStop = useCallback6(async (id) => {
|
|
3855
|
+
try {
|
|
3856
|
+
await stopProcess(id);
|
|
3857
|
+
setProcesses(listProcesses());
|
|
3858
|
+
setFeedback(`Stopped: ${id}`);
|
|
3859
|
+
} catch (err) {
|
|
3860
|
+
setFeedback(`Error: ${err instanceof Error ? err.message : "unknown"}`);
|
|
3861
|
+
}
|
|
3862
|
+
}, []);
|
|
3863
|
+
const handleRemove = useCallback6((id) => {
|
|
3864
|
+
try {
|
|
3865
|
+
removeProcess(id);
|
|
3866
|
+
setProcesses(listProcesses());
|
|
3867
|
+
setFeedback(`Removed: ${id}`);
|
|
3868
|
+
} catch (err) {
|
|
3869
|
+
setFeedback(`Error: ${err instanceof Error ? err.message : "unknown"}`);
|
|
3870
|
+
}
|
|
3871
|
+
}, []);
|
|
3872
|
+
useInput9((input2, key) => {
|
|
3873
|
+
if (!isInputActive) return;
|
|
3874
|
+
if (key.escape || key.leftArrow && !key.ctrl) {
|
|
3875
|
+
onBack();
|
|
3876
|
+
return;
|
|
3877
|
+
}
|
|
3878
|
+
if (processes.length === 0) return;
|
|
3879
|
+
if (key.upArrow || input2 === "k") {
|
|
3880
|
+
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
3881
|
+
return;
|
|
3882
|
+
}
|
|
3883
|
+
if (key.downArrow || input2 === "j") {
|
|
3884
|
+
setSelectedIndex((i) => Math.min(processes.length - 1, i + 1));
|
|
3885
|
+
return;
|
|
3886
|
+
}
|
|
3887
|
+
if (key.rightArrow || key.return) {
|
|
3888
|
+
const proc = processes[selectedIndex];
|
|
3889
|
+
if (proc) onNavigate("process-logs", { processId: proc.id });
|
|
3890
|
+
return;
|
|
3891
|
+
}
|
|
3892
|
+
if (input2 === "x") {
|
|
3893
|
+
const proc = processes[selectedIndex];
|
|
3894
|
+
if (proc?.status === "running") handleStop(proc.id);
|
|
3895
|
+
return;
|
|
3896
|
+
}
|
|
3897
|
+
if (input2 === "d") {
|
|
3898
|
+
const proc = processes[selectedIndex];
|
|
3899
|
+
if (proc && proc.status !== "running") handleRemove(proc.id);
|
|
3900
|
+
return;
|
|
3901
|
+
}
|
|
3902
|
+
});
|
|
3903
|
+
const cardWidth = Math.max(30, (panelMode ? width - 4 : width) - 2);
|
|
3904
|
+
if (processes.length === 0) {
|
|
3905
|
+
return /* @__PURE__ */ jsxs25(Box23, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
3906
|
+
!panelMode && /* @__PURE__ */ jsx26(Box23, { marginBottom: 1, children: /* @__PURE__ */ jsx26(Text27, { bold: true, color: inkColors.accent, children: "Processes" }) }),
|
|
3907
|
+
/* @__PURE__ */ jsxs25(
|
|
3908
|
+
Box23,
|
|
3909
|
+
{
|
|
3910
|
+
flexDirection: "column",
|
|
3911
|
+
borderStyle: "round",
|
|
3912
|
+
borderColor: panel.borderDim,
|
|
3913
|
+
borderDimColor: true,
|
|
3914
|
+
paddingX: 1,
|
|
3915
|
+
width: cardWidth,
|
|
3916
|
+
children: [
|
|
3917
|
+
/* @__PURE__ */ jsx26(Text27, { dimColor: true, children: "No tracked processes" }),
|
|
3918
|
+
/* @__PURE__ */ jsx26(Text27, { dimColor: true, children: "Start processes via MCP tools or CLI" })
|
|
3919
|
+
]
|
|
3920
|
+
}
|
|
3921
|
+
),
|
|
3922
|
+
/* @__PURE__ */ jsx26(Box23, { marginTop: 1, gap: 2, children: /* @__PURE__ */ jsx26(Text27, { dimColor: true, children: "Esc:back" }) })
|
|
3923
|
+
] });
|
|
3924
|
+
}
|
|
3925
|
+
const footerHeight = 2;
|
|
3926
|
+
const headerHeight = panelMode ? 0 : 2;
|
|
3927
|
+
const feedbackHeight = feedback ? 2 : 0;
|
|
3928
|
+
const availableHeight = height - headerHeight - footerHeight - feedbackHeight;
|
|
3929
|
+
const visibleCards = Math.max(1, Math.floor(availableHeight / CARD_HEIGHT));
|
|
3930
|
+
const windowStart = Math.max(0, Math.min(selectedIndex - Math.floor(visibleCards / 2), processes.length - visibleCards));
|
|
3931
|
+
const visibleProcesses = processes.slice(windowStart, windowStart + visibleCards);
|
|
3932
|
+
return /* @__PURE__ */ jsxs25(Box23, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
3933
|
+
!panelMode && /* @__PURE__ */ jsx26(Box23, { marginBottom: 1, children: /* @__PURE__ */ jsx26(Text27, { bold: true, color: inkColors.accent, children: "Processes" }) }),
|
|
3934
|
+
feedback && /* @__PURE__ */ jsx26(Box23, { marginBottom: 1, children: /* @__PURE__ */ jsx26(Text27, { color: inkColors.accent, children: feedback }) }),
|
|
3935
|
+
visibleProcesses.map((proc) => {
|
|
3936
|
+
const idx = processes.indexOf(proc);
|
|
3937
|
+
const isFocused = idx === selectedIndex;
|
|
3938
|
+
const si = statusIcon(proc.status);
|
|
3939
|
+
const pid = proc.pid ? String(proc.pid) : "\u2014";
|
|
3940
|
+
const uptimeOrExit = proc.status === "running" ? `UP ${formatUptime(proc.uptime)}` : `EXIT ${proc.exitCode ?? "?"} DURATION ${formatDuration(proc.startedAt, proc.exitedAt)}`;
|
|
3941
|
+
return /* @__PURE__ */ jsxs25(
|
|
3942
|
+
Box23,
|
|
3943
|
+
{
|
|
3944
|
+
flexDirection: "column",
|
|
3945
|
+
borderStyle: "round",
|
|
3946
|
+
borderColor: isFocused ? inkColors.accent : panel.borderDim,
|
|
3947
|
+
borderDimColor: !isFocused,
|
|
3948
|
+
paddingX: 1,
|
|
3949
|
+
width: cardWidth,
|
|
3950
|
+
children: [
|
|
3951
|
+
/* @__PURE__ */ jsxs25(Box23, { justifyContent: "space-between", children: [
|
|
3952
|
+
/* @__PURE__ */ jsxs25(Text27, { bold: true, children: [
|
|
3953
|
+
si.icon,
|
|
3954
|
+
" ",
|
|
3955
|
+
proc.id
|
|
3956
|
+
] }),
|
|
3957
|
+
/* @__PURE__ */ jsx26(Text27, { color: si.color, children: proc.status })
|
|
3958
|
+
] }),
|
|
3959
|
+
/* @__PURE__ */ jsxs25(Text27, { dimColor: true, children: [
|
|
3960
|
+
" CMD ",
|
|
3961
|
+
proc.command,
|
|
3962
|
+
" ",
|
|
3963
|
+
proc.args.join(" ")
|
|
3964
|
+
] }),
|
|
3965
|
+
/* @__PURE__ */ jsxs25(Text27, { dimColor: true, children: [
|
|
3966
|
+
" PID ",
|
|
3967
|
+
pid,
|
|
3968
|
+
" CWD ",
|
|
3969
|
+
shortenPath(proc.cwd)
|
|
3970
|
+
] }),
|
|
3971
|
+
/* @__PURE__ */ jsxs25(Text27, { dimColor: true, children: [
|
|
3972
|
+
" ",
|
|
3973
|
+
uptimeOrExit
|
|
3974
|
+
] })
|
|
3975
|
+
]
|
|
3976
|
+
},
|
|
3977
|
+
proc.id
|
|
3978
|
+
);
|
|
3979
|
+
}),
|
|
3980
|
+
processes.length > visibleCards && /* @__PURE__ */ jsx26(Box23, { children: /* @__PURE__ */ jsxs25(Text27, { dimColor: true, children: [
|
|
3981
|
+
windowStart > 0 ? "\u25B2 " : " ",
|
|
3982
|
+
windowStart + visibleCards < processes.length ? "\u25BC " : " ",
|
|
3983
|
+
processes.length,
|
|
3984
|
+
" processes"
|
|
3985
|
+
] }) }),
|
|
3986
|
+
/* @__PURE__ */ jsxs25(Box23, { marginTop: 1, gap: 2, children: [
|
|
3987
|
+
/* @__PURE__ */ jsxs25(Text27, { dimColor: true, children: [
|
|
3988
|
+
"\u2192",
|
|
3989
|
+
":logs"
|
|
3990
|
+
] }),
|
|
3991
|
+
/* @__PURE__ */ jsx26(Text27, { dimColor: true, children: "x:stop" }),
|
|
3992
|
+
/* @__PURE__ */ jsx26(Text27, { dimColor: true, children: "d:remove" }),
|
|
3993
|
+
/* @__PURE__ */ jsx26(Text27, { dimColor: true, children: "Esc:back" })
|
|
3994
|
+
] })
|
|
3995
|
+
] });
|
|
3996
|
+
}
|
|
3997
|
+
|
|
3998
|
+
// src/screens/ProcessLogs.tsx
|
|
3999
|
+
import { useState as useState20, useEffect as useEffect12, useCallback as useCallback7 } from "react";
|
|
4000
|
+
import { Box as Box24, Text as Text28, useInput as useInput10 } from "ink";
|
|
4001
|
+
import { spawn as spawn3 } from "child_process";
|
|
4002
|
+
import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
4003
|
+
function copyToClipboard2(text) {
|
|
4004
|
+
const cmd = process.platform === "darwin" ? "pbcopy" : "xclip";
|
|
4005
|
+
const args = process.platform === "darwin" ? [] : ["-selection", "clipboard"];
|
|
4006
|
+
const proc = spawn3(cmd, args, { stdio: ["pipe", "ignore", "ignore"] });
|
|
4007
|
+
proc.stdin?.write(text);
|
|
4008
|
+
proc.stdin?.end();
|
|
4009
|
+
}
|
|
4010
|
+
function ProcessLogs({
|
|
4011
|
+
processId,
|
|
4012
|
+
onBack,
|
|
4013
|
+
width = 80,
|
|
4014
|
+
height = 24,
|
|
4015
|
+
panelMode = false,
|
|
4016
|
+
isInputActive = true
|
|
4017
|
+
}) {
|
|
4018
|
+
const [stream, setStream] = useState20("both");
|
|
4019
|
+
const [lines, setLines] = useState20([]);
|
|
4020
|
+
const [proc, setProc] = useState20();
|
|
4021
|
+
const [feedback, setFeedback] = useState20();
|
|
4022
|
+
const logBoxHeight = Math.max(3, height - 6);
|
|
4023
|
+
useEffect12(() => {
|
|
4024
|
+
const refresh = () => {
|
|
4025
|
+
try {
|
|
4026
|
+
const output2 = getProcessOutput(processId, logBoxHeight, stream);
|
|
4027
|
+
const combined = stream === "stderr" ? output2.stderr : stream === "stdout" ? output2.stdout : [...output2.stdout, ...output2.stderr].slice(-logBoxHeight);
|
|
4028
|
+
setLines(combined);
|
|
4029
|
+
} catch {
|
|
4030
|
+
setLines([`Process "${processId}" not found`]);
|
|
4031
|
+
}
|
|
4032
|
+
const all = listProcesses();
|
|
4033
|
+
setProc(all.find((p) => p.id === processId));
|
|
4034
|
+
};
|
|
4035
|
+
refresh();
|
|
4036
|
+
const interval = setInterval(refresh, 1e3);
|
|
4037
|
+
return () => clearInterval(interval);
|
|
4038
|
+
}, [processId, logBoxHeight, stream]);
|
|
4039
|
+
useEffect12(() => {
|
|
4040
|
+
if (feedback) {
|
|
4041
|
+
const timer = setTimeout(() => setFeedback(void 0), 2e3);
|
|
4042
|
+
return () => clearTimeout(timer);
|
|
4043
|
+
}
|
|
4044
|
+
}, [feedback]);
|
|
4045
|
+
const handleStop = useCallback7(async () => {
|
|
4046
|
+
try {
|
|
4047
|
+
await stopProcess(processId);
|
|
4048
|
+
setFeedback("Stopped");
|
|
4049
|
+
} catch (err) {
|
|
4050
|
+
setFeedback(`Error: ${err instanceof Error ? err.message : "unknown"}`);
|
|
4051
|
+
}
|
|
4052
|
+
}, [processId]);
|
|
4053
|
+
const handleCopy = useCallback7(() => {
|
|
4054
|
+
try {
|
|
4055
|
+
copyToClipboard2(lines.join("\n"));
|
|
4056
|
+
setFeedback("Copied to clipboard");
|
|
4057
|
+
} catch {
|
|
4058
|
+
setFeedback("Copy failed");
|
|
4059
|
+
}
|
|
4060
|
+
}, [lines]);
|
|
4061
|
+
useInput10((input2, key) => {
|
|
4062
|
+
if (!isInputActive) return;
|
|
4063
|
+
if (key.escape || key.leftArrow && !key.ctrl) {
|
|
4064
|
+
onBack();
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
if (input2 === "s") {
|
|
4068
|
+
setStream((prev) => {
|
|
4069
|
+
if (prev === "both") return "stdout";
|
|
4070
|
+
if (prev === "stdout") return "stderr";
|
|
4071
|
+
return "both";
|
|
4072
|
+
});
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
if (input2 === "x") {
|
|
4076
|
+
if (proc?.status === "running") handleStop();
|
|
4077
|
+
return;
|
|
4078
|
+
}
|
|
4079
|
+
if (input2 === "c") {
|
|
4080
|
+
handleCopy();
|
|
4081
|
+
return;
|
|
4082
|
+
}
|
|
4083
|
+
});
|
|
4084
|
+
const statusColor = proc?.status === "running" ? "green" : proc?.status === "errored" ? "red" : "gray";
|
|
4085
|
+
const statusIcon2 = proc?.status === "running" ? "\u25CF" : "\u25CB";
|
|
4086
|
+
const cardWidth = Math.max(30, (panelMode ? width - 4 : width) - 2);
|
|
4087
|
+
return /* @__PURE__ */ jsxs26(Box24, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
4088
|
+
/* @__PURE__ */ jsxs26(Box24, { marginBottom: 1, gap: 2, children: [
|
|
4089
|
+
/* @__PURE__ */ jsx27(Text28, { bold: true, color: inkColors.accent, children: processId }),
|
|
4090
|
+
/* @__PURE__ */ jsxs26(Text28, { color: statusColor, children: [
|
|
4091
|
+
statusIcon2,
|
|
4092
|
+
" ",
|
|
4093
|
+
proc?.status ?? "unknown"
|
|
4094
|
+
] }),
|
|
4095
|
+
proc?.pid && /* @__PURE__ */ jsxs26(Text28, { dimColor: true, children: [
|
|
4096
|
+
"PID ",
|
|
4097
|
+
proc.pid
|
|
4098
|
+
] })
|
|
4099
|
+
] }),
|
|
4100
|
+
/* @__PURE__ */ jsx27(
|
|
4101
|
+
Box24,
|
|
4102
|
+
{
|
|
4103
|
+
flexDirection: "column",
|
|
4104
|
+
borderStyle: "round",
|
|
4105
|
+
borderColor: inkColors.accent,
|
|
4106
|
+
paddingX: 1,
|
|
4107
|
+
height: logBoxHeight + 2,
|
|
4108
|
+
width: cardWidth,
|
|
4109
|
+
overflowY: "hidden",
|
|
4110
|
+
children: lines.length === 0 ? /* @__PURE__ */ jsx27(Text28, { dimColor: true, children: "No output yet..." }) : lines.map((line, i) => /* @__PURE__ */ jsx27(Text28, { wrap: "truncate", children: line }, i))
|
|
4111
|
+
}
|
|
4112
|
+
),
|
|
4113
|
+
feedback && /* @__PURE__ */ jsx27(Box24, { children: /* @__PURE__ */ jsx27(Text28, { color: inkColors.accent, children: feedback }) }),
|
|
4114
|
+
/* @__PURE__ */ jsxs26(Box24, { marginTop: 1, gap: 2, children: [
|
|
4115
|
+
/* @__PURE__ */ jsxs26(Text28, { dimColor: true, children: [
|
|
4116
|
+
"stream:[",
|
|
4117
|
+
/* @__PURE__ */ jsx27(Text28, { bold: true, color: inkColors.accent, children: stream }),
|
|
4118
|
+
"]"
|
|
4119
|
+
] }),
|
|
4120
|
+
/* @__PURE__ */ jsx27(Text28, { dimColor: true, children: "s:toggle" }),
|
|
4121
|
+
/* @__PURE__ */ jsx27(Text28, { dimColor: true, children: "x:stop" }),
|
|
4122
|
+
/* @__PURE__ */ jsx27(Text28, { dimColor: true, children: "c:copy" }),
|
|
4123
|
+
/* @__PURE__ */ jsx27(Text28, { dimColor: true, children: "Esc:back" })
|
|
4124
|
+
] })
|
|
4125
|
+
] });
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
// src/screens/DeclarativePlan.tsx
|
|
4129
|
+
import { useEffect as useEffect13, useState as useState21 } from "react";
|
|
4130
|
+
import { Box as Box25, Text as Text29 } from "ink";
|
|
4131
|
+
import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
4132
|
+
function DeclarativePlan({
|
|
4133
|
+
onBack,
|
|
4134
|
+
onNavigate,
|
|
4135
|
+
width = 80,
|
|
4136
|
+
height = 24,
|
|
4137
|
+
panelMode = false,
|
|
4138
|
+
isInputActive = true
|
|
4139
|
+
}) {
|
|
4140
|
+
const [phase, setPhase] = useState21("loading");
|
|
4141
|
+
const [actions, setActions] = useState21([]);
|
|
4142
|
+
const [applyProgress, setApplyProgress] = useState21("");
|
|
4143
|
+
const [applyResults, setApplyResults] = useState21([]);
|
|
4144
|
+
const { openEditor } = useEditor();
|
|
4145
|
+
const loadPlan = () => {
|
|
4146
|
+
setPhase("loading");
|
|
4147
|
+
setTimeout(() => {
|
|
4148
|
+
const yamlPath = findPolterYaml();
|
|
4149
|
+
if (!yamlPath) {
|
|
4150
|
+
setPhase("no-yaml");
|
|
4151
|
+
return;
|
|
4152
|
+
}
|
|
4153
|
+
const yaml = parsePolterYaml();
|
|
4154
|
+
if (!yaml) {
|
|
4155
|
+
setPhase("no-yaml");
|
|
4156
|
+
return;
|
|
4157
|
+
}
|
|
4158
|
+
const plan = planChanges(yaml);
|
|
4159
|
+
setActions(plan.actions);
|
|
4160
|
+
setPhase("plan-view");
|
|
4161
|
+
}, 0);
|
|
4162
|
+
};
|
|
4163
|
+
useEffect13(() => {
|
|
4164
|
+
loadPlan();
|
|
4165
|
+
}, []);
|
|
4166
|
+
if (phase === "loading") {
|
|
4167
|
+
return /* @__PURE__ */ jsx28(Box25, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx28(Text29, { color: inkColors.accent, children: "Loading plan..." }) });
|
|
4168
|
+
}
|
|
4169
|
+
if (phase === "no-yaml") {
|
|
4170
|
+
const items = [
|
|
4171
|
+
...onNavigate ? [{ value: "init", label: "Init from current state", kind: "action" }] : [],
|
|
4172
|
+
{ value: "editor", label: "Open editor to create polter.yaml", kind: "action" },
|
|
4173
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4174
|
+
];
|
|
4175
|
+
const handleSelect2 = (value) => {
|
|
4176
|
+
if (value === "init" && onNavigate) {
|
|
4177
|
+
onNavigate("init-scaffold");
|
|
4178
|
+
} else if (value === "editor") {
|
|
4179
|
+
const cwd = process.cwd();
|
|
4180
|
+
openEditor(`${cwd}/polter.yaml`).then(() => loadPlan());
|
|
4181
|
+
} else {
|
|
4182
|
+
onBack();
|
|
4183
|
+
}
|
|
4184
|
+
};
|
|
4185
|
+
return /* @__PURE__ */ jsxs27(Box25, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
4186
|
+
/* @__PURE__ */ jsx28(Box25, { marginBottom: 1, children: /* @__PURE__ */ jsx28(Text29, { color: "yellow", children: "No polter.yaml found in the current directory." }) }),
|
|
4187
|
+
/* @__PURE__ */ jsx28(
|
|
4188
|
+
SelectList,
|
|
4189
|
+
{
|
|
4190
|
+
items,
|
|
4191
|
+
onSelect: handleSelect2,
|
|
4192
|
+
onCancel: onBack,
|
|
4193
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
4194
|
+
isInputActive,
|
|
4195
|
+
arrowNavigation: panelMode,
|
|
4196
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
4197
|
+
}
|
|
4198
|
+
),
|
|
4199
|
+
!panelMode && /* @__PURE__ */ jsx28(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4200
|
+
] });
|
|
4201
|
+
}
|
|
4202
|
+
if (phase === "applying") {
|
|
4203
|
+
return /* @__PURE__ */ jsxs27(Box25, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
4204
|
+
/* @__PURE__ */ jsx28(Box25, { marginBottom: 1, children: /* @__PURE__ */ jsx28(Text29, { bold: true, color: inkColors.accent, children: "Applying changes..." }) }),
|
|
4205
|
+
/* @__PURE__ */ jsx28(Text29, { children: applyProgress })
|
|
4206
|
+
] });
|
|
4207
|
+
}
|
|
4208
|
+
if (phase === "results") {
|
|
4209
|
+
const resultItems = [
|
|
4210
|
+
{ value: "__section_results__", label: "Results", kind: "header", selectable: false },
|
|
4211
|
+
...applyResults.map((r, i) => ({
|
|
4212
|
+
value: `result-${i}`,
|
|
4213
|
+
label: `${r.success ? "\u2713" : "\u2717"} ${r.action.description}`,
|
|
4214
|
+
hint: r.success ? "success" : r.result.stderr || "failed",
|
|
4215
|
+
kind: "header",
|
|
4216
|
+
selectable: false
|
|
4217
|
+
})),
|
|
4218
|
+
{ value: "__section_actions__", label: "Actions", kind: "header", selectable: false },
|
|
4219
|
+
{ value: "replan", label: "Re-run plan", kind: "action" },
|
|
4220
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4221
|
+
];
|
|
4222
|
+
const handleSelect2 = (value) => {
|
|
4223
|
+
if (value === "replan") {
|
|
4224
|
+
loadPlan();
|
|
4225
|
+
} else {
|
|
4226
|
+
onBack();
|
|
4227
|
+
}
|
|
4228
|
+
};
|
|
4229
|
+
if (panelMode) {
|
|
4230
|
+
return /* @__PURE__ */ jsx28(Box25, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx28(
|
|
4231
|
+
SelectList,
|
|
4232
|
+
{
|
|
4233
|
+
items: resultItems,
|
|
4234
|
+
onSelect: handleSelect2,
|
|
4235
|
+
onCancel: onBack,
|
|
4236
|
+
boxedSections: true,
|
|
4237
|
+
width: Math.max(20, width - 4),
|
|
4238
|
+
maxVisible: Math.max(6, height - 6),
|
|
4239
|
+
isInputActive,
|
|
4240
|
+
arrowNavigation: true,
|
|
4241
|
+
panelFocused: isInputActive
|
|
4242
|
+
}
|
|
4243
|
+
) });
|
|
4244
|
+
}
|
|
4245
|
+
return /* @__PURE__ */ jsxs27(Box25, { flexDirection: "column", children: [
|
|
4246
|
+
/* @__PURE__ */ jsx28(Box25, { marginBottom: 1, children: /* @__PURE__ */ jsx28(Text29, { bold: true, color: inkColors.accent, children: "Apply Results" }) }),
|
|
4247
|
+
/* @__PURE__ */ jsx28(
|
|
4248
|
+
SelectList,
|
|
4249
|
+
{
|
|
4250
|
+
items: resultItems,
|
|
4251
|
+
onSelect: handleSelect2,
|
|
4252
|
+
onCancel: onBack,
|
|
4253
|
+
boxedSections: true,
|
|
4254
|
+
width,
|
|
4255
|
+
maxVisible: Math.max(8, height - 10),
|
|
4256
|
+
isInputActive
|
|
4257
|
+
}
|
|
4258
|
+
),
|
|
4259
|
+
/* @__PURE__ */ jsx28(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4260
|
+
] });
|
|
4261
|
+
}
|
|
4262
|
+
const actionPrefix = (a) => {
|
|
4263
|
+
switch (a.action) {
|
|
4264
|
+
case "create":
|
|
4265
|
+
return "+";
|
|
4266
|
+
case "update":
|
|
4267
|
+
return "~";
|
|
4268
|
+
case "delete":
|
|
4269
|
+
return "-";
|
|
4270
|
+
}
|
|
4271
|
+
};
|
|
4272
|
+
const actionColor = (a) => {
|
|
4273
|
+
switch (a.action) {
|
|
4274
|
+
case "create":
|
|
4275
|
+
return "green";
|
|
4276
|
+
case "update":
|
|
4277
|
+
return "yellow";
|
|
4278
|
+
case "delete":
|
|
4279
|
+
return "red";
|
|
4280
|
+
}
|
|
4281
|
+
};
|
|
4282
|
+
const planItems = [
|
|
4283
|
+
{
|
|
4284
|
+
value: "__section_plan__",
|
|
4285
|
+
label: actions.length > 0 ? `Plan: ${actions.length} action${actions.length > 1 ? "s" : ""}` : "No changes needed",
|
|
4286
|
+
kind: "header",
|
|
4287
|
+
selectable: false
|
|
4288
|
+
},
|
|
4289
|
+
...actions.map((a, i) => ({
|
|
4290
|
+
value: `action-${i}`,
|
|
4291
|
+
label: `${actionPrefix(a)} ${a.description}`,
|
|
4292
|
+
hint: `${a.tool} ${a.resource}`,
|
|
4293
|
+
kind: "header",
|
|
4294
|
+
selectable: false
|
|
4295
|
+
})),
|
|
4296
|
+
{ value: "__section_actions__", label: "Actions", kind: "header", selectable: false },
|
|
4297
|
+
...actions.length > 0 ? [{ value: "apply", label: "Apply all changes", kind: "action" }] : [],
|
|
4298
|
+
{ value: "editor", label: "Open polter.yaml in editor", kind: "action" },
|
|
4299
|
+
{ value: "refresh", label: "Refresh plan", kind: "action" },
|
|
4300
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4301
|
+
];
|
|
4302
|
+
const handleSelect = (value) => {
|
|
4303
|
+
if (value === "apply") {
|
|
4304
|
+
setPhase("applying");
|
|
4305
|
+
applyActions(actions, process.cwd(), (completed, total, current) => {
|
|
4306
|
+
setApplyProgress(`[${completed + 1}/${total}] ${current.description}...`);
|
|
4307
|
+
}).then((results) => {
|
|
4308
|
+
setApplyResults(results);
|
|
4309
|
+
setPhase("results");
|
|
4310
|
+
});
|
|
4311
|
+
} else if (value === "editor") {
|
|
4312
|
+
const yamlPath = findPolterYaml();
|
|
4313
|
+
if (yamlPath) {
|
|
4314
|
+
openEditor(yamlPath).then(() => loadPlan());
|
|
4315
|
+
}
|
|
4316
|
+
} else if (value === "refresh") {
|
|
4317
|
+
loadPlan();
|
|
4318
|
+
} else {
|
|
4319
|
+
onBack();
|
|
4320
|
+
}
|
|
4321
|
+
};
|
|
4322
|
+
if (panelMode) {
|
|
4323
|
+
return /* @__PURE__ */ jsx28(Box25, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx28(
|
|
4324
|
+
SelectList,
|
|
4325
|
+
{
|
|
4326
|
+
items: planItems,
|
|
4327
|
+
onSelect: handleSelect,
|
|
4328
|
+
onCancel: onBack,
|
|
4329
|
+
boxedSections: true,
|
|
4330
|
+
width: Math.max(20, width - 4),
|
|
4331
|
+
maxVisible: Math.max(6, height - 6),
|
|
4332
|
+
isInputActive,
|
|
4333
|
+
arrowNavigation: true,
|
|
4334
|
+
panelFocused: isInputActive
|
|
4335
|
+
}
|
|
4336
|
+
) });
|
|
4337
|
+
}
|
|
4338
|
+
return /* @__PURE__ */ jsxs27(Box25, { flexDirection: "column", children: [
|
|
4339
|
+
/* @__PURE__ */ jsx28(Box25, { marginBottom: 1, children: /* @__PURE__ */ jsx28(Text29, { bold: true, color: inkColors.accent, children: "Plan / Apply" }) }),
|
|
4340
|
+
/* @__PURE__ */ jsx28(
|
|
4341
|
+
SelectList,
|
|
4342
|
+
{
|
|
4343
|
+
items: planItems,
|
|
4344
|
+
onSelect: handleSelect,
|
|
4345
|
+
onCancel: onBack,
|
|
4346
|
+
boxedSections: true,
|
|
4347
|
+
width,
|
|
4348
|
+
maxVisible: Math.max(8, height - 10),
|
|
4349
|
+
isInputActive
|
|
4350
|
+
}
|
|
4351
|
+
),
|
|
4352
|
+
/* @__PURE__ */ jsx28(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4353
|
+
] });
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
// src/screens/DeclarativeStatus.tsx
|
|
4357
|
+
import { useEffect as useEffect14, useState as useState22 } from "react";
|
|
4358
|
+
import { Box as Box26, Text as Text30 } from "ink";
|
|
4359
|
+
import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
4360
|
+
function DeclarativeStatus({
|
|
4361
|
+
onBack,
|
|
4362
|
+
width = 80,
|
|
4363
|
+
height = 24,
|
|
4364
|
+
panelMode = false,
|
|
4365
|
+
isInputActive = true
|
|
4366
|
+
}) {
|
|
4367
|
+
const [phase, setPhase] = useState22("loading");
|
|
4368
|
+
const [status, setStatus] = useState22({});
|
|
4369
|
+
const [config2, setConfig] = useState22(null);
|
|
4370
|
+
const [pkgInfo, setPkgInfo] = useState22(null);
|
|
4371
|
+
const load = () => {
|
|
4372
|
+
setPhase("loading");
|
|
4373
|
+
setTimeout(() => {
|
|
4374
|
+
const s = getCurrentStatus();
|
|
4375
|
+
const c = getOrCreateProjectConfig();
|
|
4376
|
+
const p = detectPkgManager();
|
|
4377
|
+
setStatus(s);
|
|
4378
|
+
setConfig(c);
|
|
4379
|
+
setPkgInfo(p);
|
|
4380
|
+
setPhase("display");
|
|
4381
|
+
}, 0);
|
|
4382
|
+
};
|
|
4383
|
+
useEffect14(() => {
|
|
4384
|
+
load();
|
|
4385
|
+
}, []);
|
|
4386
|
+
if (phase === "loading") {
|
|
4387
|
+
return /* @__PURE__ */ jsx29(Box26, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx29(Text30, { color: inkColors.accent, children: "Loading infrastructure status..." }) });
|
|
4388
|
+
}
|
|
4389
|
+
const configuredPkg = config2?.tools?.pkg?.manager;
|
|
4390
|
+
const items = [
|
|
4391
|
+
{ value: "__section_supabase__", label: "Supabase", kind: "header", selectable: false },
|
|
4392
|
+
{
|
|
4393
|
+
value: "__info_sb_linked__",
|
|
4394
|
+
label: `Linked: ${status.supabase?.linked ? "yes" : "no"}`,
|
|
4395
|
+
kind: "header",
|
|
4396
|
+
selectable: false
|
|
4397
|
+
},
|
|
4398
|
+
{
|
|
4399
|
+
value: "__info_sb_ref__",
|
|
4400
|
+
label: `Project ref: ${status.supabase?.projectRef ?? "not set"}`,
|
|
4401
|
+
kind: "header",
|
|
4402
|
+
selectable: false
|
|
4403
|
+
},
|
|
4404
|
+
{
|
|
4405
|
+
value: "__info_sb_fns__",
|
|
4406
|
+
label: `Functions: ${status.supabase?.functions?.length ? status.supabase.functions.join(", ") : "none"}`,
|
|
4407
|
+
kind: "header",
|
|
4408
|
+
selectable: false
|
|
4409
|
+
},
|
|
4410
|
+
{ value: "__section_vercel__", label: "Vercel", kind: "header", selectable: false },
|
|
4411
|
+
{
|
|
4412
|
+
value: "__info_vc_linked__",
|
|
4413
|
+
label: `Linked: ${status.vercel?.linked ? "yes" : "no"}`,
|
|
4414
|
+
kind: "header",
|
|
4415
|
+
selectable: false
|
|
4416
|
+
},
|
|
4417
|
+
{
|
|
4418
|
+
value: "__info_vc_id__",
|
|
4419
|
+
label: `Project ID: ${status.vercel?.projectId ?? "not set"}`,
|
|
4420
|
+
kind: "header",
|
|
4421
|
+
selectable: false
|
|
4422
|
+
},
|
|
4423
|
+
{ value: "__section_github__", label: "GitHub", kind: "header", selectable: false },
|
|
4424
|
+
{
|
|
4425
|
+
value: "__info_gh_auth__",
|
|
4426
|
+
label: `Authenticated: ${status.github?.authenticated ? "yes" : "no"}`,
|
|
4427
|
+
kind: "header",
|
|
4428
|
+
selectable: false
|
|
4429
|
+
},
|
|
4430
|
+
{
|
|
4431
|
+
value: "__info_gh_repo__",
|
|
4432
|
+
label: `Repo: ${status.github?.repo ?? "not set"}`,
|
|
4433
|
+
kind: "header",
|
|
4434
|
+
selectable: false
|
|
4435
|
+
},
|
|
4436
|
+
{ value: "__section_pkg__", label: "Package Manager", kind: "header", selectable: false },
|
|
4437
|
+
{
|
|
4438
|
+
value: "__info_pkg__",
|
|
4439
|
+
label: `Detected: ${pkgInfo?.id ?? "npm"}${configuredPkg ? ` (configured: ${configuredPkg})` : ""}`,
|
|
4440
|
+
kind: "header",
|
|
4441
|
+
selectable: false
|
|
4442
|
+
},
|
|
4443
|
+
{ value: "__section_actions__", label: "Actions", kind: "header", selectable: false },
|
|
4444
|
+
{ value: "refresh", label: "Refresh", kind: "action" },
|
|
4445
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4446
|
+
];
|
|
4447
|
+
const handleSelect = (value) => {
|
|
4448
|
+
if (value === "refresh") {
|
|
4449
|
+
load();
|
|
4450
|
+
} else if (value === "__back__") {
|
|
4451
|
+
onBack();
|
|
4452
|
+
}
|
|
4453
|
+
};
|
|
4454
|
+
if (panelMode) {
|
|
4455
|
+
return /* @__PURE__ */ jsx29(Box26, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx29(
|
|
4456
|
+
SelectList,
|
|
4457
|
+
{
|
|
4458
|
+
items,
|
|
4459
|
+
onSelect: handleSelect,
|
|
4460
|
+
onCancel: onBack,
|
|
4461
|
+
boxedSections: true,
|
|
4462
|
+
width: Math.max(20, width - 4),
|
|
4463
|
+
maxVisible: Math.max(6, height - 6),
|
|
4464
|
+
isInputActive,
|
|
4465
|
+
arrowNavigation: true,
|
|
4466
|
+
panelFocused: isInputActive
|
|
4467
|
+
}
|
|
4468
|
+
) });
|
|
4469
|
+
}
|
|
4470
|
+
return /* @__PURE__ */ jsxs28(Box26, { flexDirection: "column", children: [
|
|
4471
|
+
/* @__PURE__ */ jsx29(Box26, { marginBottom: 1, children: /* @__PURE__ */ jsx29(Text30, { bold: true, color: inkColors.accent, children: "Infrastructure Status" }) }),
|
|
4472
|
+
/* @__PURE__ */ jsx29(
|
|
4473
|
+
SelectList,
|
|
4474
|
+
{
|
|
4475
|
+
items,
|
|
4476
|
+
onSelect: handleSelect,
|
|
4477
|
+
onCancel: onBack,
|
|
4478
|
+
boxedSections: true,
|
|
4479
|
+
width,
|
|
4480
|
+
maxVisible: Math.max(8, height - 10),
|
|
4481
|
+
isInputActive
|
|
4482
|
+
}
|
|
4483
|
+
),
|
|
4484
|
+
/* @__PURE__ */ jsx29(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4485
|
+
] });
|
|
4486
|
+
}
|
|
4487
|
+
|
|
4488
|
+
// src/screens/InitScaffold.tsx
|
|
4489
|
+
import { useEffect as useEffect15, useState as useState23 } from "react";
|
|
4490
|
+
import { Box as Box27, Text as Text31 } from "ink";
|
|
4491
|
+
import { writeFileSync } from "fs";
|
|
4492
|
+
import { join } from "path";
|
|
4493
|
+
|
|
4494
|
+
// src/lib/yamlWriter.ts
|
|
4495
|
+
function generatePolterYaml(config2) {
|
|
4496
|
+
const lines = [];
|
|
4497
|
+
lines.push(`version: ${config2.version}`);
|
|
4498
|
+
if (config2.project) {
|
|
4499
|
+
lines.push("");
|
|
4500
|
+
lines.push("project:");
|
|
4501
|
+
lines.push(` name: ${quote(config2.project.name)}`);
|
|
4502
|
+
}
|
|
4503
|
+
if (config2.supabase) {
|
|
4504
|
+
lines.push("");
|
|
4505
|
+
lines.push("supabase:");
|
|
4506
|
+
if (config2.supabase.project_ref) {
|
|
4507
|
+
lines.push(` project_ref: ${quote(config2.supabase.project_ref)}`);
|
|
4508
|
+
}
|
|
4509
|
+
if (config2.supabase.region) {
|
|
4510
|
+
lines.push(` region: ${quote(config2.supabase.region)}`);
|
|
4511
|
+
}
|
|
4512
|
+
if (config2.supabase.database) {
|
|
4513
|
+
lines.push(" database:");
|
|
4514
|
+
if (config2.supabase.database.migrations_dir) {
|
|
4515
|
+
lines.push(` migrations_dir: ${quote(config2.supabase.database.migrations_dir)}`);
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
if (config2.supabase.functions && config2.supabase.functions.length > 0) {
|
|
4519
|
+
lines.push(" functions:");
|
|
4520
|
+
for (const fn of config2.supabase.functions) {
|
|
4521
|
+
lines.push(` - name: ${quote(fn.name)}`);
|
|
4522
|
+
if (fn.verify_jwt !== void 0) {
|
|
4523
|
+
lines.push(` verify_jwt: ${fn.verify_jwt}`);
|
|
4524
|
+
}
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
if (config2.supabase.secrets && config2.supabase.secrets.length > 0) {
|
|
4528
|
+
lines.push(" secrets:");
|
|
4529
|
+
for (const secret of config2.supabase.secrets) {
|
|
4530
|
+
lines.push(` - ${quote(secret)}`);
|
|
4531
|
+
}
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
if (config2.vercel) {
|
|
4535
|
+
lines.push("");
|
|
4536
|
+
lines.push("vercel:");
|
|
4537
|
+
if (config2.vercel.project_id) {
|
|
4538
|
+
lines.push(` project_id: ${quote(config2.vercel.project_id)}`);
|
|
4539
|
+
}
|
|
4540
|
+
if (config2.vercel.framework) {
|
|
4541
|
+
lines.push(` framework: ${quote(config2.vercel.framework)}`);
|
|
4542
|
+
}
|
|
4543
|
+
if (config2.vercel.domains && config2.vercel.domains.length > 0) {
|
|
4544
|
+
lines.push(" domains:");
|
|
4545
|
+
for (const domain of config2.vercel.domains) {
|
|
4546
|
+
lines.push(` - ${quote(domain)}`);
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
if (config2.vercel.env) {
|
|
4550
|
+
lines.push(" env:");
|
|
4551
|
+
for (const [env, vars] of Object.entries(config2.vercel.env)) {
|
|
4552
|
+
lines.push(` ${env}:`);
|
|
4553
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
4554
|
+
lines.push(` ${key}: ${quote(value)}`);
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
}
|
|
4558
|
+
}
|
|
4559
|
+
if (config2.github) {
|
|
4560
|
+
lines.push("");
|
|
4561
|
+
lines.push("github:");
|
|
4562
|
+
if (config2.github.repo) {
|
|
4563
|
+
lines.push(` repo: ${quote(config2.github.repo)}`);
|
|
4564
|
+
}
|
|
4565
|
+
if (config2.github.branch_protection) {
|
|
4566
|
+
lines.push(" branch_protection:");
|
|
4567
|
+
for (const [branch, rules] of Object.entries(config2.github.branch_protection)) {
|
|
4568
|
+
lines.push(` ${branch}:`);
|
|
4569
|
+
if (rules.required_reviews !== void 0) {
|
|
4570
|
+
lines.push(` required_reviews: ${rules.required_reviews}`);
|
|
4571
|
+
}
|
|
4572
|
+
if (rules.require_status_checks !== void 0) {
|
|
4573
|
+
lines.push(` require_status_checks: ${rules.require_status_checks}`);
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
if (config2.github.secrets && config2.github.secrets.length > 0) {
|
|
4578
|
+
lines.push(" secrets:");
|
|
4579
|
+
for (const secret of config2.github.secrets) {
|
|
4580
|
+
lines.push(` - ${quote(secret)}`);
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
if (config2.pkg) {
|
|
4585
|
+
lines.push("");
|
|
4586
|
+
lines.push("pkg:");
|
|
4587
|
+
if (config2.pkg.manager) {
|
|
4588
|
+
lines.push(` manager: ${config2.pkg.manager}`);
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
if (config2.pipelines) {
|
|
4592
|
+
lines.push("");
|
|
4593
|
+
lines.push("pipelines:");
|
|
4594
|
+
for (const [name, pipeline] of Object.entries(config2.pipelines)) {
|
|
4595
|
+
lines.push(` ${name}:`);
|
|
4596
|
+
if (pipeline.description) {
|
|
4597
|
+
lines.push(` description: ${quote(pipeline.description)}`);
|
|
4598
|
+
}
|
|
4599
|
+
lines.push(" steps:");
|
|
4600
|
+
for (const step of pipeline.steps) {
|
|
4601
|
+
lines.push(` - ${quote(step)}`);
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
lines.push("");
|
|
4606
|
+
return lines.join("\n");
|
|
4607
|
+
}
|
|
4608
|
+
function needsQuoting(value) {
|
|
4609
|
+
if (!value) return true;
|
|
4610
|
+
if (/^[\d]/.test(value) && /[^\d.]/.test(value)) return true;
|
|
4611
|
+
if (/[:#\[\]{}&*!|>'"%@`]/.test(value)) return true;
|
|
4612
|
+
if (value === "true" || value === "false" || value === "null") return true;
|
|
4613
|
+
if (value.includes(" ") && !value.startsWith('"')) return true;
|
|
4614
|
+
return false;
|
|
4615
|
+
}
|
|
4616
|
+
function quote(value) {
|
|
4617
|
+
if (needsQuoting(value)) {
|
|
4618
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
4619
|
+
}
|
|
4620
|
+
return value;
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
// src/screens/InitScaffold.tsx
|
|
4624
|
+
import { jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4625
|
+
function InitScaffold({
|
|
4626
|
+
onBack,
|
|
4627
|
+
onNavigate,
|
|
4628
|
+
width = 80,
|
|
4629
|
+
height = 24,
|
|
4630
|
+
panelMode = false,
|
|
4631
|
+
isInputActive = true
|
|
4632
|
+
}) {
|
|
4633
|
+
const [phase, setPhase] = useState23("detecting");
|
|
4634
|
+
const [yamlString, setYamlString] = useState23("");
|
|
4635
|
+
const [overwrite, setOverwrite] = useState23(false);
|
|
4636
|
+
const { openEditor } = useEditor();
|
|
4637
|
+
const cwd = process.cwd();
|
|
4638
|
+
const yamlPath = join(cwd, "polter.yaml");
|
|
4639
|
+
const detect = (forceOverwrite = false) => {
|
|
4640
|
+
setPhase("detecting");
|
|
4641
|
+
setTimeout(() => {
|
|
4642
|
+
const existing = findPolterYaml();
|
|
4643
|
+
if (existing && !forceOverwrite) {
|
|
4644
|
+
setPhase("already-exists");
|
|
4645
|
+
return;
|
|
4646
|
+
}
|
|
4647
|
+
const status = getCurrentStatus();
|
|
4648
|
+
const config2 = getOrCreateProjectConfig();
|
|
4649
|
+
const pkg = detectPkgManager();
|
|
4650
|
+
const yaml = {
|
|
4651
|
+
version: 1,
|
|
4652
|
+
project: { name: cwd.split("/").pop() ?? "my-project" }
|
|
4653
|
+
};
|
|
4654
|
+
if (status.supabase) {
|
|
4655
|
+
yaml.supabase = {};
|
|
4656
|
+
if (config2.tools.supabase?.projectRef) {
|
|
4657
|
+
yaml.supabase.project_ref = config2.tools.supabase.projectRef;
|
|
4658
|
+
}
|
|
4659
|
+
if (status.supabase.functions && status.supabase.functions.length > 0) {
|
|
4660
|
+
yaml.supabase.functions = status.supabase.functions.map((name) => ({ name }));
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
if (status.vercel) {
|
|
4664
|
+
yaml.vercel = {};
|
|
4665
|
+
if (config2.tools.vercel?.projectId) {
|
|
4666
|
+
yaml.vercel.project_id = config2.tools.vercel.projectId;
|
|
4667
|
+
}
|
|
4668
|
+
}
|
|
4669
|
+
if (status.github) {
|
|
4670
|
+
yaml.github = {};
|
|
4671
|
+
if (status.github.repo) {
|
|
4672
|
+
yaml.github.repo = status.github.repo;
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
yaml.pkg = { manager: config2.tools.pkg?.manager ?? pkg.id };
|
|
4676
|
+
const generated = generatePolterYaml(yaml);
|
|
4677
|
+
setYamlString(generated);
|
|
4678
|
+
setPhase("preview");
|
|
4679
|
+
}, 0);
|
|
4680
|
+
};
|
|
4681
|
+
useEffect15(() => {
|
|
4682
|
+
detect();
|
|
4683
|
+
}, []);
|
|
4684
|
+
if (phase === "detecting") {
|
|
4685
|
+
return /* @__PURE__ */ jsx30(Box27, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx30(Text31, { color: inkColors.accent, children: "Detecting project state..." }) });
|
|
4686
|
+
}
|
|
4687
|
+
if (phase === "already-exists") {
|
|
4688
|
+
const items2 = [
|
|
4689
|
+
{ value: "editor", label: "Open in editor", kind: "action" },
|
|
4690
|
+
{ value: "overwrite", label: "Overwrite with detected state", kind: "action" },
|
|
4691
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4692
|
+
];
|
|
4693
|
+
const handleSelect2 = (value) => {
|
|
4694
|
+
if (value === "editor") {
|
|
4695
|
+
openEditor(yamlPath);
|
|
4696
|
+
} else if (value === "overwrite") {
|
|
4697
|
+
detect(true);
|
|
4698
|
+
} else {
|
|
4699
|
+
onBack();
|
|
4700
|
+
}
|
|
4701
|
+
};
|
|
4702
|
+
return /* @__PURE__ */ jsxs29(Box27, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
4703
|
+
/* @__PURE__ */ jsx30(Box27, { marginBottom: 1, children: /* @__PURE__ */ jsx30(Text31, { color: "yellow", children: "polter.yaml already exists." }) }),
|
|
4704
|
+
/* @__PURE__ */ jsx30(
|
|
4705
|
+
SelectList,
|
|
4706
|
+
{
|
|
4707
|
+
items: items2,
|
|
4708
|
+
onSelect: handleSelect2,
|
|
4709
|
+
onCancel: onBack,
|
|
4710
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
4711
|
+
isInputActive,
|
|
4712
|
+
arrowNavigation: panelMode,
|
|
4713
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
4714
|
+
}
|
|
4715
|
+
),
|
|
4716
|
+
!panelMode && /* @__PURE__ */ jsx30(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4717
|
+
] });
|
|
4718
|
+
}
|
|
4719
|
+
if (phase === "preview") {
|
|
4720
|
+
const previewLines = yamlString.split("\n").slice(0, Math.max(8, height - 12));
|
|
4721
|
+
const items2 = [
|
|
4722
|
+
{ value: "write", label: "Write polter.yaml", kind: "action" },
|
|
4723
|
+
{ value: "edit-first", label: "Edit before writing", kind: "action" },
|
|
4724
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4725
|
+
];
|
|
4726
|
+
const handleSelect2 = (value) => {
|
|
4727
|
+
if (value === "write") {
|
|
4728
|
+
writeFileSync(yamlPath, yamlString, "utf-8");
|
|
4729
|
+
setPhase("done");
|
|
4730
|
+
} else if (value === "edit-first") {
|
|
4731
|
+
writeFileSync(yamlPath, yamlString, "utf-8");
|
|
4732
|
+
openEditor(yamlPath);
|
|
4733
|
+
} else {
|
|
4734
|
+
onBack();
|
|
4735
|
+
}
|
|
4736
|
+
};
|
|
4737
|
+
return /* @__PURE__ */ jsxs29(Box27, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
4738
|
+
/* @__PURE__ */ jsx30(Box27, { marginBottom: 1, children: /* @__PURE__ */ jsx30(Text31, { bold: true, color: inkColors.accent, children: "Preview: polter.yaml" }) }),
|
|
4739
|
+
/* @__PURE__ */ jsx30(Box27, { flexDirection: "column", marginBottom: 1, marginLeft: panelMode ? 1 : 2, children: previewLines.map((line, i) => /* @__PURE__ */ jsx30(Text31, { dimColor: true, children: line }, i)) }),
|
|
4740
|
+
/* @__PURE__ */ jsx30(
|
|
4741
|
+
SelectList,
|
|
4742
|
+
{
|
|
4743
|
+
items: items2,
|
|
4744
|
+
onSelect: handleSelect2,
|
|
4745
|
+
onCancel: onBack,
|
|
4746
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
4747
|
+
isInputActive,
|
|
4748
|
+
arrowNavigation: panelMode,
|
|
4749
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
4750
|
+
}
|
|
4751
|
+
),
|
|
4752
|
+
!panelMode && /* @__PURE__ */ jsx30(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4753
|
+
] });
|
|
4754
|
+
}
|
|
4755
|
+
if (phase === "writing") {
|
|
4756
|
+
return /* @__PURE__ */ jsx30(Box27, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: /* @__PURE__ */ jsx30(Text31, { color: inkColors.accent, children: "Writing polter.yaml..." }) });
|
|
4757
|
+
}
|
|
4758
|
+
const items = [
|
|
4759
|
+
...onNavigate ? [{ value: "plan", label: "View plan", kind: "action" }] : [],
|
|
4760
|
+
{ value: "editor", label: "Open in editor", kind: "action" },
|
|
4761
|
+
...!panelMode ? [{ value: "__back__", label: "\u2190 Back" }] : []
|
|
4762
|
+
];
|
|
4763
|
+
const handleSelect = (value) => {
|
|
4764
|
+
if (value === "plan" && onNavigate) {
|
|
4765
|
+
onNavigate("declarative-plan");
|
|
4766
|
+
} else if (value === "editor") {
|
|
4767
|
+
openEditor(yamlPath);
|
|
4768
|
+
} else {
|
|
4769
|
+
onBack();
|
|
4770
|
+
}
|
|
4771
|
+
};
|
|
4772
|
+
return /* @__PURE__ */ jsxs29(Box27, { flexDirection: "column", paddingX: panelMode ? 1 : 0, children: [
|
|
4773
|
+
/* @__PURE__ */ jsx30(Box27, { marginBottom: 1, children: /* @__PURE__ */ jsxs29(Text31, { color: inkColors.accent, children: [
|
|
4774
|
+
"\u2713",
|
|
4775
|
+
" polter.yaml created successfully!"
|
|
4776
|
+
] }) }),
|
|
4777
|
+
/* @__PURE__ */ jsx30(
|
|
4778
|
+
SelectList,
|
|
4779
|
+
{
|
|
4780
|
+
items,
|
|
4781
|
+
onSelect: handleSelect,
|
|
4782
|
+
onCancel: onBack,
|
|
4783
|
+
width: panelMode ? Math.max(20, width - 4) : width,
|
|
4784
|
+
isInputActive,
|
|
4785
|
+
arrowNavigation: panelMode,
|
|
4786
|
+
panelFocused: panelMode ? isInputActive : void 0
|
|
4787
|
+
}
|
|
4788
|
+
),
|
|
4789
|
+
!panelMode && /* @__PURE__ */ jsx30(StatusBar, { hint: "Enter select \\u00B7 Esc back", width })
|
|
4790
|
+
] });
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4793
|
+
// src/app.tsx
|
|
4794
|
+
import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
4795
|
+
function AppClassic() {
|
|
4796
|
+
const { screen, params, navigate, goBack, goHome } = useNavigation();
|
|
4797
|
+
const { exit } = useApp();
|
|
4798
|
+
const width = useTerminalWidth();
|
|
4799
|
+
const height = useTerminalHeight();
|
|
4800
|
+
const handleExit = () => {
|
|
4801
|
+
process.stdout.write(
|
|
4802
|
+
"\n" + colors.dim("Thank you for using ") + colors.primaryBold("Polter") + colors.dim("!") + "\n\n"
|
|
3260
4803
|
);
|
|
3261
4804
|
exit();
|
|
3262
4805
|
};
|
|
3263
4806
|
const renderScreen = () => {
|
|
3264
4807
|
switch (screen) {
|
|
3265
4808
|
case "home":
|
|
3266
|
-
return /* @__PURE__ */
|
|
4809
|
+
return /* @__PURE__ */ jsx31(Home, { onNavigate: navigate, onExit: handleExit, width, height });
|
|
3267
4810
|
case "command-args":
|
|
3268
|
-
return /* @__PURE__ */
|
|
4811
|
+
return /* @__PURE__ */ jsx31(
|
|
3269
4812
|
CommandArgs,
|
|
3270
4813
|
{
|
|
3271
4814
|
command: params.command ?? "",
|
|
@@ -3276,9 +4819,9 @@ function AppClassic() {
|
|
|
3276
4819
|
}
|
|
3277
4820
|
);
|
|
3278
4821
|
case "custom-command":
|
|
3279
|
-
return /* @__PURE__ */
|
|
4822
|
+
return /* @__PURE__ */ jsx31(CustomCommand, { onNavigate: navigate, onBack: goBack, width });
|
|
3280
4823
|
case "flag-selection":
|
|
3281
|
-
return /* @__PURE__ */
|
|
4824
|
+
return /* @__PURE__ */ jsx31(
|
|
3282
4825
|
FlagSelection,
|
|
3283
4826
|
{
|
|
3284
4827
|
args: params.args ?? [],
|
|
@@ -3290,7 +4833,7 @@ function AppClassic() {
|
|
|
3290
4833
|
);
|
|
3291
4834
|
case "confirm-execute":
|
|
3292
4835
|
case "command-execution":
|
|
3293
|
-
return /* @__PURE__ */
|
|
4836
|
+
return /* @__PURE__ */ jsx31(
|
|
3294
4837
|
CommandExecution,
|
|
3295
4838
|
{
|
|
3296
4839
|
args: params.args ?? [],
|
|
@@ -3305,17 +4848,23 @@ function AppClassic() {
|
|
|
3305
4848
|
}
|
|
3306
4849
|
);
|
|
3307
4850
|
case "self-update":
|
|
3308
|
-
return /* @__PURE__ */
|
|
4851
|
+
return /* @__PURE__ */ jsx31(SelfUpdate, { onBack: goBack, onExit: handleExit, width });
|
|
3309
4852
|
case "tool-status":
|
|
3310
|
-
return /* @__PURE__ */
|
|
4853
|
+
return /* @__PURE__ */ jsx31(ToolStatus, { onBack: goBack, onNavigate: navigate, width });
|
|
4854
|
+
case "mcp-manage":
|
|
4855
|
+
return /* @__PURE__ */ jsx31(McpManage, { onBack: goBack, width });
|
|
4856
|
+
case "process-list":
|
|
4857
|
+
return /* @__PURE__ */ jsx31(ProcessList, { onNavigate: navigate, onBack: goBack, width, height });
|
|
4858
|
+
case "process-logs":
|
|
4859
|
+
return /* @__PURE__ */ jsx31(ProcessLogs, { processId: params.processId ?? "", onBack: goBack, width, height });
|
|
3311
4860
|
case "project-config":
|
|
3312
|
-
return /* @__PURE__ */
|
|
4861
|
+
return /* @__PURE__ */ jsx31(ProjectConfig, { onBack: goBack, width });
|
|
3313
4862
|
case "pipeline-list":
|
|
3314
|
-
return /* @__PURE__ */
|
|
4863
|
+
return /* @__PURE__ */ jsx31(PipelineList, { onNavigate: navigate, onBack: goBack, width });
|
|
3315
4864
|
case "pipeline-builder":
|
|
3316
|
-
return /* @__PURE__ */
|
|
4865
|
+
return /* @__PURE__ */ jsx31(PipelineBuilder, { onBack: goBack, width, height });
|
|
3317
4866
|
case "pipeline-execution":
|
|
3318
|
-
return /* @__PURE__ */
|
|
4867
|
+
return /* @__PURE__ */ jsx31(
|
|
3319
4868
|
PipelineExecution,
|
|
3320
4869
|
{
|
|
3321
4870
|
pipelineId: params.pipelineId ?? "",
|
|
@@ -3324,34 +4873,40 @@ function AppClassic() {
|
|
|
3324
4873
|
width
|
|
3325
4874
|
}
|
|
3326
4875
|
);
|
|
4876
|
+
case "declarative-plan":
|
|
4877
|
+
return /* @__PURE__ */ jsx31(DeclarativePlan, { onBack: goBack, onNavigate: navigate, width, height });
|
|
4878
|
+
case "declarative-status":
|
|
4879
|
+
return /* @__PURE__ */ jsx31(DeclarativeStatus, { onBack: goBack, width, height });
|
|
4880
|
+
case "init-scaffold":
|
|
4881
|
+
return /* @__PURE__ */ jsx31(InitScaffold, { onBack: goBack, onNavigate: navigate, width, height });
|
|
3327
4882
|
default:
|
|
3328
|
-
return /* @__PURE__ */
|
|
4883
|
+
return /* @__PURE__ */ jsx31(Box28, { children: /* @__PURE__ */ jsxs30(Text32, { color: "red", children: [
|
|
3329
4884
|
"Unknown screen: ",
|
|
3330
4885
|
screen
|
|
3331
4886
|
] }) });
|
|
3332
4887
|
}
|
|
3333
4888
|
};
|
|
3334
|
-
return /* @__PURE__ */
|
|
3335
|
-
/* @__PURE__ */
|
|
4889
|
+
return /* @__PURE__ */ jsxs30(Box28, { flexDirection: "column", children: [
|
|
4890
|
+
/* @__PURE__ */ jsx31(GhostBanner, { width }),
|
|
3336
4891
|
renderScreen()
|
|
3337
4892
|
] });
|
|
3338
4893
|
}
|
|
3339
4894
|
|
|
3340
4895
|
// src/appPanel.tsx
|
|
3341
|
-
import
|
|
3342
|
-
import { Box as
|
|
4896
|
+
import React26 from "react";
|
|
4897
|
+
import { Box as Box37, Text as Text39, useApp as useApp2, useInput as useInput12 } from "ink";
|
|
3343
4898
|
|
|
3344
4899
|
// src/hooks/usePanelNavigation.ts
|
|
3345
|
-
import { useState as
|
|
4900
|
+
import { useState as useState24, useCallback as useCallback8 } from "react";
|
|
3346
4901
|
function usePanelNavigation() {
|
|
3347
|
-
const [state, setState] =
|
|
4902
|
+
const [state, setState] = useState24({
|
|
3348
4903
|
view: "pipelines",
|
|
3349
4904
|
featureId: "database",
|
|
3350
4905
|
innerScreen: "home",
|
|
3351
4906
|
innerParams: {},
|
|
3352
4907
|
innerStack: []
|
|
3353
4908
|
});
|
|
3354
|
-
const selectSidebarItem =
|
|
4909
|
+
const selectSidebarItem = useCallback8((itemId) => {
|
|
3355
4910
|
const featureIds = [
|
|
3356
4911
|
"database",
|
|
3357
4912
|
"functions",
|
|
@@ -3360,6 +4915,7 @@ function usePanelNavigation() {
|
|
|
3360
4915
|
"cicd",
|
|
3361
4916
|
"auth-storage",
|
|
3362
4917
|
"networking",
|
|
4918
|
+
"packages",
|
|
3363
4919
|
"infrastructure",
|
|
3364
4920
|
"setup"
|
|
3365
4921
|
];
|
|
@@ -3379,7 +4935,9 @@ function usePanelNavigation() {
|
|
|
3379
4935
|
pipelines: "pipelines",
|
|
3380
4936
|
"tool-status": "tool-status",
|
|
3381
4937
|
config: "config",
|
|
3382
|
-
"self-update": "self-update"
|
|
4938
|
+
"self-update": "self-update",
|
|
4939
|
+
processes: "processes",
|
|
4940
|
+
declarative: "declarative"
|
|
3383
4941
|
};
|
|
3384
4942
|
const view = viewMap[itemId];
|
|
3385
4943
|
if (view) {
|
|
@@ -3392,7 +4950,7 @@ function usePanelNavigation() {
|
|
|
3392
4950
|
});
|
|
3393
4951
|
}
|
|
3394
4952
|
}, [state.featureId]);
|
|
3395
|
-
const navigateInner =
|
|
4953
|
+
const navigateInner = useCallback8((screen, params) => {
|
|
3396
4954
|
setState((prev) => ({
|
|
3397
4955
|
...prev,
|
|
3398
4956
|
innerStack: [...prev.innerStack, { screen: prev.innerScreen, params: prev.innerParams }],
|
|
@@ -3400,7 +4958,7 @@ function usePanelNavigation() {
|
|
|
3400
4958
|
innerParams: params ?? {}
|
|
3401
4959
|
}));
|
|
3402
4960
|
}, []);
|
|
3403
|
-
const goBackInner =
|
|
4961
|
+
const goBackInner = useCallback8(() => {
|
|
3404
4962
|
setState((prev) => {
|
|
3405
4963
|
if (prev.innerStack.length === 0) {
|
|
3406
4964
|
return { ...prev, innerScreen: "home", innerParams: {} };
|
|
@@ -3415,7 +4973,7 @@ function usePanelNavigation() {
|
|
|
3415
4973
|
};
|
|
3416
4974
|
});
|
|
3417
4975
|
}, []);
|
|
3418
|
-
const goHomeInner =
|
|
4976
|
+
const goHomeInner = useCallback8(() => {
|
|
3419
4977
|
setState((prev) => ({
|
|
3420
4978
|
...prev,
|
|
3421
4979
|
innerScreen: "home",
|
|
@@ -3423,7 +4981,7 @@ function usePanelNavigation() {
|
|
|
3423
4981
|
innerStack: []
|
|
3424
4982
|
}));
|
|
3425
4983
|
}, []);
|
|
3426
|
-
const switchViewAndNavigate =
|
|
4984
|
+
const switchViewAndNavigate = useCallback8(
|
|
3427
4985
|
(view, screen, params) => {
|
|
3428
4986
|
setState((prev) => ({
|
|
3429
4987
|
...prev,
|
|
@@ -3446,14 +5004,14 @@ function usePanelNavigation() {
|
|
|
3446
5004
|
}
|
|
3447
5005
|
|
|
3448
5006
|
// src/hooks/usePanelFocus.ts
|
|
3449
|
-
import { useState as
|
|
5007
|
+
import { useState as useState25, useCallback as useCallback9 } from "react";
|
|
3450
5008
|
function usePanelFocus() {
|
|
3451
|
-
const [focused, setFocused] =
|
|
3452
|
-
const toggleFocus =
|
|
5009
|
+
const [focused, setFocused] = useState25("sidebar");
|
|
5010
|
+
const toggleFocus = useCallback9(() => {
|
|
3453
5011
|
setFocused((prev) => prev === "sidebar" ? "main" : "sidebar");
|
|
3454
5012
|
}, []);
|
|
3455
|
-
const focusSidebar =
|
|
3456
|
-
const focusMain =
|
|
5013
|
+
const focusSidebar = useCallback9(() => setFocused("sidebar"), []);
|
|
5014
|
+
const focusMain = useCallback9(() => setFocused("main"), []);
|
|
3457
5015
|
return {
|
|
3458
5016
|
focused,
|
|
3459
5017
|
isSidebarFocused: focused === "sidebar",
|
|
@@ -3473,6 +5031,7 @@ function useSidebarItems() {
|
|
|
3473
5031
|
items.push({ id: "pipelines", label: "Pipelines", icon: "\u{1F517}", type: "action", section: "workflows" });
|
|
3474
5032
|
items.push({ id: "pinned", label: "Pinned", icon: "\u{1F4CC}", type: "action", section: "workflows" });
|
|
3475
5033
|
items.push({ id: "custom-command", label: "Custom Cmd", icon: "\u270F\uFE0F", type: "action", section: "workflows" });
|
|
5034
|
+
items.push({ id: "processes", label: "Processes", icon: "\u{1F4BB}", type: "action", section: "workflows" });
|
|
3476
5035
|
items.push({ id: "__sep_features__", label: "---", icon: "", type: "separator", sectionTitle: "Features" });
|
|
3477
5036
|
for (const feature of features) {
|
|
3478
5037
|
items.push({
|
|
@@ -3484,6 +5043,7 @@ function useSidebarItems() {
|
|
|
3484
5043
|
});
|
|
3485
5044
|
}
|
|
3486
5045
|
items.push({ id: "__sep_system__", label: "---", icon: "", type: "separator", sectionTitle: "System" });
|
|
5046
|
+
items.push({ id: "declarative", label: "Infrastructure", icon: "\u{1F3D7}\uFE0F", type: "action", section: "system" });
|
|
3487
5047
|
items.push({ id: "tool-status", label: "Tool Status", icon: "\u{1F527}", type: "action", section: "system" });
|
|
3488
5048
|
items.push({ id: "config", label: "Config", icon: "\u2699\uFE0F", type: "action", section: "system" });
|
|
3489
5049
|
items.push({ id: "self-update", label: "Update", icon: "\u2B06\uFE0F", type: "action", section: "system" });
|
|
@@ -3492,13 +5052,13 @@ function useSidebarItems() {
|
|
|
3492
5052
|
}
|
|
3493
5053
|
|
|
3494
5054
|
// src/hooks/useModal.ts
|
|
3495
|
-
import { useState as
|
|
5055
|
+
import { useState as useState26, useCallback as useCallback10 } from "react";
|
|
3496
5056
|
function useModal() {
|
|
3497
|
-
const [state, setState] =
|
|
3498
|
-
const openModal =
|
|
5057
|
+
const [state, setState] = useState26(null);
|
|
5058
|
+
const openModal = useCallback10((content, title) => {
|
|
3499
5059
|
setState({ content, title });
|
|
3500
5060
|
}, []);
|
|
3501
|
-
const closeModal =
|
|
5061
|
+
const closeModal = useCallback10(() => {
|
|
3502
5062
|
setState(null);
|
|
3503
5063
|
}, []);
|
|
3504
5064
|
return {
|
|
@@ -3511,8 +5071,8 @@ function useModal() {
|
|
|
3511
5071
|
}
|
|
3512
5072
|
|
|
3513
5073
|
// src/components/PanelLayout.tsx
|
|
3514
|
-
import { Box as
|
|
3515
|
-
import { jsx as
|
|
5074
|
+
import { Box as Box29 } from "ink";
|
|
5075
|
+
import { jsx as jsx32, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3516
5076
|
function PanelLayout({
|
|
3517
5077
|
header,
|
|
3518
5078
|
footer,
|
|
@@ -3527,19 +5087,19 @@ function PanelLayout({
|
|
|
3527
5087
|
const contentHeight = Math.max(5, height - bannerHeight - footerHeight);
|
|
3528
5088
|
const sidebarWidth = singlePanel ? 0 : panel.sidebarWidth(width);
|
|
3529
5089
|
const mainWidth = singlePanel ? width : width - sidebarWidth;
|
|
3530
|
-
return /* @__PURE__ */
|
|
5090
|
+
return /* @__PURE__ */ jsxs31(Box29, { flexDirection: "column", width, height, children: [
|
|
3531
5091
|
header,
|
|
3532
|
-
/* @__PURE__ */
|
|
3533
|
-
!singlePanel && /* @__PURE__ */
|
|
3534
|
-
/* @__PURE__ */
|
|
5092
|
+
/* @__PURE__ */ jsxs31(Box29, { flexDirection: "row", height: contentHeight, children: [
|
|
5093
|
+
!singlePanel && /* @__PURE__ */ jsx32(Box29, { width: sidebarWidth, height: contentHeight, children: sidebar }),
|
|
5094
|
+
/* @__PURE__ */ jsx32(Box29, { width: mainWidth, height: contentHeight, children: main2 })
|
|
3535
5095
|
] }),
|
|
3536
|
-
/* @__PURE__ */
|
|
5096
|
+
/* @__PURE__ */ jsx32(Box29, { height: footerHeight, children: footer })
|
|
3537
5097
|
] });
|
|
3538
5098
|
}
|
|
3539
5099
|
|
|
3540
5100
|
// src/components/Panel.tsx
|
|
3541
|
-
import { Box as
|
|
3542
|
-
import { jsx as
|
|
5101
|
+
import { Box as Box30, Text as Text33 } from "ink";
|
|
5102
|
+
import { jsx as jsx33, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3543
5103
|
function Panel({
|
|
3544
5104
|
id,
|
|
3545
5105
|
title,
|
|
@@ -3549,8 +5109,8 @@ function Panel({
|
|
|
3549
5109
|
children
|
|
3550
5110
|
}) {
|
|
3551
5111
|
const borderColor = focused ? panel.borderFocused : panel.borderDim;
|
|
3552
|
-
return /* @__PURE__ */
|
|
3553
|
-
|
|
5112
|
+
return /* @__PURE__ */ jsxs32(
|
|
5113
|
+
Box30,
|
|
3554
5114
|
{
|
|
3555
5115
|
flexDirection: "column",
|
|
3556
5116
|
width,
|
|
@@ -3559,21 +5119,21 @@ function Panel({
|
|
|
3559
5119
|
borderColor,
|
|
3560
5120
|
overflow: "hidden",
|
|
3561
5121
|
children: [
|
|
3562
|
-
title && /* @__PURE__ */
|
|
5122
|
+
title && /* @__PURE__ */ jsx33(Box30, { marginBottom: 0, children: /* @__PURE__ */ jsxs32(Text33, { color: focused ? inkColors.accent : void 0, bold: focused, dimColor: !focused, children: [
|
|
3563
5123
|
" ",
|
|
3564
5124
|
title,
|
|
3565
5125
|
" "
|
|
3566
5126
|
] }) }),
|
|
3567
|
-
/* @__PURE__ */
|
|
5127
|
+
/* @__PURE__ */ jsx33(Box30, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children })
|
|
3568
5128
|
]
|
|
3569
5129
|
}
|
|
3570
5130
|
);
|
|
3571
5131
|
}
|
|
3572
5132
|
|
|
3573
5133
|
// src/components/Sidebar.tsx
|
|
3574
|
-
import { useEffect as
|
|
3575
|
-
import { Box as
|
|
3576
|
-
import { jsx as
|
|
5134
|
+
import { useEffect as useEffect16, useMemo as useMemo9, useState as useState27 } from "react";
|
|
5135
|
+
import { Box as Box31, Text as Text34, useInput as useInput11 } from "ink";
|
|
5136
|
+
import { jsx as jsx34, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3577
5137
|
function groupSections(items) {
|
|
3578
5138
|
const groups = [];
|
|
3579
5139
|
let current = null;
|
|
@@ -3600,13 +5160,13 @@ function Sidebar({
|
|
|
3600
5160
|
[items]
|
|
3601
5161
|
);
|
|
3602
5162
|
const selectedIdx = selectableItems.findIndex((item) => item.id === selectedId);
|
|
3603
|
-
const [cursorIdx, setCursorIdx] =
|
|
5163
|
+
const [cursorIdx, setCursorIdx] = useState27(Math.max(0, selectedIdx));
|
|
3604
5164
|
const sections = useMemo9(() => groupSections(items), [items]);
|
|
3605
|
-
|
|
5165
|
+
useEffect16(() => {
|
|
3606
5166
|
const idx = selectableItems.findIndex((item) => item.id === selectedId);
|
|
3607
5167
|
if (idx >= 0) setCursorIdx(idx);
|
|
3608
5168
|
}, [selectedId, selectableItems]);
|
|
3609
|
-
|
|
5169
|
+
useInput11(
|
|
3610
5170
|
(input2, key) => {
|
|
3611
5171
|
if (key.upArrow || input2 === "k") {
|
|
3612
5172
|
setCursorIdx((prev) => {
|
|
@@ -3634,28 +5194,28 @@ function Sidebar({
|
|
|
3634
5194
|
{ isActive: isFocused }
|
|
3635
5195
|
);
|
|
3636
5196
|
let flatIdx = 0;
|
|
3637
|
-
return /* @__PURE__ */
|
|
5197
|
+
return /* @__PURE__ */ jsx34(Box31, { flexDirection: "column", gap: 0, children: sections.map((section) => {
|
|
3638
5198
|
const sectionStartIdx = flatIdx;
|
|
3639
5199
|
const sectionEndIdx = sectionStartIdx + section.items.length - 1;
|
|
3640
5200
|
const hasCursorInSection = isFocused && cursorIdx >= sectionStartIdx && cursorIdx <= sectionEndIdx;
|
|
3641
5201
|
const hasActiveInSection = section.items.some((item) => item.id === selectedId);
|
|
3642
5202
|
const borderColor = hasCursorInSection || hasActiveInSection ? inkColors.accent : "#555555";
|
|
3643
|
-
const rendered = /* @__PURE__ */
|
|
3644
|
-
|
|
5203
|
+
const rendered = /* @__PURE__ */ jsxs33(
|
|
5204
|
+
Box31,
|
|
3645
5205
|
{
|
|
3646
5206
|
flexDirection: "column",
|
|
3647
5207
|
borderStyle: "round",
|
|
3648
5208
|
borderColor,
|
|
3649
5209
|
paddingX: 1,
|
|
3650
5210
|
children: [
|
|
3651
|
-
/* @__PURE__ */
|
|
5211
|
+
/* @__PURE__ */ jsx34(Text34, { dimColor: true, bold: true, children: section.title }),
|
|
3652
5212
|
section.items.map((item) => {
|
|
3653
5213
|
const thisIdx = flatIdx;
|
|
3654
5214
|
flatIdx++;
|
|
3655
5215
|
const isCursor = isFocused && thisIdx === cursorIdx;
|
|
3656
5216
|
const isActive = item.id === selectedId;
|
|
3657
|
-
return /* @__PURE__ */
|
|
3658
|
-
|
|
5217
|
+
return /* @__PURE__ */ jsx34(Box31, { gap: 0, children: /* @__PURE__ */ jsxs33(
|
|
5218
|
+
Text34,
|
|
3659
5219
|
{
|
|
3660
5220
|
color: isCursor ? inkColors.accent : isActive ? inkColors.accent : void 0,
|
|
3661
5221
|
bold: isCursor || isActive,
|
|
@@ -3678,12 +5238,12 @@ function Sidebar({
|
|
|
3678
5238
|
}
|
|
3679
5239
|
|
|
3680
5240
|
// src/components/PanelFooter.tsx
|
|
3681
|
-
import { Box as
|
|
3682
|
-
import { jsx as
|
|
5241
|
+
import { Box as Box32, Text as Text35 } from "ink";
|
|
5242
|
+
import { jsx as jsx35, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3683
5243
|
function PanelFooter({ hints, width }) {
|
|
3684
|
-
return /* @__PURE__ */
|
|
3685
|
-
/* @__PURE__ */
|
|
3686
|
-
/* @__PURE__ */
|
|
5244
|
+
return /* @__PURE__ */ jsx35(Box32, { width, children: /* @__PURE__ */ jsx35(Box32, { gap: 1, children: hints.map((hint) => /* @__PURE__ */ jsxs34(Box32, { gap: 0, children: [
|
|
5245
|
+
/* @__PURE__ */ jsx35(Text35, { color: inkColors.accent, bold: true, children: hint.key }),
|
|
5246
|
+
/* @__PURE__ */ jsxs34(Text35, { dimColor: true, children: [
|
|
3687
5247
|
":",
|
|
3688
5248
|
hint.action
|
|
3689
5249
|
] })
|
|
@@ -3691,8 +5251,8 @@ function PanelFooter({ hints, width }) {
|
|
|
3691
5251
|
}
|
|
3692
5252
|
|
|
3693
5253
|
// src/components/Modal.tsx
|
|
3694
|
-
import { Box as
|
|
3695
|
-
import { jsx as
|
|
5254
|
+
import { Box as Box33, Text as Text36 } from "ink";
|
|
5255
|
+
import { jsx as jsx36, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3696
5256
|
function Modal({
|
|
3697
5257
|
title,
|
|
3698
5258
|
width,
|
|
@@ -3703,10 +5263,10 @@ function Modal({
|
|
|
3703
5263
|
const modalHeight = Math.min(height - 4, 20);
|
|
3704
5264
|
const padX = Math.max(0, Math.floor((width - modalWidth) / 2));
|
|
3705
5265
|
const padY = Math.max(0, Math.floor((height - modalHeight) / 2));
|
|
3706
|
-
return /* @__PURE__ */
|
|
3707
|
-
padY > 0 && /* @__PURE__ */
|
|
3708
|
-
/* @__PURE__ */
|
|
3709
|
-
|
|
5266
|
+
return /* @__PURE__ */ jsxs35(Box33, { flexDirection: "column", width, height, children: [
|
|
5267
|
+
padY > 0 && /* @__PURE__ */ jsx36(Box33, { height: padY }),
|
|
5268
|
+
/* @__PURE__ */ jsx36(Box33, { marginLeft: padX, children: /* @__PURE__ */ jsxs35(
|
|
5269
|
+
Box33,
|
|
3710
5270
|
{
|
|
3711
5271
|
flexDirection: "column",
|
|
3712
5272
|
width: modalWidth,
|
|
@@ -3715,8 +5275,8 @@ function Modal({
|
|
|
3715
5275
|
borderColor: inkColors.accent,
|
|
3716
5276
|
paddingX: 1,
|
|
3717
5277
|
children: [
|
|
3718
|
-
/* @__PURE__ */
|
|
3719
|
-
/* @__PURE__ */
|
|
5278
|
+
/* @__PURE__ */ jsx36(Box33, { marginBottom: 1, children: /* @__PURE__ */ jsx36(Text36, { color: inkColors.accent, bold: true, children: title }) }),
|
|
5279
|
+
/* @__PURE__ */ jsx36(Box33, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children })
|
|
3720
5280
|
]
|
|
3721
5281
|
}
|
|
3722
5282
|
) })
|
|
@@ -3724,9 +5284,9 @@ function Modal({
|
|
|
3724
5284
|
}
|
|
3725
5285
|
|
|
3726
5286
|
// src/components/FeatureCommands.tsx
|
|
3727
|
-
import { useEffect as
|
|
3728
|
-
import { Box as
|
|
3729
|
-
import { jsx as
|
|
5287
|
+
import { useEffect as useEffect17, useMemo as useMemo10, useState as useState28 } from "react";
|
|
5288
|
+
import { Box as Box34, Text as Text37 } from "ink";
|
|
5289
|
+
import { jsx as jsx37, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3730
5290
|
function FeatureCommands({
|
|
3731
5291
|
feature,
|
|
3732
5292
|
onNavigate,
|
|
@@ -3737,10 +5297,10 @@ function FeatureCommands({
|
|
|
3737
5297
|
height = 24,
|
|
3738
5298
|
isInputActive = true
|
|
3739
5299
|
}) {
|
|
3740
|
-
const [pinnedCommands, setPinnedCommands2] =
|
|
3741
|
-
const [pinnedRuns, setPinnedRuns2] =
|
|
3742
|
-
const [pinFeedback, setPinFeedback] =
|
|
3743
|
-
|
|
5300
|
+
const [pinnedCommands, setPinnedCommands2] = useState28(() => getPinnedCommands());
|
|
5301
|
+
const [pinnedRuns, setPinnedRuns2] = useState28(() => getPinnedRuns());
|
|
5302
|
+
const [pinFeedback, setPinFeedback] = useState28();
|
|
5303
|
+
useEffect17(() => {
|
|
3744
5304
|
if (!pinFeedback) return;
|
|
3745
5305
|
const timeout = setTimeout(() => setPinFeedback(void 0), 1400);
|
|
3746
5306
|
return () => clearTimeout(timeout);
|
|
@@ -3808,12 +5368,12 @@ function FeatureCommands({
|
|
|
3808
5368
|
);
|
|
3809
5369
|
}
|
|
3810
5370
|
};
|
|
3811
|
-
return /* @__PURE__ */
|
|
3812
|
-
pinFeedback && /* @__PURE__ */
|
|
5371
|
+
return /* @__PURE__ */ jsxs36(Box34, { flexDirection: "column", paddingX: 1, children: [
|
|
5372
|
+
pinFeedback && /* @__PURE__ */ jsx37(Box34, { marginBottom: 1, children: /* @__PURE__ */ jsxs36(Text37, { color: inkColors.accent, children: [
|
|
3813
5373
|
"\u2713 ",
|
|
3814
5374
|
pinFeedback
|
|
3815
5375
|
] }) }),
|
|
3816
|
-
/* @__PURE__ */
|
|
5376
|
+
/* @__PURE__ */ jsx37(
|
|
3817
5377
|
SelectList,
|
|
3818
5378
|
{
|
|
3819
5379
|
items,
|
|
@@ -3832,9 +5392,9 @@ function FeatureCommands({
|
|
|
3832
5392
|
}
|
|
3833
5393
|
|
|
3834
5394
|
// src/components/PinnedCommands.tsx
|
|
3835
|
-
import { useEffect as
|
|
3836
|
-
import { Box as
|
|
3837
|
-
import { jsx as
|
|
5395
|
+
import { useEffect as useEffect18, useMemo as useMemo11, useState as useState29 } from "react";
|
|
5396
|
+
import { Box as Box35, Text as Text38 } from "ink";
|
|
5397
|
+
import { jsx as jsx38, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
3838
5398
|
function PinnedCommands({
|
|
3839
5399
|
onNavigate,
|
|
3840
5400
|
onBack,
|
|
@@ -3843,10 +5403,10 @@ function PinnedCommands({
|
|
|
3843
5403
|
height = 24,
|
|
3844
5404
|
isInputActive = true
|
|
3845
5405
|
}) {
|
|
3846
|
-
const [pinnedCommands, setPinnedCommands2] =
|
|
3847
|
-
const [pinnedRuns, setPinnedRuns2] =
|
|
3848
|
-
const [pinFeedback, setPinFeedback] =
|
|
3849
|
-
|
|
5406
|
+
const [pinnedCommands, setPinnedCommands2] = useState29(() => getPinnedCommands());
|
|
5407
|
+
const [pinnedRuns, setPinnedRuns2] = useState29(() => getPinnedRuns());
|
|
5408
|
+
const [pinFeedback, setPinFeedback] = useState29();
|
|
5409
|
+
useEffect18(() => {
|
|
3850
5410
|
if (!pinFeedback) return;
|
|
3851
5411
|
const timeout = setTimeout(() => setPinFeedback(void 0), 1400);
|
|
3852
5412
|
return () => clearTimeout(timeout);
|
|
@@ -3908,14 +5468,14 @@ function PinnedCommands({
|
|
|
3908
5468
|
}
|
|
3909
5469
|
};
|
|
3910
5470
|
if (items.length === 0) {
|
|
3911
|
-
return /* @__PURE__ */
|
|
5471
|
+
return /* @__PURE__ */ jsx38(Box35, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx38(Text38, { color: "gray", children: "No pinned items. Press p on any command to pin it." }) });
|
|
3912
5472
|
}
|
|
3913
|
-
return /* @__PURE__ */
|
|
3914
|
-
pinFeedback && /* @__PURE__ */
|
|
5473
|
+
return /* @__PURE__ */ jsxs37(Box35, { flexDirection: "column", paddingX: 1, children: [
|
|
5474
|
+
pinFeedback && /* @__PURE__ */ jsx38(Box35, { marginBottom: 1, children: /* @__PURE__ */ jsxs37(Text38, { color: inkColors.accent, children: [
|
|
3915
5475
|
"\u2713 ",
|
|
3916
5476
|
pinFeedback
|
|
3917
5477
|
] }) }),
|
|
3918
|
-
/* @__PURE__ */
|
|
5478
|
+
/* @__PURE__ */ jsx38(
|
|
3919
5479
|
SelectList,
|
|
3920
5480
|
{
|
|
3921
5481
|
items,
|
|
@@ -3933,8 +5493,43 @@ function PinnedCommands({
|
|
|
3933
5493
|
] });
|
|
3934
5494
|
}
|
|
3935
5495
|
|
|
5496
|
+
// src/screens/DeclarativeHome.tsx
|
|
5497
|
+
import { useMemo as useMemo12 } from "react";
|
|
5498
|
+
import { Box as Box36 } from "ink";
|
|
5499
|
+
import { jsx as jsx39 } from "react/jsx-runtime";
|
|
5500
|
+
var ITEMS = [
|
|
5501
|
+
{ value: "declarative-plan", label: "Plan / Apply", hint: "Diff and apply polter.yaml", kind: "action" },
|
|
5502
|
+
{ value: "declarative-status", label: "Infrastructure Status", hint: "Live state from CLI tools", kind: "action" },
|
|
5503
|
+
{ value: "init-scaffold", label: "Init polter.yaml", hint: "Generate from detected state", kind: "action" }
|
|
5504
|
+
];
|
|
5505
|
+
function DeclarativeHome({
|
|
5506
|
+
onNavigate,
|
|
5507
|
+
onBack,
|
|
5508
|
+
width = 80,
|
|
5509
|
+
height = 24,
|
|
5510
|
+
isInputActive = true
|
|
5511
|
+
}) {
|
|
5512
|
+
const handleSelect = useMemo12(
|
|
5513
|
+
() => (value) => onNavigate(value),
|
|
5514
|
+
[onNavigate]
|
|
5515
|
+
);
|
|
5516
|
+
return /* @__PURE__ */ jsx39(Box36, { flexDirection: "column", paddingX: 1, children: /* @__PURE__ */ jsx39(
|
|
5517
|
+
SelectList,
|
|
5518
|
+
{
|
|
5519
|
+
items: ITEMS,
|
|
5520
|
+
onSelect: handleSelect,
|
|
5521
|
+
onCancel: onBack,
|
|
5522
|
+
width: Math.max(20, width - 4),
|
|
5523
|
+
maxVisible: Math.max(6, height - 4),
|
|
5524
|
+
isInputActive,
|
|
5525
|
+
arrowNavigation: true,
|
|
5526
|
+
panelFocused: isInputActive
|
|
5527
|
+
}
|
|
5528
|
+
) });
|
|
5529
|
+
}
|
|
5530
|
+
|
|
3936
5531
|
// src/appPanel.tsx
|
|
3937
|
-
import { jsx as
|
|
5532
|
+
import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3938
5533
|
var screenLabels = {
|
|
3939
5534
|
"command-args": "Args",
|
|
3940
5535
|
"flag-selection": "Flags",
|
|
@@ -3946,7 +5541,13 @@ var screenLabels = {
|
|
|
3946
5541
|
"pipeline-execution": "Run",
|
|
3947
5542
|
"self-update": "Update",
|
|
3948
5543
|
"tool-status": "Status",
|
|
3949
|
-
"project-config": "Config"
|
|
5544
|
+
"project-config": "Config",
|
|
5545
|
+
"mcp-manage": "MCP",
|
|
5546
|
+
"process-list": "Processes",
|
|
5547
|
+
"process-logs": "Logs",
|
|
5548
|
+
"declarative-plan": "Plan/Apply",
|
|
5549
|
+
"declarative-status": "Status",
|
|
5550
|
+
"init-scaffold": "Init"
|
|
3950
5551
|
};
|
|
3951
5552
|
function buildBreadcrumb(nav) {
|
|
3952
5553
|
let base;
|
|
@@ -3974,6 +5575,12 @@ function buildBreadcrumb(nav) {
|
|
|
3974
5575
|
case "self-update":
|
|
3975
5576
|
base = "\u2B06\uFE0F Update";
|
|
3976
5577
|
break;
|
|
5578
|
+
case "processes":
|
|
5579
|
+
base = "\u{1F4BB} Processes";
|
|
5580
|
+
break;
|
|
5581
|
+
case "declarative":
|
|
5582
|
+
base = "\u{1F3D7}\uFE0F Infrastructure";
|
|
5583
|
+
break;
|
|
3977
5584
|
default:
|
|
3978
5585
|
base = nav.view;
|
|
3979
5586
|
}
|
|
@@ -4006,7 +5613,7 @@ function AppPanel() {
|
|
|
4006
5613
|
const focus = usePanelFocus();
|
|
4007
5614
|
const sidebarItems = useSidebarItems();
|
|
4008
5615
|
const modal = useModal();
|
|
4009
|
-
const refreshPins =
|
|
5616
|
+
const refreshPins = React26.useCallback(() => {
|
|
4010
5617
|
}, []);
|
|
4011
5618
|
const singlePanel = width < 60 || height < 15;
|
|
4012
5619
|
const handleExit = () => {
|
|
@@ -4015,7 +5622,7 @@ function AppPanel() {
|
|
|
4015
5622
|
);
|
|
4016
5623
|
exit();
|
|
4017
5624
|
};
|
|
4018
|
-
|
|
5625
|
+
useInput12((input2, key) => {
|
|
4019
5626
|
if (modal.isOpen) {
|
|
4020
5627
|
if (key.escape || input2 === "q") {
|
|
4021
5628
|
modal.closeModal();
|
|
@@ -4040,37 +5647,37 @@ function AppPanel() {
|
|
|
4040
5647
|
}
|
|
4041
5648
|
if (input2 === "?") {
|
|
4042
5649
|
modal.openModal(
|
|
4043
|
-
/* @__PURE__ */
|
|
4044
|
-
/* @__PURE__ */
|
|
4045
|
-
/* @__PURE__ */
|
|
5650
|
+
/* @__PURE__ */ jsxs38(Box37, { flexDirection: "column", children: [
|
|
5651
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5652
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "\u2190/\u2192" }),
|
|
4046
5653
|
" Move between sidebar and main panel"
|
|
4047
5654
|
] }),
|
|
4048
|
-
/* @__PURE__ */
|
|
4049
|
-
/* @__PURE__ */
|
|
5655
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5656
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "Tab" }),
|
|
4050
5657
|
" Toggle sidebar / main panel"
|
|
4051
5658
|
] }),
|
|
4052
|
-
/* @__PURE__ */
|
|
4053
|
-
/* @__PURE__ */
|
|
5659
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5660
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "j/k" }),
|
|
4054
5661
|
" Navigate up/down"
|
|
4055
5662
|
] }),
|
|
4056
|
-
/* @__PURE__ */
|
|
4057
|
-
/* @__PURE__ */
|
|
5663
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5664
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "Enter" }),
|
|
4058
5665
|
" Select item"
|
|
4059
5666
|
] }),
|
|
4060
|
-
/* @__PURE__ */
|
|
4061
|
-
/* @__PURE__ */
|
|
5667
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5668
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "Esc" }),
|
|
4062
5669
|
" Go back (or return to sidebar)"
|
|
4063
5670
|
] }),
|
|
4064
|
-
/* @__PURE__ */
|
|
4065
|
-
/* @__PURE__ */
|
|
5671
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5672
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "q" }),
|
|
4066
5673
|
" Quit Polter"
|
|
4067
5674
|
] }),
|
|
4068
|
-
/* @__PURE__ */
|
|
4069
|
-
/* @__PURE__ */
|
|
5675
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5676
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "?" }),
|
|
4070
5677
|
" Show this help"
|
|
4071
5678
|
] }),
|
|
4072
|
-
/* @__PURE__ */
|
|
4073
|
-
/* @__PURE__ */
|
|
5679
|
+
/* @__PURE__ */ jsxs38(Text39, { children: [
|
|
5680
|
+
/* @__PURE__ */ jsx40(Text39, { bold: true, children: "p" }),
|
|
4074
5681
|
" Pin/unpin command"
|
|
4075
5682
|
] })
|
|
4076
5683
|
] }),
|
|
@@ -4094,6 +5701,10 @@ function AppPanel() {
|
|
|
4094
5701
|
return "config";
|
|
4095
5702
|
case "self-update":
|
|
4096
5703
|
return "self-update";
|
|
5704
|
+
case "processes":
|
|
5705
|
+
return "processes";
|
|
5706
|
+
case "declarative":
|
|
5707
|
+
return "declarative";
|
|
4097
5708
|
default:
|
|
4098
5709
|
return nav.featureId;
|
|
4099
5710
|
}
|
|
@@ -4110,7 +5721,7 @@ function AppPanel() {
|
|
|
4110
5721
|
nav.selectSidebarItem(itemId);
|
|
4111
5722
|
focus.focusMain();
|
|
4112
5723
|
};
|
|
4113
|
-
const bannerHeight = width < 60 ?
|
|
5724
|
+
const bannerHeight = width < 60 ? 6 : 10;
|
|
4114
5725
|
const footerHints = FOOTER_HINTS;
|
|
4115
5726
|
const mainContentHeight = Math.max(5, height - bannerHeight - 1 - 2);
|
|
4116
5727
|
const mainContentWidth = singlePanel ? width : width - Math.max(20, Math.min(35, Math.floor(width * 0.3)));
|
|
@@ -4120,7 +5731,7 @@ function AppPanel() {
|
|
|
4120
5731
|
}
|
|
4121
5732
|
switch (nav.view) {
|
|
4122
5733
|
case "pinned":
|
|
4123
|
-
return /* @__PURE__ */
|
|
5734
|
+
return /* @__PURE__ */ jsx40(
|
|
4124
5735
|
PinnedCommands,
|
|
4125
5736
|
{
|
|
4126
5737
|
onNavigate: nav.navigateInner,
|
|
@@ -4134,12 +5745,12 @@ function AppPanel() {
|
|
|
4134
5745
|
case "feature": {
|
|
4135
5746
|
const feature = getFeatureById(nav.featureId);
|
|
4136
5747
|
if (!feature) {
|
|
4137
|
-
return /* @__PURE__ */
|
|
5748
|
+
return /* @__PURE__ */ jsxs38(Text39, { color: "red", children: [
|
|
4138
5749
|
"Feature not found: ",
|
|
4139
5750
|
nav.featureId
|
|
4140
5751
|
] });
|
|
4141
5752
|
}
|
|
4142
|
-
return /* @__PURE__ */
|
|
5753
|
+
return /* @__PURE__ */ jsx40(
|
|
4143
5754
|
FeatureCommands,
|
|
4144
5755
|
{
|
|
4145
5756
|
feature,
|
|
@@ -4154,7 +5765,7 @@ function AppPanel() {
|
|
|
4154
5765
|
);
|
|
4155
5766
|
}
|
|
4156
5767
|
case "custom-command":
|
|
4157
|
-
return /* @__PURE__ */
|
|
5768
|
+
return /* @__PURE__ */ jsx40(
|
|
4158
5769
|
CustomCommand,
|
|
4159
5770
|
{
|
|
4160
5771
|
onNavigate: nav.navigateInner,
|
|
@@ -4166,7 +5777,7 @@ function AppPanel() {
|
|
|
4166
5777
|
}
|
|
4167
5778
|
);
|
|
4168
5779
|
case "pipelines":
|
|
4169
|
-
return /* @__PURE__ */
|
|
5780
|
+
return /* @__PURE__ */ jsx40(
|
|
4170
5781
|
PipelineList,
|
|
4171
5782
|
{
|
|
4172
5783
|
onNavigate: nav.navigateInner,
|
|
@@ -4178,9 +5789,22 @@ function AppPanel() {
|
|
|
4178
5789
|
}
|
|
4179
5790
|
);
|
|
4180
5791
|
case "tool-status":
|
|
4181
|
-
return /* @__PURE__ */
|
|
5792
|
+
return /* @__PURE__ */ jsx40(
|
|
4182
5793
|
ToolStatus,
|
|
4183
5794
|
{
|
|
5795
|
+
onBack: focus.focusSidebar,
|
|
5796
|
+
onNavigate: nav.navigateInner,
|
|
5797
|
+
width: mainContentWidth - 2,
|
|
5798
|
+
height: mainContentHeight,
|
|
5799
|
+
panelMode: true,
|
|
5800
|
+
isInputActive: focus.isMainFocused
|
|
5801
|
+
}
|
|
5802
|
+
);
|
|
5803
|
+
case "processes":
|
|
5804
|
+
return /* @__PURE__ */ jsx40(
|
|
5805
|
+
ProcessList,
|
|
5806
|
+
{
|
|
5807
|
+
onNavigate: nav.navigateInner,
|
|
4184
5808
|
onBack: focus.focusSidebar,
|
|
4185
5809
|
width: mainContentWidth - 2,
|
|
4186
5810
|
height: mainContentHeight,
|
|
@@ -4188,8 +5812,19 @@ function AppPanel() {
|
|
|
4188
5812
|
isInputActive: focus.isMainFocused
|
|
4189
5813
|
}
|
|
4190
5814
|
);
|
|
5815
|
+
case "declarative":
|
|
5816
|
+
return /* @__PURE__ */ jsx40(
|
|
5817
|
+
DeclarativeHome,
|
|
5818
|
+
{
|
|
5819
|
+
onNavigate: nav.navigateInner,
|
|
5820
|
+
onBack: focus.focusSidebar,
|
|
5821
|
+
width: mainContentWidth - 2,
|
|
5822
|
+
height: mainContentHeight,
|
|
5823
|
+
isInputActive: focus.isMainFocused
|
|
5824
|
+
}
|
|
5825
|
+
);
|
|
4191
5826
|
case "config":
|
|
4192
|
-
return /* @__PURE__ */
|
|
5827
|
+
return /* @__PURE__ */ jsx40(
|
|
4193
5828
|
ProjectConfig,
|
|
4194
5829
|
{
|
|
4195
5830
|
onBack: focus.focusSidebar,
|
|
@@ -4200,7 +5835,7 @@ function AppPanel() {
|
|
|
4200
5835
|
}
|
|
4201
5836
|
);
|
|
4202
5837
|
case "self-update":
|
|
4203
|
-
return /* @__PURE__ */
|
|
5838
|
+
return /* @__PURE__ */ jsx40(
|
|
4204
5839
|
SelfUpdate,
|
|
4205
5840
|
{
|
|
4206
5841
|
onBack: focus.focusSidebar,
|
|
@@ -4212,7 +5847,7 @@ function AppPanel() {
|
|
|
4212
5847
|
}
|
|
4213
5848
|
);
|
|
4214
5849
|
default:
|
|
4215
|
-
return /* @__PURE__ */
|
|
5850
|
+
return /* @__PURE__ */ jsx40(Text39, { children: "Select an item from the sidebar" });
|
|
4216
5851
|
}
|
|
4217
5852
|
};
|
|
4218
5853
|
const renderInnerScreen = () => {
|
|
@@ -4220,7 +5855,7 @@ function AppPanel() {
|
|
|
4220
5855
|
const w = mainContentWidth - 2;
|
|
4221
5856
|
switch (nav.innerScreen) {
|
|
4222
5857
|
case "command-args":
|
|
4223
|
-
return /* @__PURE__ */
|
|
5858
|
+
return /* @__PURE__ */ jsx40(
|
|
4224
5859
|
CommandArgs,
|
|
4225
5860
|
{
|
|
4226
5861
|
command: nav.innerParams.command ?? "",
|
|
@@ -4233,7 +5868,7 @@ function AppPanel() {
|
|
|
4233
5868
|
}
|
|
4234
5869
|
);
|
|
4235
5870
|
case "custom-command":
|
|
4236
|
-
return /* @__PURE__ */
|
|
5871
|
+
return /* @__PURE__ */ jsx40(
|
|
4237
5872
|
CustomCommand,
|
|
4238
5873
|
{
|
|
4239
5874
|
onNavigate: nav.navigateInner,
|
|
@@ -4245,7 +5880,7 @@ function AppPanel() {
|
|
|
4245
5880
|
}
|
|
4246
5881
|
);
|
|
4247
5882
|
case "flag-selection":
|
|
4248
|
-
return /* @__PURE__ */
|
|
5883
|
+
return /* @__PURE__ */ jsx40(
|
|
4249
5884
|
FlagSelection,
|
|
4250
5885
|
{
|
|
4251
5886
|
args: nav.innerParams.args ?? [],
|
|
@@ -4261,7 +5896,7 @@ function AppPanel() {
|
|
|
4261
5896
|
);
|
|
4262
5897
|
case "confirm-execute":
|
|
4263
5898
|
case "command-execution":
|
|
4264
|
-
return /* @__PURE__ */
|
|
5899
|
+
return /* @__PURE__ */ jsx40(
|
|
4265
5900
|
CommandExecution,
|
|
4266
5901
|
{
|
|
4267
5902
|
args: nav.innerParams.args ?? [],
|
|
@@ -4281,7 +5916,7 @@ function AppPanel() {
|
|
|
4281
5916
|
`${nav.view}-${nav.innerParams.tool}-${(nav.innerParams.args ?? []).join("-")}`
|
|
4282
5917
|
);
|
|
4283
5918
|
case "pipeline-list":
|
|
4284
|
-
return /* @__PURE__ */
|
|
5919
|
+
return /* @__PURE__ */ jsx40(
|
|
4285
5920
|
PipelineList,
|
|
4286
5921
|
{
|
|
4287
5922
|
onNavigate: nav.navigateInner,
|
|
@@ -4293,7 +5928,7 @@ function AppPanel() {
|
|
|
4293
5928
|
}
|
|
4294
5929
|
);
|
|
4295
5930
|
case "pipeline-builder":
|
|
4296
|
-
return /* @__PURE__ */
|
|
5931
|
+
return /* @__PURE__ */ jsx40(
|
|
4297
5932
|
PipelineBuilder,
|
|
4298
5933
|
{
|
|
4299
5934
|
onBack: nav.goBackInner,
|
|
@@ -4304,7 +5939,7 @@ function AppPanel() {
|
|
|
4304
5939
|
}
|
|
4305
5940
|
);
|
|
4306
5941
|
case "pipeline-execution":
|
|
4307
|
-
return /* @__PURE__ */
|
|
5942
|
+
return /* @__PURE__ */ jsx40(
|
|
4308
5943
|
PipelineExecution,
|
|
4309
5944
|
{
|
|
4310
5945
|
pipelineId: nav.innerParams.pipelineId ?? "",
|
|
@@ -4316,7 +5951,7 @@ function AppPanel() {
|
|
|
4316
5951
|
}
|
|
4317
5952
|
);
|
|
4318
5953
|
case "self-update":
|
|
4319
|
-
return /* @__PURE__ */
|
|
5954
|
+
return /* @__PURE__ */ jsx40(
|
|
4320
5955
|
SelfUpdate,
|
|
4321
5956
|
{
|
|
4322
5957
|
onBack: nav.goBackInner,
|
|
@@ -4328,9 +5963,45 @@ function AppPanel() {
|
|
|
4328
5963
|
}
|
|
4329
5964
|
);
|
|
4330
5965
|
case "tool-status":
|
|
4331
|
-
return /* @__PURE__ */
|
|
5966
|
+
return /* @__PURE__ */ jsx40(
|
|
4332
5967
|
ToolStatus,
|
|
4333
5968
|
{
|
|
5969
|
+
onBack: nav.goBackInner,
|
|
5970
|
+
onNavigate: nav.navigateInner,
|
|
5971
|
+
width: w,
|
|
5972
|
+
height: mainContentHeight,
|
|
5973
|
+
panelMode: true,
|
|
5974
|
+
isInputActive: isActive
|
|
5975
|
+
}
|
|
5976
|
+
);
|
|
5977
|
+
case "mcp-manage":
|
|
5978
|
+
return /* @__PURE__ */ jsx40(
|
|
5979
|
+
McpManage,
|
|
5980
|
+
{
|
|
5981
|
+
onBack: nav.goBackInner,
|
|
5982
|
+
width: w,
|
|
5983
|
+
height: mainContentHeight,
|
|
5984
|
+
panelMode: true,
|
|
5985
|
+
isInputActive: isActive
|
|
5986
|
+
}
|
|
5987
|
+
);
|
|
5988
|
+
case "process-list":
|
|
5989
|
+
return /* @__PURE__ */ jsx40(
|
|
5990
|
+
ProcessList,
|
|
5991
|
+
{
|
|
5992
|
+
onNavigate: nav.navigateInner,
|
|
5993
|
+
onBack: nav.goBackInner,
|
|
5994
|
+
width: w,
|
|
5995
|
+
height: mainContentHeight,
|
|
5996
|
+
panelMode: true,
|
|
5997
|
+
isInputActive: isActive
|
|
5998
|
+
}
|
|
5999
|
+
);
|
|
6000
|
+
case "process-logs":
|
|
6001
|
+
return /* @__PURE__ */ jsx40(
|
|
6002
|
+
ProcessLogs,
|
|
6003
|
+
{
|
|
6004
|
+
processId: nav.innerParams.processId ?? "",
|
|
4334
6005
|
onBack: nav.goBackInner,
|
|
4335
6006
|
width: w,
|
|
4336
6007
|
height: mainContentHeight,
|
|
@@ -4339,7 +6010,7 @@ function AppPanel() {
|
|
|
4339
6010
|
}
|
|
4340
6011
|
);
|
|
4341
6012
|
case "project-config":
|
|
4342
|
-
return /* @__PURE__ */
|
|
6013
|
+
return /* @__PURE__ */ jsx40(
|
|
4343
6014
|
ProjectConfig,
|
|
4344
6015
|
{
|
|
4345
6016
|
onBack: nav.goBackInner,
|
|
@@ -4349,18 +6020,53 @@ function AppPanel() {
|
|
|
4349
6020
|
isInputActive: isActive
|
|
4350
6021
|
}
|
|
4351
6022
|
);
|
|
6023
|
+
case "declarative-plan":
|
|
6024
|
+
return /* @__PURE__ */ jsx40(
|
|
6025
|
+
DeclarativePlan,
|
|
6026
|
+
{
|
|
6027
|
+
onBack: nav.goBackInner,
|
|
6028
|
+
onNavigate: nav.navigateInner,
|
|
6029
|
+
width: w,
|
|
6030
|
+
height: mainContentHeight,
|
|
6031
|
+
panelMode: true,
|
|
6032
|
+
isInputActive: isActive
|
|
6033
|
+
}
|
|
6034
|
+
);
|
|
6035
|
+
case "declarative-status":
|
|
6036
|
+
return /* @__PURE__ */ jsx40(
|
|
6037
|
+
DeclarativeStatus,
|
|
6038
|
+
{
|
|
6039
|
+
onBack: nav.goBackInner,
|
|
6040
|
+
width: w,
|
|
6041
|
+
height: mainContentHeight,
|
|
6042
|
+
panelMode: true,
|
|
6043
|
+
isInputActive: isActive
|
|
6044
|
+
}
|
|
6045
|
+
);
|
|
6046
|
+
case "init-scaffold":
|
|
6047
|
+
return /* @__PURE__ */ jsx40(
|
|
6048
|
+
InitScaffold,
|
|
6049
|
+
{
|
|
6050
|
+
onBack: nav.goBackInner,
|
|
6051
|
+
onNavigate: nav.navigateInner,
|
|
6052
|
+
width: w,
|
|
6053
|
+
height: mainContentHeight,
|
|
6054
|
+
panelMode: true,
|
|
6055
|
+
isInputActive: isActive
|
|
6056
|
+
}
|
|
6057
|
+
);
|
|
4352
6058
|
default:
|
|
4353
|
-
return /* @__PURE__ */
|
|
6059
|
+
return /* @__PURE__ */ jsxs38(Text39, { color: "red", children: [
|
|
4354
6060
|
"Unknown screen: ",
|
|
4355
6061
|
nav.innerScreen
|
|
4356
6062
|
] });
|
|
4357
6063
|
}
|
|
4358
6064
|
};
|
|
4359
6065
|
if (modal.isOpen) {
|
|
4360
|
-
return /* @__PURE__ */
|
|
6066
|
+
return /* @__PURE__ */ jsx40(Box37, { flexDirection: "column", width, height, children: /* @__PURE__ */ jsx40(Modal, { title: modal.modalTitle, width, height, children: modal.modalContent }) });
|
|
4361
6067
|
}
|
|
4362
|
-
const header = /* @__PURE__ */
|
|
4363
|
-
const sidebar = /* @__PURE__ */
|
|
6068
|
+
const header = /* @__PURE__ */ jsx40(GhostBanner, { width, compact: true });
|
|
6069
|
+
const sidebar = /* @__PURE__ */ jsx40(
|
|
4364
6070
|
Panel,
|
|
4365
6071
|
{
|
|
4366
6072
|
id: "sidebar",
|
|
@@ -4368,7 +6074,7 @@ function AppPanel() {
|
|
|
4368
6074
|
width: Math.max(20, Math.min(35, Math.floor(width * 0.3))),
|
|
4369
6075
|
height: Math.max(5, height - bannerHeight - 1),
|
|
4370
6076
|
focused: focus.isSidebarFocused,
|
|
4371
|
-
children: /* @__PURE__ */
|
|
6077
|
+
children: /* @__PURE__ */ jsx40(
|
|
4372
6078
|
Sidebar,
|
|
4373
6079
|
{
|
|
4374
6080
|
items: sidebarItems,
|
|
@@ -4381,7 +6087,7 @@ function AppPanel() {
|
|
|
4381
6087
|
)
|
|
4382
6088
|
}
|
|
4383
6089
|
);
|
|
4384
|
-
const main2 = /* @__PURE__ */
|
|
6090
|
+
const main2 = /* @__PURE__ */ jsx40(
|
|
4385
6091
|
Panel,
|
|
4386
6092
|
{
|
|
4387
6093
|
id: "main",
|
|
@@ -4392,8 +6098,8 @@ function AppPanel() {
|
|
|
4392
6098
|
children: renderMainContent()
|
|
4393
6099
|
}
|
|
4394
6100
|
);
|
|
4395
|
-
const footer = /* @__PURE__ */
|
|
4396
|
-
return /* @__PURE__ */
|
|
6101
|
+
const footer = /* @__PURE__ */ jsx40(PanelFooter, { hints: footerHints, width });
|
|
6102
|
+
return /* @__PURE__ */ jsx40(
|
|
4397
6103
|
PanelLayout,
|
|
4398
6104
|
{
|
|
4399
6105
|
header,
|
|
@@ -4557,19 +6263,19 @@ function printCliHelp() {
|
|
|
4557
6263
|
import pc3 from "picocolors";
|
|
4558
6264
|
|
|
4559
6265
|
// src/apps/ops.ts
|
|
4560
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
6266
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4561
6267
|
import { mkdtemp, readdir, stat } from "fs/promises";
|
|
4562
|
-
import { dirname, join as
|
|
6268
|
+
import { dirname, join as join3, resolve } from "path";
|
|
4563
6269
|
import { tmpdir } from "os";
|
|
4564
6270
|
import pc2 from "picocolors";
|
|
4565
6271
|
|
|
4566
6272
|
// src/apps/bootstrapPaths.ts
|
|
4567
|
-
import { homedir } from "os";
|
|
4568
|
-
import { join } from "path";
|
|
6273
|
+
import { homedir as homedir2 } from "os";
|
|
6274
|
+
import { join as join2 } from "path";
|
|
4569
6275
|
function getOpsBootstrapPayloadPath() {
|
|
4570
|
-
const home =
|
|
6276
|
+
const home = homedir2();
|
|
4571
6277
|
if (process.platform === "darwin") {
|
|
4572
|
-
return
|
|
6278
|
+
return join2(
|
|
4573
6279
|
home,
|
|
4574
6280
|
"Library",
|
|
4575
6281
|
"Application Support",
|
|
@@ -4579,10 +6285,10 @@ function getOpsBootstrapPayloadPath() {
|
|
|
4579
6285
|
);
|
|
4580
6286
|
}
|
|
4581
6287
|
if (process.platform === "win32") {
|
|
4582
|
-
const appData = process.env.APPDATA ??
|
|
4583
|
-
return
|
|
6288
|
+
const appData = process.env.APPDATA ?? join2(home, "AppData", "Roaming");
|
|
6289
|
+
return join2(appData, "ops", "bootstrap", "supabase.json");
|
|
4584
6290
|
}
|
|
4585
|
-
return
|
|
6291
|
+
return join2(home, ".config", "ops", "bootstrap", "supabase.json");
|
|
4586
6292
|
}
|
|
4587
6293
|
|
|
4588
6294
|
// src/apps/opsRelease.ts
|
|
@@ -4854,9 +6560,9 @@ async function promptSelect(label, options, defaultValue) {
|
|
|
4854
6560
|
}
|
|
4855
6561
|
|
|
4856
6562
|
// src/apps/ops.ts
|
|
4857
|
-
var LINK_REF_FILE =
|
|
6563
|
+
var LINK_REF_FILE = join3("supabase", ".temp", "project-ref");
|
|
4858
6564
|
function isOpsProjectRoot(candidate) {
|
|
4859
|
-
return existsSync(
|
|
6565
|
+
return existsSync(join3(candidate, "src-tauri", "tauri.conf.json")) && existsSync(join3(candidate, "supabase", "migrations")) && existsSync(join3(candidate, "package.json"));
|
|
4860
6566
|
}
|
|
4861
6567
|
function findNearestOpsRoot(startDir) {
|
|
4862
6568
|
let currentDir = resolve(startDir);
|
|
@@ -4864,7 +6570,7 @@ function findNearestOpsRoot(startDir) {
|
|
|
4864
6570
|
if (isOpsProjectRoot(currentDir)) {
|
|
4865
6571
|
return currentDir;
|
|
4866
6572
|
}
|
|
4867
|
-
const siblingCandidate =
|
|
6573
|
+
const siblingCandidate = join3(currentDir, "ops");
|
|
4868
6574
|
if (isOpsProjectRoot(siblingCandidate)) {
|
|
4869
6575
|
return siblingCandidate;
|
|
4870
6576
|
}
|
|
@@ -4898,7 +6604,7 @@ function readEnvFile(envPath) {
|
|
|
4898
6604
|
}
|
|
4899
6605
|
function writeEnvFile(envPath, nextEnv) {
|
|
4900
6606
|
const content = Object.entries(nextEnv).map(([key, value]) => `${key}=${value}`).join("\n");
|
|
4901
|
-
|
|
6607
|
+
writeFileSync2(envPath, `${content}
|
|
4902
6608
|
`);
|
|
4903
6609
|
}
|
|
4904
6610
|
function assertProjectRoot(projectRoot) {
|
|
@@ -4910,7 +6616,7 @@ function assertProjectRoot(projectRoot) {
|
|
|
4910
6616
|
return projectRoot;
|
|
4911
6617
|
}
|
|
4912
6618
|
function getLinkedProjectRef(projectRoot) {
|
|
4913
|
-
const refPath =
|
|
6619
|
+
const refPath = join3(projectRoot, LINK_REF_FILE);
|
|
4914
6620
|
if (!existsSync(refPath)) {
|
|
4915
6621
|
return null;
|
|
4916
6622
|
}
|
|
@@ -4935,7 +6641,7 @@ async function ensurePrerequisites() {
|
|
|
4935
6641
|
}
|
|
4936
6642
|
}
|
|
4937
6643
|
async function runOrThrow(execution, args, cwd, failureMessage) {
|
|
4938
|
-
const result = await runCommand(execution, args, cwd);
|
|
6644
|
+
const result = await runCommand(execution, args, cwd).promise;
|
|
4939
6645
|
if (result.spawnError || result.exitCode !== 0) {
|
|
4940
6646
|
throw new Error(
|
|
4941
6647
|
result.stderr.trim() || result.spawnError || failureMessage
|
|
@@ -4968,7 +6674,7 @@ async function ensureSupabaseLink(projectRoot, forceRelink = false) {
|
|
|
4968
6674
|
);
|
|
4969
6675
|
}
|
|
4970
6676
|
async function collectSupabaseConfig(projectRoot) {
|
|
4971
|
-
const envPath = projectRoot ?
|
|
6677
|
+
const envPath = projectRoot ? join3(projectRoot, ".env.local") : void 0;
|
|
4972
6678
|
const currentEnv = envPath ? readEnvFile(envPath) : {};
|
|
4973
6679
|
const currentRef = projectRoot ? getLinkedProjectRef(projectRoot) : null;
|
|
4974
6680
|
const url = await promptText("Supabase URL", {
|
|
@@ -4990,7 +6696,7 @@ async function collectSupabaseConfig(projectRoot) {
|
|
|
4990
6696
|
};
|
|
4991
6697
|
}
|
|
4992
6698
|
function writeOpsEnv(projectRoot, config2) {
|
|
4993
|
-
const envPath =
|
|
6699
|
+
const envPath = join3(projectRoot, ".env.local");
|
|
4994
6700
|
const currentEnv = readEnvFile(envPath);
|
|
4995
6701
|
const nextEnv = {
|
|
4996
6702
|
...currentEnv,
|
|
@@ -5002,7 +6708,7 @@ function writeOpsEnv(projectRoot, config2) {
|
|
|
5002
6708
|
function writeBootstrapPayload(config2) {
|
|
5003
6709
|
const payloadPath = getOpsBootstrapPayloadPath();
|
|
5004
6710
|
mkdirSync(dirname(payloadPath), { recursive: true });
|
|
5005
|
-
|
|
6711
|
+
writeFileSync2(
|
|
5006
6712
|
payloadPath,
|
|
5007
6713
|
JSON.stringify(
|
|
5008
6714
|
{
|
|
@@ -5163,7 +6869,7 @@ async function downloadFile(url, destinationPath) {
|
|
|
5163
6869
|
}
|
|
5164
6870
|
const arrayBuffer = await response.arrayBuffer();
|
|
5165
6871
|
const buffer = Buffer.from(arrayBuffer);
|
|
5166
|
-
|
|
6872
|
+
writeFileSync2(destinationPath, buffer);
|
|
5167
6873
|
return buffer.byteLength;
|
|
5168
6874
|
}
|
|
5169
6875
|
async function extractArchive(archivePath, outputDir) {
|
|
@@ -5190,7 +6896,7 @@ async function extractArchive(archivePath, outputDir) {
|
|
|
5190
6896
|
async function findFirstAppBundle(dir) {
|
|
5191
6897
|
const entries = await readdir(dir);
|
|
5192
6898
|
for (const entry of entries) {
|
|
5193
|
-
const fullPath =
|
|
6899
|
+
const fullPath = join3(dir, entry);
|
|
5194
6900
|
const entryStat = await stat(fullPath);
|
|
5195
6901
|
if (entryStat.isDirectory() && entry.endsWith(".app")) {
|
|
5196
6902
|
return fullPath;
|
|
@@ -5206,9 +6912,9 @@ async function findFirstAppBundle(dir) {
|
|
|
5206
6912
|
}
|
|
5207
6913
|
async function deployMacosApp(context, options) {
|
|
5208
6914
|
const artifact = await resolveOpsMacosArtifact(context.options);
|
|
5209
|
-
const tempRoot = await mkdtemp(
|
|
5210
|
-
const archivePath =
|
|
5211
|
-
const extractDir =
|
|
6915
|
+
const tempRoot = await mkdtemp(join3(tmpdir(), "polter-ops-"));
|
|
6916
|
+
const archivePath = join3(tempRoot, artifact.fileName);
|
|
6917
|
+
const extractDir = join3(tempRoot, "extract");
|
|
5212
6918
|
mkdirSync(extractDir, { recursive: true });
|
|
5213
6919
|
if (artifact.source === "github-release") {
|
|
5214
6920
|
const releaseLabel = artifact.tagName ?? "latest";
|
|
@@ -5237,7 +6943,7 @@ async function deployMacosApp(context, options) {
|
|
|
5237
6943
|
}
|
|
5238
6944
|
const installDir = context.options.installDir ?? "/Applications";
|
|
5239
6945
|
mkdirSync(installDir, { recursive: true });
|
|
5240
|
-
const destination =
|
|
6946
|
+
const destination = join3(installDir, "ops.app");
|
|
5241
6947
|
if (options.requireExistingInstallation && !existsSync(destination)) {
|
|
5242
6948
|
throw new Error(
|
|
5243
6949
|
`No existing Ops installation was found at ${destination}. Run \`polter app install ops\` first.`
|
|
@@ -5358,168 +7064,8 @@ async function runAppCli(options) {
|
|
|
5358
7064
|
});
|
|
5359
7065
|
}
|
|
5360
7066
|
|
|
5361
|
-
// src/lib/mcpInstaller.ts
|
|
5362
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
5363
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
5364
|
-
import { join as join3 } from "path";
|
|
5365
|
-
import { homedir as homedir2 } from "os";
|
|
5366
|
-
import { createRequire as createRequire2 } from "module";
|
|
5367
|
-
import pc4 from "picocolors";
|
|
5368
|
-
var require3 = createRequire2(import.meta.url);
|
|
5369
|
-
var MCP_ARGS = ["npx", "-y", "-p", "@polterware/polter@latest", "polter-mcp"];
|
|
5370
|
-
var SCOPE_LABELS = {
|
|
5371
|
-
local: "local (this machine)",
|
|
5372
|
-
project: "project (shared via repo)",
|
|
5373
|
-
user: "global (all projects)"
|
|
5374
|
-
};
|
|
5375
|
-
function tryClaudeCli(scope) {
|
|
5376
|
-
if (!commandExists("claude")) return false;
|
|
5377
|
-
const result = spawnSync2("claude", ["mcp", "add", "-s", scope, "polter", "--", ...MCP_ARGS], {
|
|
5378
|
-
stdio: "inherit",
|
|
5379
|
-
shell: true
|
|
5380
|
-
});
|
|
5381
|
-
return result.status === 0;
|
|
5382
|
-
}
|
|
5383
|
-
function getSettingsPath(scope) {
|
|
5384
|
-
if (scope === "project") {
|
|
5385
|
-
return join3(process.cwd(), ".mcp.json");
|
|
5386
|
-
}
|
|
5387
|
-
return join3(homedir2(), ".claude", "settings.json");
|
|
5388
|
-
}
|
|
5389
|
-
function tryManualInstall(scope) {
|
|
5390
|
-
const settingsPath = getSettingsPath(scope);
|
|
5391
|
-
const dir = join3(settingsPath, "..");
|
|
5392
|
-
let settings = {};
|
|
5393
|
-
if (existsSync2(settingsPath)) {
|
|
5394
|
-
try {
|
|
5395
|
-
settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
5396
|
-
} catch {
|
|
5397
|
-
process.stderr.write(pc4.red(`Failed to parse ${settingsPath}
|
|
5398
|
-
`));
|
|
5399
|
-
return false;
|
|
5400
|
-
}
|
|
5401
|
-
} else {
|
|
5402
|
-
mkdirSync2(dir, { recursive: true });
|
|
5403
|
-
}
|
|
5404
|
-
const mcpServers = settings.mcpServers ?? {};
|
|
5405
|
-
mcpServers.polter = {
|
|
5406
|
-
command: "npx",
|
|
5407
|
-
args: ["-y", "-p", "@polterware/polter@latest", "polter-mcp"]
|
|
5408
|
-
};
|
|
5409
|
-
settings.mcpServers = mcpServers;
|
|
5410
|
-
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
5411
|
-
return true;
|
|
5412
|
-
}
|
|
5413
|
-
async function installMcpServer(scope) {
|
|
5414
|
-
process.stdout.write(pc4.bold(`Installing Polter MCP server \u2014 ${SCOPE_LABELS[scope]}
|
|
5415
|
-
|
|
5416
|
-
`));
|
|
5417
|
-
if (commandExists("claude")) {
|
|
5418
|
-
process.stdout.write(` Using 'claude mcp add -s ${scope}'...
|
|
5419
|
-
`);
|
|
5420
|
-
if (tryClaudeCli(scope)) {
|
|
5421
|
-
process.stdout.write(pc4.green("\n Done! Restart Claude Code to use Polter tools.\n"));
|
|
5422
|
-
return;
|
|
5423
|
-
}
|
|
5424
|
-
process.stdout.write(pc4.yellow(" 'claude mcp add' failed, falling back to manual install...\n\n"));
|
|
5425
|
-
}
|
|
5426
|
-
const settingsPath = getSettingsPath(scope);
|
|
5427
|
-
process.stdout.write(` Writing to ${settingsPath}...
|
|
5428
|
-
`);
|
|
5429
|
-
if (tryManualInstall(scope)) {
|
|
5430
|
-
process.stdout.write(pc4.green("\n Done! Restart Claude Code to use Polter tools.\n"));
|
|
5431
|
-
} else {
|
|
5432
|
-
process.stderr.write(pc4.red("\n Failed to install. Add manually:\n\n"));
|
|
5433
|
-
process.stderr.write(` ${pc4.dim(JSON.stringify({ mcpServers: { polter: { command: "npx", args: ["-y", "-p", "@polterware/polter@latest", "polter-mcp"] } } }, null, 2))}
|
|
5434
|
-
`);
|
|
5435
|
-
process.exit(1);
|
|
5436
|
-
}
|
|
5437
|
-
}
|
|
5438
|
-
async function removeMcpServer(scope) {
|
|
5439
|
-
process.stdout.write(pc4.bold(`Removing Polter MCP server \u2014 ${SCOPE_LABELS[scope]}
|
|
5440
|
-
|
|
5441
|
-
`));
|
|
5442
|
-
if (commandExists("claude")) {
|
|
5443
|
-
const result = spawnSync2("claude", ["mcp", "remove", "-s", scope, "polter"], {
|
|
5444
|
-
stdio: "inherit",
|
|
5445
|
-
shell: true
|
|
5446
|
-
});
|
|
5447
|
-
if (result.status === 0) {
|
|
5448
|
-
process.stdout.write(pc4.green("\n Done! Polter MCP server removed.\n"));
|
|
5449
|
-
return;
|
|
5450
|
-
}
|
|
5451
|
-
process.stdout.write(pc4.yellow(" 'claude mcp remove' failed, falling back to manual removal...\n\n"));
|
|
5452
|
-
}
|
|
5453
|
-
const settingsPath = getSettingsPath(scope);
|
|
5454
|
-
if (!existsSync2(settingsPath)) {
|
|
5455
|
-
process.stdout.write(pc4.yellow(" No settings file found. Nothing to remove.\n"));
|
|
5456
|
-
return;
|
|
5457
|
-
}
|
|
5458
|
-
let settings;
|
|
5459
|
-
try {
|
|
5460
|
-
settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
5461
|
-
} catch {
|
|
5462
|
-
process.stderr.write(pc4.red(` Failed to parse ${settingsPath}
|
|
5463
|
-
`));
|
|
5464
|
-
process.exit(1);
|
|
5465
|
-
return;
|
|
5466
|
-
}
|
|
5467
|
-
const mcpServers = settings.mcpServers;
|
|
5468
|
-
if (!mcpServers?.polter) {
|
|
5469
|
-
process.stdout.write(pc4.yellow(" Polter MCP server not found in settings. Nothing to remove.\n"));
|
|
5470
|
-
return;
|
|
5471
|
-
}
|
|
5472
|
-
delete mcpServers.polter;
|
|
5473
|
-
settings.mcpServers = mcpServers;
|
|
5474
|
-
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
5475
|
-
process.stdout.write(pc4.green(" Done! Polter MCP server removed.\n"));
|
|
5476
|
-
}
|
|
5477
|
-
async function mcpStatus() {
|
|
5478
|
-
process.stdout.write(pc4.bold("Polter MCP Server Status\n\n"));
|
|
5479
|
-
const pkg = require3("../../package.json");
|
|
5480
|
-
process.stdout.write(` Installed version: ${pc4.cyan(pkg.version)}
|
|
5481
|
-
`);
|
|
5482
|
-
const latestResult = spawnSync2("npm", ["view", "@polterware/polter", "version"], {
|
|
5483
|
-
encoding: "utf-8",
|
|
5484
|
-
shell: true,
|
|
5485
|
-
timeout: 1e4
|
|
5486
|
-
});
|
|
5487
|
-
const latest = latestResult.stdout?.trim();
|
|
5488
|
-
if (latest) {
|
|
5489
|
-
const upToDate = latest === pkg.version;
|
|
5490
|
-
process.stdout.write(` Latest version: ${upToDate ? pc4.green(latest) : pc4.yellow(`${latest} (update available)`)}
|
|
5491
|
-
`);
|
|
5492
|
-
}
|
|
5493
|
-
process.stdout.write("\n");
|
|
5494
|
-
const scopes = [
|
|
5495
|
-
{ label: "Project (.mcp.json)", path: join3(process.cwd(), ".mcp.json"), key: "project" },
|
|
5496
|
-
{ label: "User (~/.claude/settings.json)", path: join3(homedir2(), ".claude", "settings.json"), key: "user" }
|
|
5497
|
-
];
|
|
5498
|
-
for (const scope of scopes) {
|
|
5499
|
-
if (!existsSync2(scope.path)) {
|
|
5500
|
-
process.stdout.write(` ${scope.label}: ${pc4.dim("not found")}
|
|
5501
|
-
`);
|
|
5502
|
-
continue;
|
|
5503
|
-
}
|
|
5504
|
-
try {
|
|
5505
|
-
const settings = JSON.parse(readFileSync2(scope.path, "utf-8"));
|
|
5506
|
-
const mcpServers = settings.mcpServers;
|
|
5507
|
-
if (mcpServers?.polter) {
|
|
5508
|
-
process.stdout.write(` ${scope.label}: ${pc4.green("registered")}
|
|
5509
|
-
`);
|
|
5510
|
-
} else {
|
|
5511
|
-
process.stdout.write(` ${scope.label}: ${pc4.dim("not registered")}
|
|
5512
|
-
`);
|
|
5513
|
-
}
|
|
5514
|
-
} catch {
|
|
5515
|
-
process.stdout.write(` ${scope.label}: ${pc4.red("error reading file")}
|
|
5516
|
-
`);
|
|
5517
|
-
}
|
|
5518
|
-
}
|
|
5519
|
-
}
|
|
5520
|
-
|
|
5521
7067
|
// src/index.tsx
|
|
5522
|
-
import
|
|
7068
|
+
import pc4 from "picocolors";
|
|
5523
7069
|
async function main() {
|
|
5524
7070
|
const parsed = parseCliArgs(process.argv.slice(2));
|
|
5525
7071
|
if (parsed.mode === "help") {
|
|
@@ -5553,7 +7099,7 @@ async function main() {
|
|
|
5553
7099
|
`);
|
|
5554
7100
|
process.exit(1);
|
|
5555
7101
|
}
|
|
5556
|
-
process.stdout.write(
|
|
7102
|
+
process.stdout.write(pc4.bold(`Running pipeline: ${pipeline.name}
|
|
5557
7103
|
`));
|
|
5558
7104
|
const results = await executePipeline(pipeline, (progress) => {
|
|
5559
7105
|
if (progress.done) return;
|
|
@@ -5567,24 +7113,24 @@ async function main() {
|
|
|
5567
7113
|
});
|
|
5568
7114
|
const errors = results.filter((r) => r.status === "error");
|
|
5569
7115
|
if (errors.length > 0) {
|
|
5570
|
-
process.stderr.write(
|
|
7116
|
+
process.stderr.write(pc4.red(`
|
|
5571
7117
|
Pipeline completed with ${errors.length} error(s)
|
|
5572
7118
|
`));
|
|
5573
7119
|
process.exit(1);
|
|
5574
7120
|
}
|
|
5575
|
-
process.stdout.write(
|
|
7121
|
+
process.stdout.write(pc4.green("\nPipeline completed successfully!\n"));
|
|
5576
7122
|
return;
|
|
5577
7123
|
}
|
|
5578
7124
|
if (parsed.mode === "status") {
|
|
5579
7125
|
const tools = ["supabase", "gh", "vercel", "git"];
|
|
5580
|
-
process.stdout.write(
|
|
7126
|
+
process.stdout.write(pc4.bold("Tool Status\n\n"));
|
|
5581
7127
|
for (const toolId of tools) {
|
|
5582
7128
|
const info = getToolInfo(toolId);
|
|
5583
|
-
const status = info.installed ?
|
|
7129
|
+
const status = info.installed ? pc4.green(`\u2713 ${info.label} ${info.version ?? ""}`) : pc4.red(`\u2717 ${info.label} not found`);
|
|
5584
7130
|
process.stdout.write(` ${status}
|
|
5585
7131
|
`);
|
|
5586
7132
|
}
|
|
5587
|
-
process.stdout.write(
|
|
7133
|
+
process.stdout.write(pc4.bold("\nProject Status\n\n"));
|
|
5588
7134
|
const projectStatus = getCurrentStatus();
|
|
5589
7135
|
if (projectStatus.supabase) {
|
|
5590
7136
|
process.stdout.write(` Supabase: ${projectStatus.supabase.linked ? "linked" : "not linked"}
|
|
@@ -5608,15 +7154,15 @@ Pipeline completed with ${errors.length} error(s)
|
|
|
5608
7154
|
}
|
|
5609
7155
|
const plan = planChanges(yaml);
|
|
5610
7156
|
if (plan.noChanges) {
|
|
5611
|
-
process.stdout.write(
|
|
7157
|
+
process.stdout.write(pc4.green("No changes needed. State is up to date.\n"));
|
|
5612
7158
|
return;
|
|
5613
7159
|
}
|
|
5614
|
-
process.stdout.write(
|
|
7160
|
+
process.stdout.write(pc4.bold(`Plan: ${plan.actions.length} action(s)
|
|
5615
7161
|
|
|
5616
7162
|
`));
|
|
5617
7163
|
for (const action of plan.actions) {
|
|
5618
7164
|
const prefix = action.action === "create" ? "+" : action.action === "delete" ? "-" : "~";
|
|
5619
|
-
const color = action.action === "create" ?
|
|
7165
|
+
const color = action.action === "create" ? pc4.green : action.action === "delete" ? pc4.red : pc4.yellow;
|
|
5620
7166
|
process.stdout.write(` ${color(`${prefix} [${action.tool}] ${action.description}`)}
|
|
5621
7167
|
`);
|
|
5622
7168
|
}
|
|
@@ -5630,10 +7176,10 @@ Pipeline completed with ${errors.length} error(s)
|
|
|
5630
7176
|
}
|
|
5631
7177
|
const plan = planChanges(yaml);
|
|
5632
7178
|
if (plan.noChanges) {
|
|
5633
|
-
process.stdout.write(
|
|
7179
|
+
process.stdout.write(pc4.green("No changes needed. State is up to date.\n"));
|
|
5634
7180
|
return;
|
|
5635
7181
|
}
|
|
5636
|
-
process.stdout.write(
|
|
7182
|
+
process.stdout.write(pc4.bold(`Applying ${plan.actions.length} action(s)...
|
|
5637
7183
|
|
|
5638
7184
|
`));
|
|
5639
7185
|
const results = await applyActions(plan.actions, process.cwd(), (i, total, action) => {
|
|
@@ -5642,16 +7188,16 @@ Pipeline completed with ${errors.length} error(s)
|
|
|
5642
7188
|
});
|
|
5643
7189
|
const errors = results.filter((r) => !r.success);
|
|
5644
7190
|
if (errors.length > 0) {
|
|
5645
|
-
process.stderr.write(
|
|
7191
|
+
process.stderr.write(pc4.red(`
|
|
5646
7192
|
Apply completed with ${errors.length} error(s).
|
|
5647
7193
|
`));
|
|
5648
7194
|
for (const err of errors) {
|
|
5649
|
-
process.stderr.write(
|
|
7195
|
+
process.stderr.write(pc4.red(` \u2717 ${err.action.description}
|
|
5650
7196
|
`));
|
|
5651
7197
|
}
|
|
5652
7198
|
process.exit(1);
|
|
5653
7199
|
}
|
|
5654
|
-
process.stdout.write(
|
|
7200
|
+
process.stdout.write(pc4.green("\nAll changes applied successfully!\n"));
|
|
5655
7201
|
return;
|
|
5656
7202
|
}
|
|
5657
7203
|
if (parsed.mode === "config") {
|
|
@@ -5667,11 +7213,11 @@ Apply completed with ${errors.length} error(s).
|
|
|
5667
7213
|
process.exit(result.exitCode ?? 0);
|
|
5668
7214
|
}
|
|
5669
7215
|
const AppComponent2 = parsed.classic ? AppClassic : AppPanel;
|
|
5670
|
-
render(
|
|
7216
|
+
render(React27.createElement(AppComponent2));
|
|
5671
7217
|
return;
|
|
5672
7218
|
}
|
|
5673
7219
|
const AppComponent = parsed.classic ? AppClassic : AppPanel;
|
|
5674
|
-
render(
|
|
7220
|
+
render(React27.createElement(AppComponent));
|
|
5675
7221
|
}
|
|
5676
7222
|
main().catch((error) => {
|
|
5677
7223
|
const message = error instanceof Error ? error.message : String(error);
|