@polterware/polter 0.4.2 → 0.5.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/README.md +70 -184
- package/dist/api.js +62 -30
- package/dist/app-HGIGWI7F.js +393 -0
- package/dist/appPanel-EZOHLTBX.js +1365 -0
- package/dist/applier-OEXIUYYO.js +10 -0
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-45CQFZU7.js +262 -0
- package/dist/chunk-57CZSEY5.js +5398 -0
- package/dist/chunk-6IBRTRLX.js +257 -0
- package/dist/chunk-AK3NTS3Y.js +220 -0
- package/dist/chunk-BGT5TT2A.js +32 -0
- package/dist/chunk-BIN7BDA2.js +77 -0
- package/dist/chunk-E2B5FFBU.js +81 -0
- package/dist/chunk-EAMHFQKU.js +222 -0
- package/dist/chunk-ELSIHPJL.js +455 -0
- package/dist/{chunk-XCCKD3RZ.js → chunk-GCS7JEYU.js} +7 -3
- package/dist/chunk-GKROVUDG.js +15 -0
- package/dist/chunk-GVIKF6UI.js +738 -0
- package/dist/chunk-JQB2A3CA.js +72 -0
- package/dist/chunk-KEGROLGX.js +50 -0
- package/dist/chunk-OKHPN6X7.js +49 -0
- package/dist/chunk-RVMOIUSL.js +22 -0
- package/dist/chunk-TD6YNU6L.js +22 -0
- package/dist/chunk-U64WZOJ3.js +101 -0
- package/dist/chunk-U6725U7K.js +138 -0
- package/dist/chunk-XNRIN3VM.js +125 -0
- package/dist/chunk-ZU5VZHYD.js +28 -0
- package/dist/commands-BIIWGCVS.js +15 -0
- package/dist/editor-AUFJZ4PE.js +11 -0
- package/dist/engine-EZQ26HDJ.js +11 -0
- package/dist/globalConf-AGMMIKSL.js +7 -0
- package/dist/index.js +49 -7601
- package/dist/ipcServer-HXOPKNBP.js +10 -0
- package/dist/mcp.js +182 -13892
- package/dist/mcpInstaller-J2AGFNWR.js +19 -0
- package/dist/parser-4ZBGSI2U.js +10 -0
- package/dist/planner-ZVBA66V6.js +9 -0
- package/dist/processManager-6T5DBURV.js +37 -0
- package/dist/projectConfig-TRCJS3VI.js +21 -0
- package/dist/skillSetup-ZQEHJ5ZG.js +14 -0
- package/dist/status-QMRCV4XJ.js +8 -0
- package/dist/storage-C3D7TLJW.js +17 -0
- package/dist/toolResolver-A2BUT3NK.js +17 -0
- package/package.json +28 -3
- package/dist/chunk-CWBIXRZP.js +0 -2607
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findNearestPackageRoot
|
|
3
|
+
} from "./chunk-ZU5VZHYD.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/processManager.ts
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { execa } from "execa";
|
|
8
|
+
import ms from "ms";
|
|
9
|
+
import { onExit } from "signal-exit";
|
|
10
|
+
|
|
11
|
+
// src/lib/processEvents.ts
|
|
12
|
+
import EE from "eventemitter3";
|
|
13
|
+
var EventEmitter = EE.EventEmitter ?? EE;
|
|
14
|
+
var processEvents = new EventEmitter();
|
|
15
|
+
|
|
16
|
+
// src/lib/processManager.ts
|
|
17
|
+
var DEFAULT_BUFFER_CAP = 1e3;
|
|
18
|
+
function createRingBuffer(cap = DEFAULT_BUFFER_CAP) {
|
|
19
|
+
return { lines: [], cap, totalLines: 0 };
|
|
20
|
+
}
|
|
21
|
+
function appendToBuffer(buf, data) {
|
|
22
|
+
const newLines = data.split("\n");
|
|
23
|
+
if (newLines.length > 0 && newLines[newLines.length - 1] === "") {
|
|
24
|
+
newLines.pop();
|
|
25
|
+
}
|
|
26
|
+
if (newLines.length === 0) return;
|
|
27
|
+
buf.lines.push(...newLines);
|
|
28
|
+
buf.totalLines += newLines.length;
|
|
29
|
+
if (buf.lines.length > buf.cap) {
|
|
30
|
+
buf.lines.splice(0, buf.lines.length - buf.cap);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function tailBuffer(buf, n) {
|
|
34
|
+
if (n === void 0 || n >= buf.lines.length) return [...buf.lines];
|
|
35
|
+
return buf.lines.slice(-n);
|
|
36
|
+
}
|
|
37
|
+
var registry = /* @__PURE__ */ new Map();
|
|
38
|
+
var cleanupRegistered = false;
|
|
39
|
+
function registerCleanup() {
|
|
40
|
+
if (cleanupRegistered) return;
|
|
41
|
+
cleanupRegistered = true;
|
|
42
|
+
onExit(() => {
|
|
43
|
+
for (const proc of registry.values()) {
|
|
44
|
+
if (proc.status === "running" && proc.child.pid) {
|
|
45
|
+
try {
|
|
46
|
+
process.kill(-proc.child.pid, "SIGKILL");
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, { alwaysLast: true });
|
|
52
|
+
}
|
|
53
|
+
function generateProcessId(command, args) {
|
|
54
|
+
const slug = [command, ...args].join("-").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
|
|
55
|
+
if (!registry.has(slug)) return slug;
|
|
56
|
+
let i = 2;
|
|
57
|
+
while (registry.has(`${slug}-${i}`)) i++;
|
|
58
|
+
return `${slug}-${i}`;
|
|
59
|
+
}
|
|
60
|
+
function trackChild(id, command, args, cwd, child) {
|
|
61
|
+
const existing = registry.get(id);
|
|
62
|
+
if (existing && existing.status === "running") {
|
|
63
|
+
throw new Error(`Process "${id}" is already running (pid ${existing.child.pid})`);
|
|
64
|
+
}
|
|
65
|
+
registerCleanup();
|
|
66
|
+
const tracked = {
|
|
67
|
+
id,
|
|
68
|
+
command,
|
|
69
|
+
args,
|
|
70
|
+
cwd,
|
|
71
|
+
child,
|
|
72
|
+
status: "running",
|
|
73
|
+
exitCode: null,
|
|
74
|
+
signal: null,
|
|
75
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
76
|
+
exitedAt: null,
|
|
77
|
+
stdout: createRingBuffer(),
|
|
78
|
+
stderr: createRingBuffer()
|
|
79
|
+
};
|
|
80
|
+
child.stdout?.on("data", (data) => {
|
|
81
|
+
const text = data.toString();
|
|
82
|
+
appendToBuffer(tracked.stdout, text);
|
|
83
|
+
processEvents.emit("output", id, "stdout", text);
|
|
84
|
+
});
|
|
85
|
+
child.stderr?.on("data", (data) => {
|
|
86
|
+
const text = data.toString();
|
|
87
|
+
appendToBuffer(tracked.stderr, text);
|
|
88
|
+
processEvents.emit("output", id, "stderr", text);
|
|
89
|
+
});
|
|
90
|
+
child.on("exit", (code, signal) => {
|
|
91
|
+
tracked.status = "exited";
|
|
92
|
+
tracked.exitCode = code;
|
|
93
|
+
tracked.signal = signal;
|
|
94
|
+
tracked.exitedAt = /* @__PURE__ */ new Date();
|
|
95
|
+
processEvents.emit("stopped", toProcessInfo(tracked));
|
|
96
|
+
});
|
|
97
|
+
child.on("error", (err) => {
|
|
98
|
+
tracked.status = "errored";
|
|
99
|
+
tracked.exitedAt = /* @__PURE__ */ new Date();
|
|
100
|
+
appendToBuffer(tracked.stderr, `spawn error: ${err.message}
|
|
101
|
+
`);
|
|
102
|
+
processEvents.emit("errored", toProcessInfo(tracked), err.message);
|
|
103
|
+
});
|
|
104
|
+
registry.set(id, tracked);
|
|
105
|
+
const info = toProcessInfo(tracked);
|
|
106
|
+
processEvents.emit("started", info);
|
|
107
|
+
return info;
|
|
108
|
+
}
|
|
109
|
+
function startProcess(id, command, args = [], cwd = process.cwd(), env) {
|
|
110
|
+
const subprocess = execa(command, args, {
|
|
111
|
+
cwd,
|
|
112
|
+
env: env ?? process.env,
|
|
113
|
+
detached: true,
|
|
114
|
+
stdin: "ignore",
|
|
115
|
+
stdout: "pipe",
|
|
116
|
+
stderr: "pipe",
|
|
117
|
+
shell: true,
|
|
118
|
+
reject: false
|
|
119
|
+
});
|
|
120
|
+
return trackChild(id, command, args, cwd, subprocess);
|
|
121
|
+
}
|
|
122
|
+
function registerForegroundProcess(id, command, args, cwd, child) {
|
|
123
|
+
return trackChild(id, command, args, cwd, child);
|
|
124
|
+
}
|
|
125
|
+
function stopProcess(id) {
|
|
126
|
+
const proc = registry.get(id);
|
|
127
|
+
if (!proc) throw new Error(`No tracked process with id "${id}"`);
|
|
128
|
+
if (proc.status !== "running") return Promise.resolve(toProcessInfo(proc));
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
const escalateTimer = setTimeout(() => {
|
|
131
|
+
if (proc.status === "running" && proc.child.pid) {
|
|
132
|
+
try {
|
|
133
|
+
process.kill(-proc.child.pid, "SIGKILL");
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}, ms("5s"));
|
|
138
|
+
const onDone = () => {
|
|
139
|
+
clearTimeout(escalateTimer);
|
|
140
|
+
resolve(toProcessInfo(proc));
|
|
141
|
+
};
|
|
142
|
+
proc.child.once("exit", onDone);
|
|
143
|
+
if (proc.child.pid) {
|
|
144
|
+
try {
|
|
145
|
+
process.kill(-proc.child.pid, "SIGTERM");
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (proc.status !== "running") {
|
|
150
|
+
clearTimeout(escalateTimer);
|
|
151
|
+
proc.child.removeListener("exit", onDone);
|
|
152
|
+
resolve(toProcessInfo(proc));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function listProcesses() {
|
|
157
|
+
return Array.from(registry.values()).map(toProcessInfo).reverse();
|
|
158
|
+
}
|
|
159
|
+
function getProcessOutput(id, tail, stream) {
|
|
160
|
+
const proc = registry.get(id);
|
|
161
|
+
if (!proc) throw new Error(`No tracked process with id "${id}"`);
|
|
162
|
+
const which = stream ?? "both";
|
|
163
|
+
return {
|
|
164
|
+
stdout: which === "stderr" ? [] : tailBuffer(proc.stdout, tail),
|
|
165
|
+
stderr: which === "stdout" ? [] : tailBuffer(proc.stderr, tail),
|
|
166
|
+
stdoutLineCount: proc.stdout.totalLines,
|
|
167
|
+
stderrLineCount: proc.stderr.totalLines
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function isProcessRunning(id) {
|
|
171
|
+
const proc = registry.get(id);
|
|
172
|
+
if (!proc) return false;
|
|
173
|
+
if (proc.status !== "running") return false;
|
|
174
|
+
if (proc.child.pid) {
|
|
175
|
+
try {
|
|
176
|
+
process.kill(proc.child.pid, 0);
|
|
177
|
+
return true;
|
|
178
|
+
} catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
function removeProcess(id) {
|
|
185
|
+
const proc = registry.get(id);
|
|
186
|
+
if (!proc) throw new Error(`No tracked process with id "${id}"`);
|
|
187
|
+
if (proc.status === "running") {
|
|
188
|
+
throw new Error(`Cannot remove running process "${id}". Stop it first.`);
|
|
189
|
+
}
|
|
190
|
+
registry.delete(id);
|
|
191
|
+
}
|
|
192
|
+
function findProcessesByCwd(cwd) {
|
|
193
|
+
const normalized = cwd.replace(/\/+$/, "");
|
|
194
|
+
return Array.from(registry.values()).filter((proc) => proc.cwd.replace(/\/+$/, "") === normalized).map(toProcessInfo);
|
|
195
|
+
}
|
|
196
|
+
function findRunningByCommand(cwd, command, args) {
|
|
197
|
+
const normalized = cwd.replace(/\/+$/, "");
|
|
198
|
+
const argsStr = args.join(" ");
|
|
199
|
+
for (const proc of registry.values()) {
|
|
200
|
+
if (proc.cwd.replace(/\/+$/, "") === normalized && proc.status === "running" && proc.command === command && proc.args.join(" ") === argsStr) {
|
|
201
|
+
return toProcessInfo(proc);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return void 0;
|
|
205
|
+
}
|
|
206
|
+
function toProcessInfo(proc) {
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
const start = proc.startedAt.getTime();
|
|
209
|
+
const end = proc.exitedAt ? proc.exitedAt.getTime() : now;
|
|
210
|
+
return {
|
|
211
|
+
id: proc.id,
|
|
212
|
+
command: proc.command,
|
|
213
|
+
args: proc.args,
|
|
214
|
+
cwd: proc.cwd,
|
|
215
|
+
pid: proc.child.pid,
|
|
216
|
+
status: proc.status,
|
|
217
|
+
exitCode: proc.exitCode,
|
|
218
|
+
signal: proc.signal,
|
|
219
|
+
startedAt: proc.startedAt.toISOString(),
|
|
220
|
+
exitedAt: proc.exitedAt?.toISOString() ?? null,
|
|
221
|
+
uptime: end - start
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function _resetForTests() {
|
|
225
|
+
for (const proc of registry.values()) {
|
|
226
|
+
if (proc.status === "running" && proc.child.pid) {
|
|
227
|
+
try {
|
|
228
|
+
process.kill(-proc.child.pid, "SIGKILL");
|
|
229
|
+
} catch {
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
registry.clear();
|
|
234
|
+
}
|
|
235
|
+
function getSocketPath(cwd) {
|
|
236
|
+
const root = findNearestPackageRoot(cwd);
|
|
237
|
+
if (!root) return void 0;
|
|
238
|
+
return join(root, ".polter", "polter.sock");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export {
|
|
242
|
+
createRingBuffer,
|
|
243
|
+
appendToBuffer,
|
|
244
|
+
tailBuffer,
|
|
245
|
+
generateProcessId,
|
|
246
|
+
startProcess,
|
|
247
|
+
registerForegroundProcess,
|
|
248
|
+
stopProcess,
|
|
249
|
+
listProcesses,
|
|
250
|
+
getProcessOutput,
|
|
251
|
+
isProcessRunning,
|
|
252
|
+
removeProcess,
|
|
253
|
+
findProcessesByCwd,
|
|
254
|
+
findRunningByCommand,
|
|
255
|
+
_resetForTests,
|
|
256
|
+
getSocketPath
|
|
257
|
+
};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ghCommands,
|
|
3
|
+
gitCommands,
|
|
4
|
+
pkgCommands,
|
|
5
|
+
supabaseCommands,
|
|
6
|
+
vercelCommands
|
|
7
|
+
} from "./chunk-GVIKF6UI.js";
|
|
8
|
+
|
|
9
|
+
// src/data/features.ts
|
|
10
|
+
var allSources = [...supabaseCommands, ...ghCommands, ...vercelCommands, ...gitCommands, ...pkgCommands];
|
|
11
|
+
var allSourceIds = new Set(allSources.map((cmd) => cmd.id));
|
|
12
|
+
function pick(ids) {
|
|
13
|
+
if (process.env.NODE_ENV !== "production") {
|
|
14
|
+
for (const id of ids) {
|
|
15
|
+
if (!allSourceIds.has(id)) {
|
|
16
|
+
throw new Error(`features.ts: unknown command ID "${id}". Check your feature definitions.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const idSet = new Set(ids);
|
|
21
|
+
return allSources.filter((cmd) => idSet.has(cmd.id));
|
|
22
|
+
}
|
|
23
|
+
var features = [
|
|
24
|
+
{
|
|
25
|
+
id: "database",
|
|
26
|
+
icon: "\u{1F5C4}\uFE0F",
|
|
27
|
+
label: "Database",
|
|
28
|
+
commands: pick([
|
|
29
|
+
"supabase:db",
|
|
30
|
+
"supabase:migration",
|
|
31
|
+
"supabase:seed",
|
|
32
|
+
"supabase:inspect"
|
|
33
|
+
])
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "functions",
|
|
37
|
+
icon: "\u26A1",
|
|
38
|
+
label: "Functions",
|
|
39
|
+
commands: pick([
|
|
40
|
+
"supabase:functions"
|
|
41
|
+
])
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "deploy",
|
|
45
|
+
icon: "\u{1F680}",
|
|
46
|
+
label: "Deploy",
|
|
47
|
+
commands: pick([
|
|
48
|
+
"supabase:db",
|
|
49
|
+
"supabase:functions",
|
|
50
|
+
"vercel:deploy",
|
|
51
|
+
"vercel:deploy:prod",
|
|
52
|
+
"vercel:promote",
|
|
53
|
+
"vercel:rollback",
|
|
54
|
+
"git:commit",
|
|
55
|
+
"git:push"
|
|
56
|
+
])
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "repo",
|
|
60
|
+
icon: "\u{1F5C3}\uFE0F",
|
|
61
|
+
label: "Repo",
|
|
62
|
+
commands: pick([
|
|
63
|
+
"git:status",
|
|
64
|
+
"git:add",
|
|
65
|
+
"git:commit",
|
|
66
|
+
"git:push",
|
|
67
|
+
"git:pull",
|
|
68
|
+
"git:branch",
|
|
69
|
+
"git:checkout",
|
|
70
|
+
"git:log",
|
|
71
|
+
"git:diff",
|
|
72
|
+
"git:merge",
|
|
73
|
+
"git:stash",
|
|
74
|
+
"gh:repo:clone",
|
|
75
|
+
"gh:repo:create",
|
|
76
|
+
"gh:repo:view",
|
|
77
|
+
"gh:repo:list",
|
|
78
|
+
"gh:pr:create",
|
|
79
|
+
"gh:pr:list",
|
|
80
|
+
"gh:pr:view",
|
|
81
|
+
"gh:pr:merge",
|
|
82
|
+
"gh:pr:checkout",
|
|
83
|
+
"gh:pr:review",
|
|
84
|
+
"gh:issue:create",
|
|
85
|
+
"gh:issue:list",
|
|
86
|
+
"gh:issue:view",
|
|
87
|
+
"gh:issue:close",
|
|
88
|
+
"gh:release:create",
|
|
89
|
+
"gh:release:list",
|
|
90
|
+
"gh:release:view"
|
|
91
|
+
])
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "cicd",
|
|
95
|
+
icon: "\u{1F504}",
|
|
96
|
+
label: "CI/CD",
|
|
97
|
+
commands: pick([
|
|
98
|
+
"vercel:env:ls",
|
|
99
|
+
"vercel:env:add",
|
|
100
|
+
"vercel:env:rm",
|
|
101
|
+
"vercel:env:pull",
|
|
102
|
+
"gh:workflow:list",
|
|
103
|
+
"gh:workflow:run",
|
|
104
|
+
"gh:workflow:view",
|
|
105
|
+
"gh:run:list",
|
|
106
|
+
"gh:run:view",
|
|
107
|
+
"gh:run:watch"
|
|
108
|
+
])
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "auth-storage",
|
|
112
|
+
icon: "\u{1F510}",
|
|
113
|
+
label: "Auth & Storage",
|
|
114
|
+
commands: pick([
|
|
115
|
+
"supabase:storage",
|
|
116
|
+
"supabase:secrets",
|
|
117
|
+
"supabase:sso"
|
|
118
|
+
])
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "networking",
|
|
122
|
+
icon: "\u{1F310}",
|
|
123
|
+
label: "Networking",
|
|
124
|
+
commands: pick([
|
|
125
|
+
"supabase:domains",
|
|
126
|
+
"supabase:ssl-enforcement",
|
|
127
|
+
"supabase:network-bans",
|
|
128
|
+
"supabase:network-restrictions",
|
|
129
|
+
"supabase:vanity-subdomains",
|
|
130
|
+
"supabase:encryption",
|
|
131
|
+
"vercel:domains:list",
|
|
132
|
+
"vercel:domains:add",
|
|
133
|
+
"vercel:domains:rm"
|
|
134
|
+
])
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "packages",
|
|
138
|
+
icon: "\u{1F4CB}",
|
|
139
|
+
label: "Packages",
|
|
140
|
+
commands: pick([
|
|
141
|
+
"pkg:install",
|
|
142
|
+
"pkg:add",
|
|
143
|
+
"pkg:remove",
|
|
144
|
+
"pkg:update",
|
|
145
|
+
"pkg:outdated",
|
|
146
|
+
"pkg:audit",
|
|
147
|
+
"pkg:ls",
|
|
148
|
+
"pkg:publish",
|
|
149
|
+
"pkg:pack",
|
|
150
|
+
"pkg:version:patch",
|
|
151
|
+
"pkg:version:minor",
|
|
152
|
+
"pkg:version:major",
|
|
153
|
+
"pkg:login",
|
|
154
|
+
"pkg:logout",
|
|
155
|
+
"pkg:config:list",
|
|
156
|
+
"pkg:whoami",
|
|
157
|
+
"pkg:info",
|
|
158
|
+
"pkg:search",
|
|
159
|
+
"pkg:init"
|
|
160
|
+
])
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: "setup",
|
|
164
|
+
icon: "\u2699\uFE0F",
|
|
165
|
+
label: "Setup",
|
|
166
|
+
commands: pick([
|
|
167
|
+
"supabase:init",
|
|
168
|
+
"supabase:link",
|
|
169
|
+
"supabase:login",
|
|
170
|
+
"vercel:link",
|
|
171
|
+
"vercel:login",
|
|
172
|
+
"gh:auth:login",
|
|
173
|
+
"gh:auth:status"
|
|
174
|
+
])
|
|
175
|
+
}
|
|
176
|
+
];
|
|
177
|
+
var featureById = new Map(features.map((f) => [f.id, f]));
|
|
178
|
+
function getFeatureById(id) {
|
|
179
|
+
return featureById.get(id);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/data/flags.ts
|
|
183
|
+
var globalFlags = [
|
|
184
|
+
{ value: "--debug", label: "--debug", hint: "Output debug logs to stderr" },
|
|
185
|
+
{ value: "--yes", label: "--yes", hint: "Answer yes to all prompts" },
|
|
186
|
+
{
|
|
187
|
+
value: "--create-ticket",
|
|
188
|
+
label: "--create-ticket",
|
|
189
|
+
hint: "Create support ticket on error"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
value: "--experimental",
|
|
193
|
+
label: "--experimental",
|
|
194
|
+
hint: "Enable experimental features"
|
|
195
|
+
}
|
|
196
|
+
];
|
|
197
|
+
var toolFlags = {
|
|
198
|
+
supabase: globalFlags,
|
|
199
|
+
gh: [],
|
|
200
|
+
vercel: [
|
|
201
|
+
{ value: "--yes", label: "--yes", hint: "Skip confirmation prompts" },
|
|
202
|
+
{ value: "--debug", label: "--debug", hint: "Debug mode" }
|
|
203
|
+
],
|
|
204
|
+
git: [],
|
|
205
|
+
pkg: [
|
|
206
|
+
{ value: "--save-dev", label: "--save-dev", hint: "Save as dev dependency" },
|
|
207
|
+
{ value: "--global", label: "--global", hint: "Install globally" },
|
|
208
|
+
{ value: "--dry-run", label: "--dry-run", hint: "Show what would happen" }
|
|
209
|
+
]
|
|
210
|
+
};
|
|
211
|
+
function getFlagsForTool(toolId) {
|
|
212
|
+
return toolFlags[toolId] ?? globalFlags;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export {
|
|
216
|
+
features,
|
|
217
|
+
getFeatureById,
|
|
218
|
+
toolFlags,
|
|
219
|
+
getFlagsForTool
|
|
220
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveToolCommand,
|
|
3
|
+
runCommand
|
|
4
|
+
} from "./chunk-ELSIHPJL.js";
|
|
5
|
+
|
|
6
|
+
// src/declarative/applier.ts
|
|
7
|
+
import pLimit from "p-limit";
|
|
8
|
+
async function applyActions(actions, cwd = process.cwd(), onProgress) {
|
|
9
|
+
const limit = pLimit(3);
|
|
10
|
+
let completed = 0;
|
|
11
|
+
const results = await Promise.all(
|
|
12
|
+
actions.map(
|
|
13
|
+
(action) => limit(async () => {
|
|
14
|
+
onProgress?.(completed, actions.length, action);
|
|
15
|
+
const resolved = resolveToolCommand(action.tool, cwd);
|
|
16
|
+
const result = await runCommand(
|
|
17
|
+
{ command: resolved.command, env: resolved.env },
|
|
18
|
+
action.args,
|
|
19
|
+
cwd
|
|
20
|
+
).promise;
|
|
21
|
+
completed++;
|
|
22
|
+
const success = !result.spawnError && result.exitCode === 0;
|
|
23
|
+
return { action, success, result };
|
|
24
|
+
})
|
|
25
|
+
)
|
|
26
|
+
);
|
|
27
|
+
return results;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
applyActions
|
|
32
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findNearestPackageRoot
|
|
3
|
+
} from "./chunk-ZU5VZHYD.js";
|
|
4
|
+
import {
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
writeFileSync
|
|
9
|
+
} from "./chunk-TD6YNU6L.js";
|
|
10
|
+
|
|
11
|
+
// src/config/projectConfig.ts
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
var CONFIG_DIR = ".polter";
|
|
14
|
+
var CONFIG_FILE = "config.json";
|
|
15
|
+
function defaultConfig() {
|
|
16
|
+
return {
|
|
17
|
+
version: 1,
|
|
18
|
+
tools: {},
|
|
19
|
+
pipelines: []
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function getProjectConfigPath(startDir) {
|
|
23
|
+
const root = findNearestPackageRoot(startDir);
|
|
24
|
+
if (!root) return void 0;
|
|
25
|
+
const dir = join(root, CONFIG_DIR);
|
|
26
|
+
return { dir, file: join(dir, CONFIG_FILE) };
|
|
27
|
+
}
|
|
28
|
+
function readProjectConfig(startDir) {
|
|
29
|
+
const paths = getProjectConfigPath(startDir);
|
|
30
|
+
if (!paths) return void 0;
|
|
31
|
+
if (!existsSync(paths.file)) return void 0;
|
|
32
|
+
try {
|
|
33
|
+
const raw = readFileSync(paths.file, "utf-8");
|
|
34
|
+
return JSON.parse(raw);
|
|
35
|
+
} catch {
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function writeProjectConfig(config, startDir) {
|
|
40
|
+
const paths = getProjectConfigPath(startDir);
|
|
41
|
+
if (!paths) return false;
|
|
42
|
+
mkdirSync(paths.dir, { recursive: true });
|
|
43
|
+
writeFileSync(paths.file, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
function getOrCreateProjectConfig(startDir) {
|
|
47
|
+
return readProjectConfig(startDir) ?? defaultConfig();
|
|
48
|
+
}
|
|
49
|
+
function getProjectPipelines(startDir) {
|
|
50
|
+
const config = readProjectConfig(startDir);
|
|
51
|
+
return config?.pipelines ?? [];
|
|
52
|
+
}
|
|
53
|
+
function saveProjectPipeline(pipeline, startDir) {
|
|
54
|
+
const config = getOrCreateProjectConfig(startDir);
|
|
55
|
+
const idx = config.pipelines.findIndex((p) => p.id === pipeline.id);
|
|
56
|
+
if (idx >= 0) {
|
|
57
|
+
config.pipelines[idx] = pipeline;
|
|
58
|
+
} else {
|
|
59
|
+
config.pipelines.push(pipeline);
|
|
60
|
+
}
|
|
61
|
+
return writeProjectConfig(config, startDir);
|
|
62
|
+
}
|
|
63
|
+
function deleteProjectPipeline(pipelineId, startDir) {
|
|
64
|
+
const config = getOrCreateProjectConfig(startDir);
|
|
65
|
+
config.pipelines = config.pipelines.filter((p) => p.id !== pipelineId);
|
|
66
|
+
return writeProjectConfig(config, startDir);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
getProjectConfigPath,
|
|
71
|
+
readProjectConfig,
|
|
72
|
+
writeProjectConfig,
|
|
73
|
+
getOrCreateProjectConfig,
|
|
74
|
+
getProjectPipelines,
|
|
75
|
+
saveProjectPipeline,
|
|
76
|
+
deleteProjectPipeline
|
|
77
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCurrentStatus
|
|
3
|
+
} from "./chunk-OKHPN6X7.js";
|
|
4
|
+
|
|
5
|
+
// src/declarative/planner.ts
|
|
6
|
+
function planChanges(desired, cwd = process.cwd()) {
|
|
7
|
+
const current = getCurrentStatus(cwd);
|
|
8
|
+
const actions = [];
|
|
9
|
+
if (desired.supabase?.functions) {
|
|
10
|
+
const currentFunctions = new Set(current.supabase?.functions ?? []);
|
|
11
|
+
for (const fn of desired.supabase.functions) {
|
|
12
|
+
if (!currentFunctions.has(fn.name)) {
|
|
13
|
+
const args = ["functions", "deploy", fn.name];
|
|
14
|
+
if (fn.verify_jwt === false) {
|
|
15
|
+
args.push("--no-verify-jwt");
|
|
16
|
+
}
|
|
17
|
+
actions.push({
|
|
18
|
+
tool: "supabase",
|
|
19
|
+
action: "create",
|
|
20
|
+
resource: `function:${fn.name}`,
|
|
21
|
+
description: `Deploy function "${fn.name}"`,
|
|
22
|
+
args
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (desired.supabase?.secrets) {
|
|
28
|
+
for (const secret of desired.supabase.secrets) {
|
|
29
|
+
actions.push({
|
|
30
|
+
tool: "supabase",
|
|
31
|
+
action: "update",
|
|
32
|
+
resource: `secret:${secret}`,
|
|
33
|
+
description: `Ensure secret "${secret}" is set`,
|
|
34
|
+
args: ["secrets", "set", secret]
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (desired.vercel?.domains) {
|
|
39
|
+
for (const domain of desired.vercel.domains) {
|
|
40
|
+
actions.push({
|
|
41
|
+
tool: "vercel",
|
|
42
|
+
action: "create",
|
|
43
|
+
resource: `domain:${domain}`,
|
|
44
|
+
description: `Add domain "${domain}"`,
|
|
45
|
+
args: ["domains", "add", domain]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (desired.vercel?.env) {
|
|
50
|
+
for (const [env, vars] of Object.entries(desired.vercel.env)) {
|
|
51
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
52
|
+
actions.push({
|
|
53
|
+
tool: "vercel",
|
|
54
|
+
action: "update",
|
|
55
|
+
resource: `env:${env}:${key}`,
|
|
56
|
+
description: `Set env var "${key}" for ${env}`,
|
|
57
|
+
args: ["env", "add", key, env]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (desired.github?.secrets) {
|
|
63
|
+
for (const secret of desired.github.secrets) {
|
|
64
|
+
actions.push({
|
|
65
|
+
tool: "gh",
|
|
66
|
+
action: "update",
|
|
67
|
+
resource: `secret:${secret}`,
|
|
68
|
+
description: `Ensure GitHub secret "${secret}" is set`,
|
|
69
|
+
args: ["secret", "set", secret]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
actions,
|
|
75
|
+
noChanges: actions.length === 0
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
planChanges
|
|
81
|
+
};
|