@polterware/polter 0.2.1 → 0.2.3
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 +1 -1
- package/dist/{chunk-3XNNC5AW.js → chunk-2B2UWOVQ.js} +110 -23
- package/dist/index.js +120 -51
- package/dist/mcp.js +1 -1
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -12,21 +12,24 @@ var supabaseCommands = [
|
|
|
12
12
|
tool: "supabase",
|
|
13
13
|
base: ["bootstrap"],
|
|
14
14
|
label: "bootstrap",
|
|
15
|
-
hint: "Bootstrap from a starter template"
|
|
15
|
+
hint: "Bootstrap from a starter template",
|
|
16
|
+
interactive: true
|
|
16
17
|
},
|
|
17
18
|
{
|
|
18
19
|
id: "supabase:init",
|
|
19
20
|
tool: "supabase",
|
|
20
21
|
base: ["init"],
|
|
21
22
|
label: "init",
|
|
22
|
-
hint: "Initialize a local project"
|
|
23
|
+
hint: "Initialize a local project",
|
|
24
|
+
interactive: true
|
|
23
25
|
},
|
|
24
26
|
{
|
|
25
27
|
id: "supabase:login",
|
|
26
28
|
tool: "supabase",
|
|
27
29
|
base: ["login"],
|
|
28
30
|
label: "login",
|
|
29
|
-
hint: "Authenticate with access token"
|
|
31
|
+
hint: "Authenticate with access token",
|
|
32
|
+
interactive: true
|
|
30
33
|
},
|
|
31
34
|
{
|
|
32
35
|
id: "supabase:logout",
|
|
@@ -131,7 +134,8 @@ var supabaseCommands = [
|
|
|
131
134
|
tool: "supabase",
|
|
132
135
|
base: ["link"],
|
|
133
136
|
label: "link",
|
|
134
|
-
hint: "Link to remote project"
|
|
137
|
+
hint: "Link to remote project",
|
|
138
|
+
interactive: true
|
|
135
139
|
},
|
|
136
140
|
{
|
|
137
141
|
id: "supabase:unlink",
|
|
@@ -325,7 +329,8 @@ var ghCommands = [
|
|
|
325
329
|
tool: "gh",
|
|
326
330
|
base: ["repo", "create"],
|
|
327
331
|
label: "repo create",
|
|
328
|
-
hint: "Create a new repository"
|
|
332
|
+
hint: "Create a new repository",
|
|
333
|
+
interactive: true
|
|
329
334
|
},
|
|
330
335
|
{
|
|
331
336
|
id: "gh:repo:view",
|
|
@@ -489,7 +494,8 @@ var ghCommands = [
|
|
|
489
494
|
tool: "gh",
|
|
490
495
|
base: ["auth", "login"],
|
|
491
496
|
label: "auth login",
|
|
492
|
-
hint: "Log in to GitHub"
|
|
497
|
+
hint: "Log in to GitHub",
|
|
498
|
+
interactive: true
|
|
493
499
|
},
|
|
494
500
|
{
|
|
495
501
|
id: "gh:auth:status",
|
|
@@ -610,14 +616,16 @@ var vercelCommands = [
|
|
|
610
616
|
tool: "vercel",
|
|
611
617
|
base: ["link"],
|
|
612
618
|
label: "link",
|
|
613
|
-
hint: "Link to a Vercel project"
|
|
619
|
+
hint: "Link to a Vercel project",
|
|
620
|
+
interactive: true
|
|
614
621
|
},
|
|
615
622
|
{
|
|
616
623
|
id: "vercel:login",
|
|
617
624
|
tool: "vercel",
|
|
618
625
|
base: ["login"],
|
|
619
626
|
label: "login",
|
|
620
|
-
hint: "Log in to Vercel"
|
|
627
|
+
hint: "Log in to Vercel",
|
|
628
|
+
interactive: true
|
|
621
629
|
},
|
|
622
630
|
{
|
|
623
631
|
id: "vercel:whoami",
|
|
@@ -863,7 +871,7 @@ function getFlagsForTool(toolId) {
|
|
|
863
871
|
}
|
|
864
872
|
|
|
865
873
|
// src/lib/runner.ts
|
|
866
|
-
import { spawn } from "child_process";
|
|
874
|
+
import { spawn, spawnSync } from "child_process";
|
|
867
875
|
import { existsSync } from "fs";
|
|
868
876
|
import { delimiter, dirname, join, resolve } from "path";
|
|
869
877
|
function getSupabaseBinaryCandidates() {
|
|
@@ -953,10 +961,30 @@ async function runCommand(execution, args, cwd = process.cwd(), options) {
|
|
|
953
961
|
});
|
|
954
962
|
});
|
|
955
963
|
}
|
|
964
|
+
function runInteractiveCommand(execution, args, cwd = process.cwd()) {
|
|
965
|
+
const resolved = typeof execution === "string" ? { command: execution } : execution;
|
|
966
|
+
const result = spawnSync(resolved.command, args, {
|
|
967
|
+
cwd,
|
|
968
|
+
env: resolved.env,
|
|
969
|
+
shell: true,
|
|
970
|
+
stdio: "inherit"
|
|
971
|
+
});
|
|
972
|
+
return {
|
|
973
|
+
exitCode: result.status,
|
|
974
|
+
signal: result.signal,
|
|
975
|
+
stdout: "",
|
|
976
|
+
stderr: "",
|
|
977
|
+
spawnError: result.error?.message
|
|
978
|
+
};
|
|
979
|
+
}
|
|
956
980
|
async function runSupabaseCommand(args, cwd = process.cwd()) {
|
|
957
981
|
return runCommand(resolveSupabaseCommand(cwd), args, cwd);
|
|
958
982
|
}
|
|
959
983
|
|
|
984
|
+
// src/lib/toolResolver.ts
|
|
985
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
986
|
+
import { join as join2 } from "path";
|
|
987
|
+
|
|
960
988
|
// src/lib/system.ts
|
|
961
989
|
import { execSync } from "child_process";
|
|
962
990
|
function commandExists(command) {
|
|
@@ -1029,6 +1057,63 @@ function getToolInfo(toolId) {
|
|
|
1029
1057
|
toolInfoCache.set(toolId, info);
|
|
1030
1058
|
return info;
|
|
1031
1059
|
}
|
|
1060
|
+
function detectSupabaseLink(cwd) {
|
|
1061
|
+
try {
|
|
1062
|
+
const configPath = join2(cwd, ".supabase", "config.toml");
|
|
1063
|
+
if (existsSync2(configPath)) {
|
|
1064
|
+
const content = readFileSync(configPath, "utf-8");
|
|
1065
|
+
const match = content.match(/project_id\s*=\s*"([^"]+)"/);
|
|
1066
|
+
return { linked: true, project: match?.[1] };
|
|
1067
|
+
}
|
|
1068
|
+
} catch {
|
|
1069
|
+
}
|
|
1070
|
+
return { linked: false };
|
|
1071
|
+
}
|
|
1072
|
+
function detectVercelLink(cwd) {
|
|
1073
|
+
try {
|
|
1074
|
+
const projectPath = join2(cwd, ".vercel", "project.json");
|
|
1075
|
+
if (existsSync2(projectPath)) {
|
|
1076
|
+
const data = JSON.parse(readFileSync(projectPath, "utf-8"));
|
|
1077
|
+
return { linked: true, project: data.projectId };
|
|
1078
|
+
}
|
|
1079
|
+
} catch {
|
|
1080
|
+
}
|
|
1081
|
+
return { linked: false };
|
|
1082
|
+
}
|
|
1083
|
+
function detectGhLink(cwd) {
|
|
1084
|
+
try {
|
|
1085
|
+
const remote = execCapture(`git -C "${cwd}" remote get-url origin 2>/dev/null`);
|
|
1086
|
+
if (remote) {
|
|
1087
|
+
const match = remote.match(/[/:]([\w.-]+\/[\w.-]+?)(?:\.git)?$/);
|
|
1088
|
+
return { linked: true, project: match?.[1] ?? remote };
|
|
1089
|
+
}
|
|
1090
|
+
} catch {
|
|
1091
|
+
}
|
|
1092
|
+
return { linked: false };
|
|
1093
|
+
}
|
|
1094
|
+
var toolLinkCache = /* @__PURE__ */ new Map();
|
|
1095
|
+
function getToolLinkInfo(toolId, cwd = process.cwd()) {
|
|
1096
|
+
const cached = toolLinkCache.get(toolId);
|
|
1097
|
+
if (cached) return cached;
|
|
1098
|
+
const base = getToolInfo(toolId);
|
|
1099
|
+
let linkStatus = { linked: false };
|
|
1100
|
+
if (base.installed) {
|
|
1101
|
+
switch (toolId) {
|
|
1102
|
+
case "supabase":
|
|
1103
|
+
linkStatus = detectSupabaseLink(cwd);
|
|
1104
|
+
break;
|
|
1105
|
+
case "vercel":
|
|
1106
|
+
linkStatus = detectVercelLink(cwd);
|
|
1107
|
+
break;
|
|
1108
|
+
case "gh":
|
|
1109
|
+
linkStatus = detectGhLink(cwd);
|
|
1110
|
+
break;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
const info = { ...base, ...linkStatus };
|
|
1114
|
+
toolLinkCache.set(toolId, info);
|
|
1115
|
+
return info;
|
|
1116
|
+
}
|
|
1032
1117
|
|
|
1033
1118
|
// src/pipeline/engine.ts
|
|
1034
1119
|
async function executePipeline(pipeline, onProgress, cwd = process.cwd()) {
|
|
@@ -1076,19 +1161,19 @@ async function executePipeline(pipeline, onProgress, cwd = process.cwd()) {
|
|
|
1076
1161
|
}
|
|
1077
1162
|
|
|
1078
1163
|
// src/config/projectConfig.ts
|
|
1079
|
-
import { existsSync as
|
|
1080
|
-
import { join as
|
|
1164
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
1165
|
+
import { join as join4 } from "path";
|
|
1081
1166
|
|
|
1082
1167
|
// src/lib/packageRoot.ts
|
|
1083
|
-
import { existsSync as
|
|
1084
|
-
import { dirname as dirname2, join as
|
|
1168
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1169
|
+
import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
|
|
1085
1170
|
var rootCache = /* @__PURE__ */ new Map();
|
|
1086
1171
|
function findNearestPackageRoot(startDir = process.cwd()) {
|
|
1087
1172
|
const resolvedStart = resolve2(startDir);
|
|
1088
1173
|
if (rootCache.has(resolvedStart)) return rootCache.get(resolvedStart);
|
|
1089
1174
|
let currentDir = resolvedStart;
|
|
1090
1175
|
while (true) {
|
|
1091
|
-
if (
|
|
1176
|
+
if (existsSync3(join3(currentDir, "package.json"))) {
|
|
1092
1177
|
rootCache.set(resolvedStart, currentDir);
|
|
1093
1178
|
return currentDir;
|
|
1094
1179
|
}
|
|
@@ -1114,15 +1199,15 @@ function defaultConfig() {
|
|
|
1114
1199
|
function getProjectConfigPath(startDir) {
|
|
1115
1200
|
const root = findNearestPackageRoot(startDir);
|
|
1116
1201
|
if (!root) return void 0;
|
|
1117
|
-
const dir =
|
|
1118
|
-
return { dir, file:
|
|
1202
|
+
const dir = join4(root, CONFIG_DIR);
|
|
1203
|
+
return { dir, file: join4(dir, CONFIG_FILE) };
|
|
1119
1204
|
}
|
|
1120
1205
|
function readProjectConfig(startDir) {
|
|
1121
1206
|
const paths = getProjectConfigPath(startDir);
|
|
1122
1207
|
if (!paths) return void 0;
|
|
1123
|
-
if (!
|
|
1208
|
+
if (!existsSync4(paths.file)) return void 0;
|
|
1124
1209
|
try {
|
|
1125
|
-
const raw =
|
|
1210
|
+
const raw = readFileSync2(paths.file, "utf-8");
|
|
1126
1211
|
return JSON.parse(raw);
|
|
1127
1212
|
} catch {
|
|
1128
1213
|
return void 0;
|
|
@@ -1221,8 +1306,8 @@ function findPipelineByName(name, startDir) {
|
|
|
1221
1306
|
}
|
|
1222
1307
|
|
|
1223
1308
|
// src/declarative/parser.ts
|
|
1224
|
-
import { existsSync as
|
|
1225
|
-
import { join as
|
|
1309
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
1310
|
+
import { join as join5 } from "path";
|
|
1226
1311
|
var YAML_FILE = "polter.yaml";
|
|
1227
1312
|
function parseSimpleYaml(content) {
|
|
1228
1313
|
const lines = content.split("\n");
|
|
@@ -1294,13 +1379,13 @@ function parseValue(raw) {
|
|
|
1294
1379
|
return raw;
|
|
1295
1380
|
}
|
|
1296
1381
|
function findPolterYaml(startDir = process.cwd()) {
|
|
1297
|
-
const filePath =
|
|
1298
|
-
return
|
|
1382
|
+
const filePath = join5(startDir, YAML_FILE);
|
|
1383
|
+
return existsSync5(filePath) ? filePath : void 0;
|
|
1299
1384
|
}
|
|
1300
1385
|
function parsePolterYaml(startDir = process.cwd()) {
|
|
1301
1386
|
const filePath = findPolterYaml(startDir);
|
|
1302
1387
|
if (!filePath) return void 0;
|
|
1303
|
-
const content =
|
|
1388
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
1304
1389
|
const raw = parseSimpleYaml(content);
|
|
1305
1390
|
return raw;
|
|
1306
1391
|
}
|
|
@@ -1451,10 +1536,12 @@ export {
|
|
|
1451
1536
|
toolFlags,
|
|
1452
1537
|
getFlagsForTool,
|
|
1453
1538
|
runCommand,
|
|
1539
|
+
runInteractiveCommand,
|
|
1454
1540
|
runSupabaseCommand,
|
|
1455
1541
|
commandExists,
|
|
1456
1542
|
resolveToolCommand,
|
|
1457
1543
|
getToolInfo,
|
|
1544
|
+
getToolLinkInfo,
|
|
1458
1545
|
executePipeline,
|
|
1459
1546
|
findNearestPackageRoot,
|
|
1460
1547
|
getProjectConfigPath,
|
package/dist/index.js
CHANGED
|
@@ -17,14 +17,16 @@ import {
|
|
|
17
17
|
getOrCreateProjectConfig,
|
|
18
18
|
getProjectConfigPath,
|
|
19
19
|
getToolInfo,
|
|
20
|
+
getToolLinkInfo,
|
|
20
21
|
parsePolterYaml,
|
|
21
22
|
planChanges,
|
|
22
23
|
resolveToolCommand,
|
|
23
24
|
runCommand,
|
|
25
|
+
runInteractiveCommand,
|
|
24
26
|
runSupabaseCommand,
|
|
25
27
|
savePipeline,
|
|
26
28
|
writeProjectConfig
|
|
27
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-2B2UWOVQ.js";
|
|
28
30
|
|
|
29
31
|
// src/index.tsx
|
|
30
32
|
import React20 from "react";
|
|
@@ -176,16 +178,16 @@ var ghost = {
|
|
|
176
178
|
// src/components/GhostBanner.tsx
|
|
177
179
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
178
180
|
var ToolStatusBadges = React.memo(function ToolStatusBadges2() {
|
|
179
|
-
const tools = ["supabase", "gh", "vercel"].map(
|
|
181
|
+
const tools = ["supabase", "gh", "vercel"].map((id) => getToolLinkInfo(id));
|
|
180
182
|
return /* @__PURE__ */ jsx(Box, { gap: 1, children: tools.map((t) => /* @__PURE__ */ jsxs(
|
|
181
183
|
Text,
|
|
182
184
|
{
|
|
183
|
-
color: t.
|
|
185
|
+
color: t.linked ? inkColors.accent : t.installed ? "yellow" : "red",
|
|
184
186
|
dimColor: !t.installed,
|
|
185
187
|
children: [
|
|
186
188
|
t.id,
|
|
187
189
|
":",
|
|
188
|
-
t.installed ? "ok" : "x"
|
|
190
|
+
t.linked ? "linked" : t.installed ? "ok" : "x"
|
|
189
191
|
]
|
|
190
192
|
},
|
|
191
193
|
t.id
|
|
@@ -1127,7 +1129,8 @@ function CommandArgs({
|
|
|
1127
1129
|
onNavigate("flag-selection", {
|
|
1128
1130
|
args: [...baseArgs, ...extraArgs],
|
|
1129
1131
|
command,
|
|
1130
|
-
tool: resolvedTool
|
|
1132
|
+
tool: resolvedTool,
|
|
1133
|
+
interactive: cmdDef?.interactive
|
|
1131
1134
|
});
|
|
1132
1135
|
};
|
|
1133
1136
|
useInput4((_input, key) => {
|
|
@@ -1427,6 +1430,7 @@ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
|
1427
1430
|
function FlagSelection({
|
|
1428
1431
|
args,
|
|
1429
1432
|
tool = "supabase",
|
|
1433
|
+
interactive,
|
|
1430
1434
|
onNavigate,
|
|
1431
1435
|
onBack,
|
|
1432
1436
|
width = 80,
|
|
@@ -1436,7 +1440,7 @@ function FlagSelection({
|
|
|
1436
1440
|
}) {
|
|
1437
1441
|
const flags = getFlagsForTool(tool);
|
|
1438
1442
|
if (flags.length === 0) {
|
|
1439
|
-
onNavigate("confirm-execute", { args, tool });
|
|
1443
|
+
onNavigate("confirm-execute", { args, tool, interactive });
|
|
1440
1444
|
return /* @__PURE__ */ jsx11(Box10, {});
|
|
1441
1445
|
}
|
|
1442
1446
|
const cmdDisplay = `${tool} ${args.join(" ")}`;
|
|
@@ -1460,7 +1464,7 @@ function FlagSelection({
|
|
|
1460
1464
|
flags,
|
|
1461
1465
|
onSubmit: (selectedFlags) => {
|
|
1462
1466
|
const finalArgs = selectedFlags.length > 0 ? [...args, ...selectedFlags] : args;
|
|
1463
|
-
onNavigate("confirm-execute", { args: finalArgs, tool });
|
|
1467
|
+
onNavigate("confirm-execute", { args: finalArgs, tool, interactive });
|
|
1464
1468
|
},
|
|
1465
1469
|
onCancel: onBack,
|
|
1466
1470
|
isInputActive,
|
|
@@ -1486,7 +1490,7 @@ function FlagSelection({
|
|
|
1486
1490
|
}
|
|
1487
1491
|
|
|
1488
1492
|
// src/screens/CommandExecution.tsx
|
|
1489
|
-
import { useState as useState11, useEffect as
|
|
1493
|
+
import { useState as useState11, useEffect as useEffect6 } from "react";
|
|
1490
1494
|
import { Box as Box13, Text as Text17 } from "ink";
|
|
1491
1495
|
|
|
1492
1496
|
// src/components/Spinner.tsx
|
|
@@ -1668,6 +1672,58 @@ function useCommand(execution = "supabase", cwd = process.cwd(), options) {
|
|
|
1668
1672
|
return { status, result, run, reset };
|
|
1669
1673
|
}
|
|
1670
1674
|
|
|
1675
|
+
// src/hooks/useInteractiveRun.ts
|
|
1676
|
+
import { useCallback as useCallback3 } from "react";
|
|
1677
|
+
|
|
1678
|
+
// src/hooks/useFullscreen.ts
|
|
1679
|
+
import { useEffect as useEffect5 } from "react";
|
|
1680
|
+
var ENTER_ALT_SCREEN = "\x1B[?1049h";
|
|
1681
|
+
var LEAVE_ALT_SCREEN = "\x1B[?1049l";
|
|
1682
|
+
var HIDE_CURSOR = "\x1B[?25l";
|
|
1683
|
+
var SHOW_CURSOR = "\x1B[?25h";
|
|
1684
|
+
function useFullscreen() {
|
|
1685
|
+
useEffect5(() => {
|
|
1686
|
+
process.stdout.write(ENTER_ALT_SCREEN + HIDE_CURSOR);
|
|
1687
|
+
return () => {
|
|
1688
|
+
process.stdout.write(SHOW_CURSOR + LEAVE_ALT_SCREEN);
|
|
1689
|
+
};
|
|
1690
|
+
}, []);
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
// src/hooks/useInteractiveRun.ts
|
|
1694
|
+
function useInteractiveRun() {
|
|
1695
|
+
const runInteractive = useCallback3(
|
|
1696
|
+
(tool, args, cwd) => {
|
|
1697
|
+
process.stdout.write(SHOW_CURSOR + LEAVE_ALT_SCREEN + "\x1B[2J\x1B[H");
|
|
1698
|
+
if (process.stdin.isTTY) {
|
|
1699
|
+
process.stdin.setRawMode(false);
|
|
1700
|
+
}
|
|
1701
|
+
process.stdout.write(`
|
|
1702
|
+
Running: ${tool} ${args.join(" ")}
|
|
1703
|
+
|
|
1704
|
+
`);
|
|
1705
|
+
const resolved = resolveToolCommand(tool, cwd);
|
|
1706
|
+
const result = runInteractiveCommand(
|
|
1707
|
+
{ command: resolved.command, env: resolved.env },
|
|
1708
|
+
args,
|
|
1709
|
+
cwd
|
|
1710
|
+
);
|
|
1711
|
+
process.stdout.write(
|
|
1712
|
+
`
|
|
1713
|
+
Command exited (code ${result.exitCode ?? "?"}). Returning to Polter...
|
|
1714
|
+
`
|
|
1715
|
+
);
|
|
1716
|
+
if (process.stdin.isTTY) {
|
|
1717
|
+
process.stdin.setRawMode(true);
|
|
1718
|
+
}
|
|
1719
|
+
process.stdout.write(ENTER_ALT_SCREEN + HIDE_CURSOR);
|
|
1720
|
+
return result;
|
|
1721
|
+
},
|
|
1722
|
+
[]
|
|
1723
|
+
);
|
|
1724
|
+
return { runInteractive };
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1671
1727
|
// src/lib/clipboard.ts
|
|
1672
1728
|
import { spawn, exec } from "child_process";
|
|
1673
1729
|
async function copyToClipboard(text) {
|
|
@@ -1731,6 +1787,7 @@ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
|
1731
1787
|
function CommandExecution({
|
|
1732
1788
|
args: initialArgs,
|
|
1733
1789
|
tool = "supabase",
|
|
1790
|
+
interactive = false,
|
|
1734
1791
|
onBack,
|
|
1735
1792
|
onHome,
|
|
1736
1793
|
onExit,
|
|
@@ -1746,14 +1803,24 @@ function CommandExecution({
|
|
|
1746
1803
|
const { status, result, run, reset } = useCommand(tool, process.cwd(), {
|
|
1747
1804
|
quiet: panelMode
|
|
1748
1805
|
});
|
|
1806
|
+
const { runInteractive } = useInteractiveRun();
|
|
1749
1807
|
const cmdDisplay = `${tool} ${currentArgs.join(" ")}`;
|
|
1750
1808
|
const runCommand2 = currentArgs.join(" ");
|
|
1751
|
-
|
|
1809
|
+
useEffect6(() => {
|
|
1752
1810
|
if (phase === "running" && status === "idle") {
|
|
1753
|
-
|
|
1811
|
+
if (panelMode && interactive) {
|
|
1812
|
+
const interactiveResult = runInteractive(tool, currentArgs);
|
|
1813
|
+
if (!interactiveResult.spawnError && interactiveResult.exitCode === 0) {
|
|
1814
|
+
setPhase("success");
|
|
1815
|
+
} else {
|
|
1816
|
+
setPhase("error-menu");
|
|
1817
|
+
}
|
|
1818
|
+
} else {
|
|
1819
|
+
run(currentArgs);
|
|
1820
|
+
}
|
|
1754
1821
|
}
|
|
1755
|
-
}, [phase, status, run, currentArgs]);
|
|
1756
|
-
|
|
1822
|
+
}, [phase, status, run, currentArgs, panelMode, interactive, tool, runInteractive]);
|
|
1823
|
+
useEffect6(() => {
|
|
1757
1824
|
if (phase === "running" && status === "success") {
|
|
1758
1825
|
if (isPinnedRun(runCommand2)) {
|
|
1759
1826
|
setPhase("success");
|
|
@@ -1916,6 +1983,13 @@ function CommandExecution({
|
|
|
1916
1983
|
});
|
|
1917
1984
|
}
|
|
1918
1985
|
}
|
|
1986
|
+
if (panelMode && !result?.spawnError) {
|
|
1987
|
+
errorItems.push({
|
|
1988
|
+
value: "run-interactive",
|
|
1989
|
+
label: "\u{1F4BB} Run in terminal",
|
|
1990
|
+
hint: "Suspend TUI and run interactively"
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1919
1993
|
errorItems.push({
|
|
1920
1994
|
value: "copy",
|
|
1921
1995
|
label: "\u{1F4CB} Copy command to clipboard"
|
|
@@ -1967,7 +2041,7 @@ function CommandExecution({
|
|
|
1967
2041
|
{
|
|
1968
2042
|
stdout: result?.stdout,
|
|
1969
2043
|
stderr: result?.stderr,
|
|
1970
|
-
height: Math.max(3, height -
|
|
2044
|
+
height: Math.max(3, height - 13 - errorItems.length - (suggestions.length > 0 ? suggestions.length + 4 : 0)),
|
|
1971
2045
|
isActive: false
|
|
1972
2046
|
}
|
|
1973
2047
|
),
|
|
@@ -2006,6 +2080,13 @@ function CommandExecution({
|
|
|
2006
2080
|
setPhase("running");
|
|
2007
2081
|
break;
|
|
2008
2082
|
}
|
|
2083
|
+
case "run-interactive": {
|
|
2084
|
+
const interactiveResult = runInteractive(tool, currentArgs);
|
|
2085
|
+
if (!interactiveResult.spawnError && interactiveResult.exitCode === 0) {
|
|
2086
|
+
setPhase("success");
|
|
2087
|
+
}
|
|
2088
|
+
break;
|
|
2089
|
+
}
|
|
2009
2090
|
case "copy":
|
|
2010
2091
|
await copyToClipboard(cmdDisplay);
|
|
2011
2092
|
break;
|
|
@@ -2031,7 +2112,7 @@ function CommandExecution({
|
|
|
2031
2112
|
}
|
|
2032
2113
|
|
|
2033
2114
|
// src/screens/SelfUpdate.tsx
|
|
2034
|
-
import { useEffect as
|
|
2115
|
+
import { useEffect as useEffect7, useState as useState12 } from "react";
|
|
2035
2116
|
import { Box as Box14, Text as Text18 } from "ink";
|
|
2036
2117
|
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2037
2118
|
var packageName = "@polterware/polter";
|
|
@@ -2061,12 +2142,12 @@ function SelfUpdate({
|
|
|
2061
2142
|
const { status, result, run, reset } = useCommand("npm", updateCwd, {
|
|
2062
2143
|
quiet: panelMode
|
|
2063
2144
|
});
|
|
2064
|
-
|
|
2145
|
+
useEffect7(() => {
|
|
2065
2146
|
if (phase === "running" && status === "idle") {
|
|
2066
2147
|
run(updateArgs);
|
|
2067
2148
|
}
|
|
2068
2149
|
}, [phase, run, status, updateArgs]);
|
|
2069
|
-
|
|
2150
|
+
useEffect7(() => {
|
|
2070
2151
|
if (phase === "running" && status === "success") {
|
|
2071
2152
|
setPhase("success");
|
|
2072
2153
|
}
|
|
@@ -2311,15 +2392,16 @@ import { useMemo as useMemo4 } from "react";
|
|
|
2311
2392
|
import { Box as Box15, Text as Text19 } from "ink";
|
|
2312
2393
|
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2313
2394
|
var toolIds = ["supabase", "gh", "vercel", "git"];
|
|
2395
|
+
var linkableTools = /* @__PURE__ */ new Set(["supabase", "gh", "vercel"]);
|
|
2314
2396
|
function ToolStatus({ onBack, width = 80, height = 24, panelMode = false, isInputActive = true }) {
|
|
2315
|
-
const tools = useMemo4(() => toolIds.map(
|
|
2397
|
+
const tools = useMemo4(() => toolIds.map((id) => getToolLinkInfo(id)), []);
|
|
2316
2398
|
if (panelMode) {
|
|
2317
2399
|
const statusItems = [
|
|
2318
2400
|
{ value: "__section__", label: "Installed Tools", kind: "header", selectable: false },
|
|
2319
2401
|
...tools.map((tool) => ({
|
|
2320
2402
|
value: tool.id,
|
|
2321
2403
|
label: `${tool.installed ? "\u2713" : "\u2717"} ${tool.label}`,
|
|
2322
|
-
hint: tool.installed ? tool.version ?? "installed" : "not found",
|
|
2404
|
+
hint: tool.installed ? `${tool.version ?? "installed"}${linkableTools.has(tool.id) ? tool.linked ? ` \u2192 ${tool.project ? `linked (${tool.project})` : "linked"}` : " \u2192 not linked" : ""}` : "not found",
|
|
2323
2405
|
kind: "action"
|
|
2324
2406
|
}))
|
|
2325
2407
|
];
|
|
@@ -2344,7 +2426,7 @@ function ToolStatus({ onBack, width = 80, height = 24, panelMode = false, isInpu
|
|
|
2344
2426
|
tools.map((tool) => /* @__PURE__ */ jsxs17(Box15, { gap: 1, marginLeft: 2, children: [
|
|
2345
2427
|
/* @__PURE__ */ jsx19(Text19, { color: tool.installed ? inkColors.accent : "red", children: tool.installed ? "\u2713" : "\u2717" }),
|
|
2346
2428
|
/* @__PURE__ */ jsx19(Box15, { width: 16, children: /* @__PURE__ */ jsx19(Text19, { bold: true, children: tool.label }) }),
|
|
2347
|
-
/* @__PURE__ */ jsx19(Text19, { dimColor: true, children: tool.installed ? tool.version ?? "installed" : "not found" })
|
|
2429
|
+
/* @__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" })
|
|
2348
2430
|
] }, tool.id)),
|
|
2349
2431
|
/* @__PURE__ */ jsx19(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx19(
|
|
2350
2432
|
SelectList,
|
|
@@ -2365,7 +2447,7 @@ import { useMemo as useMemo5, useState as useState14 } from "react";
|
|
|
2365
2447
|
import { Box as Box16, Text as Text20 } from "ink";
|
|
2366
2448
|
|
|
2367
2449
|
// src/hooks/useEditor.ts
|
|
2368
|
-
import { useState as useState13, useCallback as
|
|
2450
|
+
import { useState as useState13, useCallback as useCallback4 } from "react";
|
|
2369
2451
|
import { useStdin } from "ink";
|
|
2370
2452
|
|
|
2371
2453
|
// src/lib/editor.ts
|
|
@@ -2417,7 +2499,7 @@ function openInEditor(filePath) {
|
|
|
2417
2499
|
function useEditor() {
|
|
2418
2500
|
const { setRawMode } = useStdin();
|
|
2419
2501
|
const [isEditing, setIsEditing] = useState13(false);
|
|
2420
|
-
const openEditor =
|
|
2502
|
+
const openEditor = useCallback4(async (filePath) => {
|
|
2421
2503
|
const editor = resolveEditor();
|
|
2422
2504
|
const terminal = isTerminalEditor(editor.command);
|
|
2423
2505
|
setIsEditing(true);
|
|
@@ -2956,7 +3038,7 @@ function PipelineBuilder({
|
|
|
2956
3038
|
}
|
|
2957
3039
|
|
|
2958
3040
|
// src/screens/PipelineExecution.tsx
|
|
2959
|
-
import { useState as useState16, useEffect as
|
|
3041
|
+
import { useState as useState16, useEffect as useEffect8, useMemo as useMemo7 } from "react";
|
|
2960
3042
|
import { Box as Box21, Text as Text25 } from "ink";
|
|
2961
3043
|
|
|
2962
3044
|
// src/components/StepIndicator.tsx
|
|
@@ -3052,7 +3134,7 @@ function PipelineExecution({
|
|
|
3052
3134
|
const [phase, setPhase] = useState16("running");
|
|
3053
3135
|
const [progress, setProgress] = useState16(null);
|
|
3054
3136
|
const [results, setResults] = useState16([]);
|
|
3055
|
-
|
|
3137
|
+
useEffect8(() => {
|
|
3056
3138
|
if (!pipeline) return;
|
|
3057
3139
|
executePipeline(pipeline, (p) => {
|
|
3058
3140
|
setProgress({ ...p });
|
|
@@ -3259,23 +3341,8 @@ function AppClassic() {
|
|
|
3259
3341
|
import React19 from "react";
|
|
3260
3342
|
import { Box as Box30, Text as Text33, useApp as useApp2, useInput as useInput9 } from "ink";
|
|
3261
3343
|
|
|
3262
|
-
// src/hooks/useFullscreen.ts
|
|
3263
|
-
import { useEffect as useEffect8 } from "react";
|
|
3264
|
-
var ENTER_ALT_SCREEN = "\x1B[?1049h";
|
|
3265
|
-
var LEAVE_ALT_SCREEN = "\x1B[?1049l";
|
|
3266
|
-
var HIDE_CURSOR = "\x1B[?25l";
|
|
3267
|
-
var SHOW_CURSOR = "\x1B[?25h";
|
|
3268
|
-
function useFullscreen() {
|
|
3269
|
-
useEffect8(() => {
|
|
3270
|
-
process.stdout.write(ENTER_ALT_SCREEN + HIDE_CURSOR);
|
|
3271
|
-
return () => {
|
|
3272
|
-
process.stdout.write(SHOW_CURSOR + LEAVE_ALT_SCREEN);
|
|
3273
|
-
};
|
|
3274
|
-
}, []);
|
|
3275
|
-
}
|
|
3276
|
-
|
|
3277
3344
|
// src/hooks/usePanelNavigation.ts
|
|
3278
|
-
import { useState as useState17, useCallback as
|
|
3345
|
+
import { useState as useState17, useCallback as useCallback5 } from "react";
|
|
3279
3346
|
function usePanelNavigation() {
|
|
3280
3347
|
const [state, setState] = useState17({
|
|
3281
3348
|
view: "pipelines",
|
|
@@ -3284,7 +3351,7 @@ function usePanelNavigation() {
|
|
|
3284
3351
|
innerParams: {},
|
|
3285
3352
|
innerStack: []
|
|
3286
3353
|
});
|
|
3287
|
-
const selectSidebarItem =
|
|
3354
|
+
const selectSidebarItem = useCallback5((itemId) => {
|
|
3288
3355
|
const featureIds = [
|
|
3289
3356
|
"database",
|
|
3290
3357
|
"functions",
|
|
@@ -3325,7 +3392,7 @@ function usePanelNavigation() {
|
|
|
3325
3392
|
});
|
|
3326
3393
|
}
|
|
3327
3394
|
}, [state.featureId]);
|
|
3328
|
-
const navigateInner =
|
|
3395
|
+
const navigateInner = useCallback5((screen, params) => {
|
|
3329
3396
|
setState((prev) => ({
|
|
3330
3397
|
...prev,
|
|
3331
3398
|
innerStack: [...prev.innerStack, { screen: prev.innerScreen, params: prev.innerParams }],
|
|
@@ -3333,7 +3400,7 @@ function usePanelNavigation() {
|
|
|
3333
3400
|
innerParams: params ?? {}
|
|
3334
3401
|
}));
|
|
3335
3402
|
}, []);
|
|
3336
|
-
const goBackInner =
|
|
3403
|
+
const goBackInner = useCallback5(() => {
|
|
3337
3404
|
setState((prev) => {
|
|
3338
3405
|
if (prev.innerStack.length === 0) {
|
|
3339
3406
|
return { ...prev, innerScreen: "home", innerParams: {} };
|
|
@@ -3348,7 +3415,7 @@ function usePanelNavigation() {
|
|
|
3348
3415
|
};
|
|
3349
3416
|
});
|
|
3350
3417
|
}, []);
|
|
3351
|
-
const goHomeInner =
|
|
3418
|
+
const goHomeInner = useCallback5(() => {
|
|
3352
3419
|
setState((prev) => ({
|
|
3353
3420
|
...prev,
|
|
3354
3421
|
innerScreen: "home",
|
|
@@ -3356,7 +3423,7 @@ function usePanelNavigation() {
|
|
|
3356
3423
|
innerStack: []
|
|
3357
3424
|
}));
|
|
3358
3425
|
}, []);
|
|
3359
|
-
const switchViewAndNavigate =
|
|
3426
|
+
const switchViewAndNavigate = useCallback5(
|
|
3360
3427
|
(view, screen, params) => {
|
|
3361
3428
|
setState((prev) => ({
|
|
3362
3429
|
...prev,
|
|
@@ -3379,14 +3446,14 @@ function usePanelNavigation() {
|
|
|
3379
3446
|
}
|
|
3380
3447
|
|
|
3381
3448
|
// src/hooks/usePanelFocus.ts
|
|
3382
|
-
import { useState as useState18, useCallback as
|
|
3449
|
+
import { useState as useState18, useCallback as useCallback6 } from "react";
|
|
3383
3450
|
function usePanelFocus() {
|
|
3384
3451
|
const [focused, setFocused] = useState18("sidebar");
|
|
3385
|
-
const toggleFocus =
|
|
3452
|
+
const toggleFocus = useCallback6(() => {
|
|
3386
3453
|
setFocused((prev) => prev === "sidebar" ? "main" : "sidebar");
|
|
3387
3454
|
}, []);
|
|
3388
|
-
const focusSidebar =
|
|
3389
|
-
const focusMain =
|
|
3455
|
+
const focusSidebar = useCallback6(() => setFocused("sidebar"), []);
|
|
3456
|
+
const focusMain = useCallback6(() => setFocused("main"), []);
|
|
3390
3457
|
return {
|
|
3391
3458
|
focused,
|
|
3392
3459
|
isSidebarFocused: focused === "sidebar",
|
|
@@ -3425,13 +3492,13 @@ function useSidebarItems() {
|
|
|
3425
3492
|
}
|
|
3426
3493
|
|
|
3427
3494
|
// src/hooks/useModal.ts
|
|
3428
|
-
import { useState as useState19, useCallback as
|
|
3495
|
+
import { useState as useState19, useCallback as useCallback7 } from "react";
|
|
3429
3496
|
function useModal() {
|
|
3430
3497
|
const [state, setState] = useState19(null);
|
|
3431
|
-
const openModal =
|
|
3498
|
+
const openModal = useCallback7((content, title) => {
|
|
3432
3499
|
setState({ content, title });
|
|
3433
3500
|
}, []);
|
|
3434
|
-
const closeModal =
|
|
3501
|
+
const closeModal = useCallback7(() => {
|
|
3435
3502
|
setState(null);
|
|
3436
3503
|
}, []);
|
|
3437
3504
|
return {
|
|
@@ -4183,6 +4250,7 @@ function AppPanel() {
|
|
|
4183
4250
|
{
|
|
4184
4251
|
args: nav.innerParams.args ?? [],
|
|
4185
4252
|
tool: nav.innerParams.tool,
|
|
4253
|
+
interactive: nav.innerParams.interactive,
|
|
4186
4254
|
onNavigate: nav.navigateInner,
|
|
4187
4255
|
onBack: nav.goBackInner,
|
|
4188
4256
|
width: w,
|
|
@@ -4198,6 +4266,7 @@ function AppPanel() {
|
|
|
4198
4266
|
{
|
|
4199
4267
|
args: nav.innerParams.args ?? [],
|
|
4200
4268
|
tool: nav.innerParams.tool,
|
|
4269
|
+
interactive: nav.innerParams.interactive,
|
|
4201
4270
|
onBack: nav.goBackInner,
|
|
4202
4271
|
onHome: nav.goHomeInner,
|
|
4203
4272
|
onExit: handleExit,
|
package/dist/mcp.js
CHANGED