@polterware/polter 0.3.1 → 0.4.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 +15 -2
- package/dist/chunk-VYHW3UNY.js +108 -0
- package/dist/{chunk-7MIUDIAI.js → chunk-ZHVOYB5M.js} +284 -60
- package/dist/index.js +956 -515
- package/dist/mcp.js +250 -14
- package/package.json +1 -1
- package/dist/chunk-AGVTFYXU.js +0 -0
package/dist/api.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
createIpcClient
|
|
3
|
+
} from "./chunk-VYHW3UNY.js";
|
|
2
4
|
import {
|
|
3
5
|
allCommands,
|
|
4
6
|
applyActions,
|
|
7
|
+
createIpcServer,
|
|
5
8
|
deletePipeline,
|
|
6
9
|
detectPkgManager,
|
|
7
10
|
executePipeline,
|
|
8
11
|
features,
|
|
9
12
|
findPipelineByName,
|
|
13
|
+
findProcessesByCwd,
|
|
14
|
+
findRunningByCommand,
|
|
10
15
|
generateProcessId,
|
|
11
16
|
getAllPipelines,
|
|
12
17
|
getCommandById,
|
|
@@ -17,6 +22,8 @@ import {
|
|
|
17
22
|
getFlagsForTool,
|
|
18
23
|
getMcpStatusInfo,
|
|
19
24
|
getProcessOutput,
|
|
25
|
+
getSocketPath,
|
|
26
|
+
getToolDisplayName,
|
|
20
27
|
getToolInfo,
|
|
21
28
|
installMcpServerSilent,
|
|
22
29
|
isProcessRunning,
|
|
@@ -33,15 +40,19 @@ import {
|
|
|
33
40
|
stopProcess,
|
|
34
41
|
toolFlags,
|
|
35
42
|
translateCommand
|
|
36
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-ZHVOYB5M.js";
|
|
37
44
|
export {
|
|
38
45
|
allCommands,
|
|
39
46
|
applyActions,
|
|
47
|
+
createIpcClient,
|
|
48
|
+
createIpcServer,
|
|
40
49
|
deletePipeline,
|
|
41
50
|
detectPkgManager,
|
|
42
51
|
executePipeline,
|
|
43
52
|
features,
|
|
44
53
|
findPipelineByName,
|
|
54
|
+
findProcessesByCwd,
|
|
55
|
+
findRunningByCommand,
|
|
45
56
|
generateProcessId,
|
|
46
57
|
getAllPipelines,
|
|
47
58
|
getCommandById,
|
|
@@ -52,6 +63,8 @@ export {
|
|
|
52
63
|
getFlagsForTool,
|
|
53
64
|
getMcpStatusInfo,
|
|
54
65
|
getProcessOutput,
|
|
66
|
+
getSocketPath,
|
|
67
|
+
getToolDisplayName,
|
|
55
68
|
getToolInfo,
|
|
56
69
|
installMcpServerSilent,
|
|
57
70
|
isProcessRunning,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseMessages,
|
|
3
|
+
serializeMessage
|
|
4
|
+
} from "./chunk-ZHVOYB5M.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/ipcClient.ts
|
|
7
|
+
import net from "net";
|
|
8
|
+
var DEFAULT_TIMEOUT = 5e3;
|
|
9
|
+
function createIpcClient(socketPath) {
|
|
10
|
+
let socket = null;
|
|
11
|
+
let connected = false;
|
|
12
|
+
let nextId = 1;
|
|
13
|
+
let buffer = "";
|
|
14
|
+
const pending = /* @__PURE__ */ new Map();
|
|
15
|
+
function handleData(data) {
|
|
16
|
+
buffer += data.toString();
|
|
17
|
+
const { messages, remainder } = parseMessages(buffer);
|
|
18
|
+
buffer = remainder;
|
|
19
|
+
for (const msg of messages) {
|
|
20
|
+
if ("id" in msg && !("method" in msg)) {
|
|
21
|
+
const resp = msg;
|
|
22
|
+
const entry = pending.get(resp.id);
|
|
23
|
+
if (entry) {
|
|
24
|
+
pending.delete(resp.id);
|
|
25
|
+
if (resp.error) {
|
|
26
|
+
entry.reject(new Error(resp.error.message));
|
|
27
|
+
} else {
|
|
28
|
+
entry.resolve(resp.result);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
connect() {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
socket = net.createConnection(socketPath);
|
|
38
|
+
socket.on("connect", () => {
|
|
39
|
+
connected = true;
|
|
40
|
+
resolve();
|
|
41
|
+
});
|
|
42
|
+
socket.on("data", handleData);
|
|
43
|
+
socket.on("close", () => {
|
|
44
|
+
connected = false;
|
|
45
|
+
for (const entry of pending.values()) {
|
|
46
|
+
entry.reject(new Error("Connection closed"));
|
|
47
|
+
}
|
|
48
|
+
pending.clear();
|
|
49
|
+
});
|
|
50
|
+
socket.on("error", (err) => {
|
|
51
|
+
connected = false;
|
|
52
|
+
if (!connected) {
|
|
53
|
+
reject(err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
disconnect() {
|
|
59
|
+
if (socket) {
|
|
60
|
+
socket.destroy();
|
|
61
|
+
socket = null;
|
|
62
|
+
connected = false;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
isConnected() {
|
|
66
|
+
return connected;
|
|
67
|
+
},
|
|
68
|
+
call(method, params) {
|
|
69
|
+
if (!socket || !connected) {
|
|
70
|
+
return Promise.reject(new Error("Not connected"));
|
|
71
|
+
}
|
|
72
|
+
const id = nextId++;
|
|
73
|
+
const request = {
|
|
74
|
+
jsonrpc: "2.0",
|
|
75
|
+
id,
|
|
76
|
+
method,
|
|
77
|
+
...params !== void 0 ? { params } : {}
|
|
78
|
+
};
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const timer = setTimeout(() => {
|
|
81
|
+
pending.delete(id);
|
|
82
|
+
reject(new Error(`RPC call "${method}" timed out after ${DEFAULT_TIMEOUT}ms`));
|
|
83
|
+
}, DEFAULT_TIMEOUT);
|
|
84
|
+
pending.set(id, {
|
|
85
|
+
resolve: (v) => {
|
|
86
|
+
clearTimeout(timer);
|
|
87
|
+
resolve(v);
|
|
88
|
+
},
|
|
89
|
+
reject: (e) => {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
reject(e);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
socket.write(serializeMessage(request));
|
|
96
|
+
} catch (err) {
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
pending.delete(id);
|
|
99
|
+
reject(err);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
createIpcClient
|
|
108
|
+
};
|
|
@@ -675,8 +675,7 @@ var gitCommands = [
|
|
|
675
675
|
|
|
676
676
|
// src/data/commands/pkg.ts
|
|
677
677
|
var pkgCommands = [
|
|
678
|
-
//
|
|
679
|
-
{ id: "pkg:build", tool: "pkg", base: ["run", "build"], label: "build", hint: "Run build script" },
|
|
678
|
+
// Publish & Version
|
|
680
679
|
{ id: "pkg:publish", tool: "pkg", base: ["publish"], label: "publish", hint: "Publish package to registry" },
|
|
681
680
|
{ id: "pkg:pack", tool: "pkg", base: ["pack"], label: "pack", hint: "Create tarball from package" },
|
|
682
681
|
{ id: "pkg:version:patch", tool: "pkg", base: ["version", "patch"], label: "version patch", hint: "Bump patch version" },
|
|
@@ -695,8 +694,7 @@ var pkgCommands = [
|
|
|
695
694
|
// Registry & Config
|
|
696
695
|
{ id: "pkg:config:list", tool: "pkg", base: ["config", "list"], label: "config list", hint: "Show config" },
|
|
697
696
|
{ id: "pkg:whoami", tool: "pkg", base: ["whoami"], label: "whoami", hint: "Show logged-in user" },
|
|
698
|
-
//
|
|
699
|
-
{ id: "pkg:run", tool: "pkg", base: ["run"], label: "run", hint: "Run a package script" },
|
|
697
|
+
// Info & Registry
|
|
700
698
|
{ id: "pkg:info", tool: "pkg", base: ["info"], label: "info", hint: "Show package info" },
|
|
701
699
|
{ id: "pkg:search", tool: "pkg", base: ["search"], label: "search", hint: "Search packages in registry" },
|
|
702
700
|
{ id: "pkg:init", tool: "pkg", base: ["init"], label: "init", hint: "Initialize a new package.json" }
|
|
@@ -863,8 +861,6 @@ var features = [
|
|
|
863
861
|
"pkg:outdated",
|
|
864
862
|
"pkg:audit",
|
|
865
863
|
"pkg:ls",
|
|
866
|
-
"pkg:build",
|
|
867
|
-
"pkg:run",
|
|
868
864
|
"pkg:publish",
|
|
869
865
|
"pkg:pack",
|
|
870
866
|
"pkg:version:patch",
|
|
@@ -993,6 +989,7 @@ function runCommand(execution, args, cwd = process.cwd(), options) {
|
|
|
993
989
|
cwd,
|
|
994
990
|
env: resolvedExecution.env,
|
|
995
991
|
shell: true,
|
|
992
|
+
detached: true,
|
|
996
993
|
stdio: [options?.quiet ? "pipe" : "inherit", "pipe", "pipe"]
|
|
997
994
|
});
|
|
998
995
|
if (options?.quiet) {
|
|
@@ -1003,11 +1000,13 @@ function runCommand(execution, args, cwd = process.cwd(), options) {
|
|
|
1003
1000
|
const text = data.toString();
|
|
1004
1001
|
stdout += text;
|
|
1005
1002
|
if (!options?.quiet) process.stdout.write(text);
|
|
1003
|
+
options?.onData?.(stdout, stderr);
|
|
1006
1004
|
});
|
|
1007
1005
|
child.stderr?.on("data", (data) => {
|
|
1008
1006
|
const text = data.toString();
|
|
1009
1007
|
stderr += text;
|
|
1010
1008
|
if (!options?.quiet) process.stderr.write(text);
|
|
1009
|
+
options?.onData?.(stdout, stderr);
|
|
1011
1010
|
});
|
|
1012
1011
|
child.on("error", (err) => {
|
|
1013
1012
|
resolve3({
|
|
@@ -1024,7 +1023,14 @@ function runCommand(execution, args, cwd = process.cwd(), options) {
|
|
|
1024
1023
|
});
|
|
1025
1024
|
return {
|
|
1026
1025
|
promise,
|
|
1027
|
-
abort: () =>
|
|
1026
|
+
abort: () => {
|
|
1027
|
+
if (child.pid) {
|
|
1028
|
+
try {
|
|
1029
|
+
process.kill(-child.pid, "SIGTERM");
|
|
1030
|
+
} catch {
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1028
1034
|
};
|
|
1029
1035
|
}
|
|
1030
1036
|
function runInteractiveCommand(execution, args, cwd = process.cwd()) {
|
|
@@ -1183,6 +1189,20 @@ function execCapture(command) {
|
|
|
1183
1189
|
}
|
|
1184
1190
|
|
|
1185
1191
|
// src/lib/toolResolver.ts
|
|
1192
|
+
function getToolDisplayName(toolId, cwd = process.cwd()) {
|
|
1193
|
+
if (toolId === "pkg") {
|
|
1194
|
+
const mgr = detectPkgManager(cwd);
|
|
1195
|
+
return mgr.id;
|
|
1196
|
+
}
|
|
1197
|
+
const names = {
|
|
1198
|
+
supabase: "supabase",
|
|
1199
|
+
gh: "github",
|
|
1200
|
+
vercel: "vercel",
|
|
1201
|
+
git: "git",
|
|
1202
|
+
pkg: "npm"
|
|
1203
|
+
};
|
|
1204
|
+
return names[toolId];
|
|
1205
|
+
}
|
|
1186
1206
|
function resolveToolCommand(toolId, cwd = process.cwd()) {
|
|
1187
1207
|
if (toolId === "supabase") {
|
|
1188
1208
|
const resolved = resolveSupabaseCommand(cwd);
|
|
@@ -1325,6 +1345,31 @@ function getToolLinkInfo(toolId, cwd = process.cwd()) {
|
|
|
1325
1345
|
|
|
1326
1346
|
// src/lib/processManager.ts
|
|
1327
1347
|
import { spawn as spawn2 } from "child_process";
|
|
1348
|
+
import { join as join5 } from "path";
|
|
1349
|
+
|
|
1350
|
+
// src/lib/packageRoot.ts
|
|
1351
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1352
|
+
import { dirname as dirname3, join as join4, resolve as resolve2 } from "path";
|
|
1353
|
+
var rootCache = /* @__PURE__ */ new Map();
|
|
1354
|
+
function findNearestPackageRoot(startDir = process.cwd()) {
|
|
1355
|
+
const resolvedStart = resolve2(startDir);
|
|
1356
|
+
if (rootCache.has(resolvedStart)) return rootCache.get(resolvedStart);
|
|
1357
|
+
let currentDir = resolvedStart;
|
|
1358
|
+
while (true) {
|
|
1359
|
+
if (existsSync4(join4(currentDir, "package.json"))) {
|
|
1360
|
+
rootCache.set(resolvedStart, currentDir);
|
|
1361
|
+
return currentDir;
|
|
1362
|
+
}
|
|
1363
|
+
const parentDir = dirname3(currentDir);
|
|
1364
|
+
if (parentDir === currentDir) {
|
|
1365
|
+
rootCache.set(resolvedStart, void 0);
|
|
1366
|
+
return void 0;
|
|
1367
|
+
}
|
|
1368
|
+
currentDir = parentDir;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// src/lib/processManager.ts
|
|
1328
1373
|
var DEFAULT_BUFFER_CAP = 1e3;
|
|
1329
1374
|
function createRingBuffer(cap = DEFAULT_BUFFER_CAP) {
|
|
1330
1375
|
return { lines: [], cap, totalLines: 0 };
|
|
@@ -1492,6 +1537,20 @@ function removeProcess(id) {
|
|
|
1492
1537
|
}
|
|
1493
1538
|
registry.delete(id);
|
|
1494
1539
|
}
|
|
1540
|
+
function findProcessesByCwd(cwd) {
|
|
1541
|
+
const normalized = cwd.replace(/\/+$/, "");
|
|
1542
|
+
return Array.from(registry.values()).filter((proc) => proc.cwd.replace(/\/+$/, "") === normalized).map(toProcessInfo);
|
|
1543
|
+
}
|
|
1544
|
+
function findRunningByCommand(cwd, command, args) {
|
|
1545
|
+
const normalized = cwd.replace(/\/+$/, "");
|
|
1546
|
+
const argsStr = args.join(" ");
|
|
1547
|
+
for (const proc of registry.values()) {
|
|
1548
|
+
if (proc.cwd.replace(/\/+$/, "") === normalized && proc.status === "running" && proc.command === command && proc.args.join(" ") === argsStr) {
|
|
1549
|
+
return toProcessInfo(proc);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return void 0;
|
|
1553
|
+
}
|
|
1495
1554
|
function toProcessInfo(proc) {
|
|
1496
1555
|
const now = Date.now();
|
|
1497
1556
|
const start = proc.startedAt.getTime();
|
|
@@ -1510,6 +1569,188 @@ function toProcessInfo(proc) {
|
|
|
1510
1569
|
uptime: end - start
|
|
1511
1570
|
};
|
|
1512
1571
|
}
|
|
1572
|
+
function getSocketPath(cwd) {
|
|
1573
|
+
const root = findNearestPackageRoot(cwd);
|
|
1574
|
+
if (!root) return void 0;
|
|
1575
|
+
return join5(root, ".polter", "polter.sock");
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
// src/lib/ipcServer.ts
|
|
1579
|
+
import net from "net";
|
|
1580
|
+
import { mkdirSync, unlinkSync, existsSync as existsSync5 } from "fs";
|
|
1581
|
+
import { dirname as dirname4 } from "path";
|
|
1582
|
+
|
|
1583
|
+
// src/lib/ipcProtocol.ts
|
|
1584
|
+
var DELIMITER = "\n";
|
|
1585
|
+
function serializeMessage(msg) {
|
|
1586
|
+
return JSON.stringify(msg) + DELIMITER;
|
|
1587
|
+
}
|
|
1588
|
+
function parseMessages(buffer) {
|
|
1589
|
+
const messages = [];
|
|
1590
|
+
let remainder = buffer;
|
|
1591
|
+
let idx;
|
|
1592
|
+
while ((idx = remainder.indexOf(DELIMITER)) !== -1) {
|
|
1593
|
+
const line = remainder.slice(0, idx);
|
|
1594
|
+
remainder = remainder.slice(idx + 1);
|
|
1595
|
+
if (line.length === 0) continue;
|
|
1596
|
+
try {
|
|
1597
|
+
messages.push(JSON.parse(line));
|
|
1598
|
+
} catch {
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
return { messages, remainder };
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
// src/lib/ipcServer.ts
|
|
1605
|
+
var handlers = {
|
|
1606
|
+
"ps.list": () => listProcesses(),
|
|
1607
|
+
"ps.start": (params) => {
|
|
1608
|
+
const { command, args, cwd, id } = params;
|
|
1609
|
+
const processArgs = args ?? [];
|
|
1610
|
+
const processId = id ?? generateProcessId(command, processArgs);
|
|
1611
|
+
const processCwd = cwd ?? process.cwd();
|
|
1612
|
+
return startProcess(processId, command, processArgs, processCwd);
|
|
1613
|
+
},
|
|
1614
|
+
"ps.stop": async (params) => {
|
|
1615
|
+
const { id } = params;
|
|
1616
|
+
return stopProcess(id);
|
|
1617
|
+
},
|
|
1618
|
+
"ps.logs": (params) => {
|
|
1619
|
+
const { id, tail, stream } = params;
|
|
1620
|
+
return getProcessOutput(id, tail, stream);
|
|
1621
|
+
},
|
|
1622
|
+
"ps.remove": (params) => {
|
|
1623
|
+
const { id } = params;
|
|
1624
|
+
removeProcess(id);
|
|
1625
|
+
return null;
|
|
1626
|
+
},
|
|
1627
|
+
"ps.find_by_cwd": (params) => {
|
|
1628
|
+
const { cwd, filter } = params;
|
|
1629
|
+
let processes = findProcessesByCwd(cwd);
|
|
1630
|
+
if (filter) {
|
|
1631
|
+
const f = filter.toLowerCase();
|
|
1632
|
+
processes = processes.filter(
|
|
1633
|
+
(p) => (p.command + " " + p.args.join(" ")).toLowerCase().includes(f)
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
return processes;
|
|
1637
|
+
},
|
|
1638
|
+
"ps.find_running": (params) => {
|
|
1639
|
+
const { cwd, command, args } = params;
|
|
1640
|
+
return findRunningByCommand(cwd, command, args) ?? null;
|
|
1641
|
+
},
|
|
1642
|
+
"ps.generate_id": (params) => {
|
|
1643
|
+
const { command, args } = params;
|
|
1644
|
+
return generateProcessId(command, args);
|
|
1645
|
+
},
|
|
1646
|
+
status: () => ({ tui: true, pid: process.pid })
|
|
1647
|
+
};
|
|
1648
|
+
async function handleRequest(req) {
|
|
1649
|
+
const handler = handlers[req.method];
|
|
1650
|
+
if (!handler) {
|
|
1651
|
+
return {
|
|
1652
|
+
jsonrpc: "2.0",
|
|
1653
|
+
id: req.id,
|
|
1654
|
+
error: { code: -32601, message: `Method not found: ${req.method}` }
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
try {
|
|
1658
|
+
const result = await handler(req.params ?? {});
|
|
1659
|
+
return { jsonrpc: "2.0", id: req.id, result };
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
return {
|
|
1662
|
+
jsonrpc: "2.0",
|
|
1663
|
+
id: req.id,
|
|
1664
|
+
error: { code: -32e3, message: err.message }
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function createIpcServer(socketPath) {
|
|
1669
|
+
let server = null;
|
|
1670
|
+
const connections = /* @__PURE__ */ new Set();
|
|
1671
|
+
function handleConnection(socket) {
|
|
1672
|
+
connections.add(socket);
|
|
1673
|
+
let buffer = "";
|
|
1674
|
+
socket.on("data", async (data) => {
|
|
1675
|
+
buffer += data.toString();
|
|
1676
|
+
const { messages, remainder } = parseMessages(buffer);
|
|
1677
|
+
buffer = remainder;
|
|
1678
|
+
for (const msg of messages) {
|
|
1679
|
+
if ("method" in msg) {
|
|
1680
|
+
const response = await handleRequest(msg);
|
|
1681
|
+
try {
|
|
1682
|
+
socket.write(serializeMessage(response));
|
|
1683
|
+
} catch {
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
});
|
|
1688
|
+
socket.on("close", () => {
|
|
1689
|
+
connections.delete(socket);
|
|
1690
|
+
});
|
|
1691
|
+
socket.on("error", () => {
|
|
1692
|
+
connections.delete(socket);
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
async function cleanStaleSocket() {
|
|
1696
|
+
if (!existsSync5(socketPath)) return;
|
|
1697
|
+
return new Promise((resolve3) => {
|
|
1698
|
+
const probe = net.createConnection(socketPath);
|
|
1699
|
+
probe.on("connect", () => {
|
|
1700
|
+
probe.destroy();
|
|
1701
|
+
resolve3();
|
|
1702
|
+
});
|
|
1703
|
+
probe.on("error", () => {
|
|
1704
|
+
try {
|
|
1705
|
+
unlinkSync(socketPath);
|
|
1706
|
+
} catch {
|
|
1707
|
+
}
|
|
1708
|
+
resolve3();
|
|
1709
|
+
});
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
return {
|
|
1713
|
+
async start() {
|
|
1714
|
+
mkdirSync(dirname4(socketPath), { recursive: true });
|
|
1715
|
+
await cleanStaleSocket();
|
|
1716
|
+
return new Promise((resolve3, reject) => {
|
|
1717
|
+
server = net.createServer(handleConnection);
|
|
1718
|
+
server.on("error", (err) => {
|
|
1719
|
+
if (err.code === "EADDRINUSE") {
|
|
1720
|
+
try {
|
|
1721
|
+
unlinkSync(socketPath);
|
|
1722
|
+
} catch {
|
|
1723
|
+
}
|
|
1724
|
+
server.listen(socketPath, () => resolve3());
|
|
1725
|
+
} else {
|
|
1726
|
+
reject(err);
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
server.listen(socketPath, () => resolve3());
|
|
1730
|
+
});
|
|
1731
|
+
},
|
|
1732
|
+
async stop() {
|
|
1733
|
+
for (const conn of connections) {
|
|
1734
|
+
conn.destroy();
|
|
1735
|
+
}
|
|
1736
|
+
connections.clear();
|
|
1737
|
+
return new Promise((resolve3) => {
|
|
1738
|
+
if (!server) {
|
|
1739
|
+
resolve3();
|
|
1740
|
+
return;
|
|
1741
|
+
}
|
|
1742
|
+
server.close(() => {
|
|
1743
|
+
try {
|
|
1744
|
+
unlinkSync(socketPath);
|
|
1745
|
+
} catch {
|
|
1746
|
+
}
|
|
1747
|
+
server = null;
|
|
1748
|
+
resolve3();
|
|
1749
|
+
});
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1513
1754
|
|
|
1514
1755
|
// src/pipeline/engine.ts
|
|
1515
1756
|
async function executePipeline(pipeline, onProgress, cwd = process.cwd()) {
|
|
@@ -1564,32 +1805,8 @@ async function executePipeline(pipeline, onProgress, cwd = process.cwd()) {
|
|
|
1564
1805
|
}
|
|
1565
1806
|
|
|
1566
1807
|
// src/config/projectConfig.ts
|
|
1567
|
-
import { existsSync as
|
|
1568
|
-
import { join as
|
|
1569
|
-
|
|
1570
|
-
// src/lib/packageRoot.ts
|
|
1571
|
-
import { existsSync as existsSync4 } from "fs";
|
|
1572
|
-
import { dirname as dirname3, join as join4, resolve as resolve2 } from "path";
|
|
1573
|
-
var rootCache = /* @__PURE__ */ new Map();
|
|
1574
|
-
function findNearestPackageRoot(startDir = process.cwd()) {
|
|
1575
|
-
const resolvedStart = resolve2(startDir);
|
|
1576
|
-
if (rootCache.has(resolvedStart)) return rootCache.get(resolvedStart);
|
|
1577
|
-
let currentDir = resolvedStart;
|
|
1578
|
-
while (true) {
|
|
1579
|
-
if (existsSync4(join4(currentDir, "package.json"))) {
|
|
1580
|
-
rootCache.set(resolvedStart, currentDir);
|
|
1581
|
-
return currentDir;
|
|
1582
|
-
}
|
|
1583
|
-
const parentDir = dirname3(currentDir);
|
|
1584
|
-
if (parentDir === currentDir) {
|
|
1585
|
-
rootCache.set(resolvedStart, void 0);
|
|
1586
|
-
return void 0;
|
|
1587
|
-
}
|
|
1588
|
-
currentDir = parentDir;
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
// src/config/projectConfig.ts
|
|
1808
|
+
import { existsSync as existsSync6, readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
1809
|
+
import { join as join6 } from "path";
|
|
1593
1810
|
var CONFIG_DIR = ".polter";
|
|
1594
1811
|
var CONFIG_FILE = "config.json";
|
|
1595
1812
|
function defaultConfig() {
|
|
@@ -1602,13 +1819,13 @@ function defaultConfig() {
|
|
|
1602
1819
|
function getProjectConfigPath(startDir) {
|
|
1603
1820
|
const root = findNearestPackageRoot(startDir);
|
|
1604
1821
|
if (!root) return void 0;
|
|
1605
|
-
const dir =
|
|
1606
|
-
return { dir, file:
|
|
1822
|
+
const dir = join6(root, CONFIG_DIR);
|
|
1823
|
+
return { dir, file: join6(dir, CONFIG_FILE) };
|
|
1607
1824
|
}
|
|
1608
1825
|
function readProjectConfig(startDir) {
|
|
1609
1826
|
const paths = getProjectConfigPath(startDir);
|
|
1610
1827
|
if (!paths) return void 0;
|
|
1611
|
-
if (!
|
|
1828
|
+
if (!existsSync6(paths.file)) return void 0;
|
|
1612
1829
|
try {
|
|
1613
1830
|
const raw = readFileSync2(paths.file, "utf-8");
|
|
1614
1831
|
return JSON.parse(raw);
|
|
@@ -1619,7 +1836,7 @@ function readProjectConfig(startDir) {
|
|
|
1619
1836
|
function writeProjectConfig(config2, startDir) {
|
|
1620
1837
|
const paths = getProjectConfigPath(startDir);
|
|
1621
1838
|
if (!paths) return false;
|
|
1622
|
-
|
|
1839
|
+
mkdirSync2(paths.dir, { recursive: true });
|
|
1623
1840
|
writeFileSync(paths.file, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
1624
1841
|
return true;
|
|
1625
1842
|
}
|
|
@@ -1709,8 +1926,8 @@ function findPipelineByName(name, startDir) {
|
|
|
1709
1926
|
}
|
|
1710
1927
|
|
|
1711
1928
|
// src/declarative/parser.ts
|
|
1712
|
-
import { existsSync as
|
|
1713
|
-
import { join as
|
|
1929
|
+
import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
|
|
1930
|
+
import { join as join7 } from "path";
|
|
1714
1931
|
var YAML_FILE = "polter.yaml";
|
|
1715
1932
|
function parseSimpleYaml(content) {
|
|
1716
1933
|
const lines = content.split("\n");
|
|
@@ -1782,8 +1999,8 @@ function parseValue(raw) {
|
|
|
1782
1999
|
return raw;
|
|
1783
2000
|
}
|
|
1784
2001
|
function findPolterYaml(startDir = process.cwd()) {
|
|
1785
|
-
const filePath =
|
|
1786
|
-
return
|
|
2002
|
+
const filePath = join7(startDir, YAML_FILE);
|
|
2003
|
+
return existsSync7(filePath) ? filePath : void 0;
|
|
1787
2004
|
}
|
|
1788
2005
|
function parsePolterYaml(startDir = process.cwd()) {
|
|
1789
2006
|
const filePath = findPolterYaml(startDir);
|
|
@@ -1929,16 +2146,16 @@ async function applyActions(actions, cwd = process.cwd(), onProgress) {
|
|
|
1929
2146
|
|
|
1930
2147
|
// src/lib/mcpInstaller.ts
|
|
1931
2148
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1932
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as
|
|
1933
|
-
import { join as
|
|
2149
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync8 } from "fs";
|
|
2150
|
+
import { join as join8, dirname as dirname5 } from "path";
|
|
1934
2151
|
import { fileURLToPath } from "url";
|
|
1935
2152
|
import { homedir } from "os";
|
|
1936
2153
|
import pc from "picocolors";
|
|
1937
|
-
var __dirname =
|
|
2154
|
+
var __dirname = dirname5(fileURLToPath(import.meta.url));
|
|
1938
2155
|
function readPkgVersion() {
|
|
1939
2156
|
for (const rel of ["../../package.json", "../package.json"]) {
|
|
1940
|
-
const p =
|
|
1941
|
-
if (
|
|
2157
|
+
const p = join8(__dirname, rel);
|
|
2158
|
+
if (existsSync8(p)) {
|
|
1942
2159
|
const pkg = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1943
2160
|
return pkg.version;
|
|
1944
2161
|
}
|
|
@@ -1961,15 +2178,15 @@ function tryClaudeCli(scope) {
|
|
|
1961
2178
|
}
|
|
1962
2179
|
function getSettingsPath(scope) {
|
|
1963
2180
|
if (scope === "project") {
|
|
1964
|
-
return
|
|
2181
|
+
return join8(process.cwd(), ".mcp.json");
|
|
1965
2182
|
}
|
|
1966
|
-
return
|
|
2183
|
+
return join8(homedir(), ".claude", "settings.json");
|
|
1967
2184
|
}
|
|
1968
2185
|
function tryManualInstall(scope) {
|
|
1969
2186
|
const settingsPath = getSettingsPath(scope);
|
|
1970
|
-
const dir =
|
|
2187
|
+
const dir = join8(settingsPath, "..");
|
|
1971
2188
|
let settings = {};
|
|
1972
|
-
if (
|
|
2189
|
+
if (existsSync8(settingsPath)) {
|
|
1973
2190
|
try {
|
|
1974
2191
|
settings = JSON.parse(readFileSync4(settingsPath, "utf-8"));
|
|
1975
2192
|
} catch {
|
|
@@ -1978,7 +2195,7 @@ function tryManualInstall(scope) {
|
|
|
1978
2195
|
return false;
|
|
1979
2196
|
}
|
|
1980
2197
|
} else {
|
|
1981
|
-
|
|
2198
|
+
mkdirSync3(dir, { recursive: true });
|
|
1982
2199
|
}
|
|
1983
2200
|
const mcpServers = settings.mcpServers ?? {};
|
|
1984
2201
|
mcpServers.polter = {
|
|
@@ -2030,7 +2247,7 @@ async function removeMcpServer(scope) {
|
|
|
2030
2247
|
process.stdout.write(pc.yellow(" 'claude mcp remove' failed, falling back to manual removal...\n\n"));
|
|
2031
2248
|
}
|
|
2032
2249
|
const settingsPath = getSettingsPath(scope);
|
|
2033
|
-
if (!
|
|
2250
|
+
if (!existsSync8(settingsPath)) {
|
|
2034
2251
|
process.stdout.write(pc.yellow(" No settings file found. Nothing to remove.\n"));
|
|
2035
2252
|
return;
|
|
2036
2253
|
}
|
|
@@ -2056,11 +2273,11 @@ async function removeMcpServer(scope) {
|
|
|
2056
2273
|
function getMcpStatusInfo() {
|
|
2057
2274
|
const version = readPkgVersion();
|
|
2058
2275
|
const scopeDefs = [
|
|
2059
|
-
{ label: "Project (.mcp.json)", path:
|
|
2060
|
-
{ label: "User (~/.claude/settings.json)", path:
|
|
2276
|
+
{ label: "Project (.mcp.json)", path: join8(process.cwd(), ".mcp.json"), scope: "project" },
|
|
2277
|
+
{ label: "User (~/.claude/settings.json)", path: join8(homedir(), ".claude", "settings.json"), scope: "user" }
|
|
2061
2278
|
];
|
|
2062
2279
|
const scopes = scopeDefs.map((s) => {
|
|
2063
|
-
if (!
|
|
2280
|
+
if (!existsSync8(s.path)) {
|
|
2064
2281
|
return { label: s.label, scope: s.scope, registered: false };
|
|
2065
2282
|
}
|
|
2066
2283
|
try {
|
|
@@ -2107,7 +2324,7 @@ async function removeMcpServerSilent(scope) {
|
|
|
2107
2324
|
messages.push("'claude mcp remove' failed, falling back to manual removal...");
|
|
2108
2325
|
}
|
|
2109
2326
|
const settingsPath = getSettingsPath(scope);
|
|
2110
|
-
if (!
|
|
2327
|
+
if (!existsSync8(settingsPath)) {
|
|
2111
2328
|
messages.push("No settings file found. Nothing to remove.");
|
|
2112
2329
|
return { success: true, message: messages.join("\n") };
|
|
2113
2330
|
}
|
|
@@ -2146,11 +2363,11 @@ async function mcpStatus() {
|
|
|
2146
2363
|
}
|
|
2147
2364
|
process.stdout.write("\n");
|
|
2148
2365
|
const scopes = [
|
|
2149
|
-
{ label: "Project (.mcp.json)", path:
|
|
2150
|
-
{ label: "User (~/.claude/settings.json)", path:
|
|
2366
|
+
{ label: "Project (.mcp.json)", path: join8(process.cwd(), ".mcp.json"), key: "project" },
|
|
2367
|
+
{ label: "User (~/.claude/settings.json)", path: join8(homedir(), ".claude", "settings.json"), key: "user" }
|
|
2151
2368
|
];
|
|
2152
2369
|
for (const scope of scopes) {
|
|
2153
|
-
if (!
|
|
2370
|
+
if (!existsSync8(scope.path)) {
|
|
2154
2371
|
process.stdout.write(` ${scope.label}: ${pc.dim("not found")}
|
|
2155
2372
|
`);
|
|
2156
2373
|
continue;
|
|
@@ -2190,9 +2407,11 @@ export {
|
|
|
2190
2407
|
detectPkgManager,
|
|
2191
2408
|
translateCommand,
|
|
2192
2409
|
resolvePkgArgs,
|
|
2410
|
+
getToolDisplayName,
|
|
2193
2411
|
resolveToolCommand,
|
|
2194
2412
|
getToolInfo,
|
|
2195
2413
|
getToolLinkInfo,
|
|
2414
|
+
findNearestPackageRoot,
|
|
2196
2415
|
generateProcessId,
|
|
2197
2416
|
startProcess,
|
|
2198
2417
|
stopProcess,
|
|
@@ -2200,8 +2419,13 @@ export {
|
|
|
2200
2419
|
getProcessOutput,
|
|
2201
2420
|
isProcessRunning,
|
|
2202
2421
|
removeProcess,
|
|
2422
|
+
findProcessesByCwd,
|
|
2423
|
+
findRunningByCommand,
|
|
2424
|
+
getSocketPath,
|
|
2425
|
+
serializeMessage,
|
|
2426
|
+
parseMessages,
|
|
2427
|
+
createIpcServer,
|
|
2203
2428
|
executePipeline,
|
|
2204
|
-
findNearestPackageRoot,
|
|
2205
2429
|
getProjectConfigPath,
|
|
2206
2430
|
writeProjectConfig,
|
|
2207
2431
|
getOrCreateProjectConfig,
|