@lovinka/deployik-mcp 0.3.2 → 0.5.0
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 +30 -1
- package/dist/daemon.js +119 -0
- package/dist/daemon.js.map +1 -0
- package/dist/index.js +104 -1
- package/dist/index.js.map +1 -1
- package/dist/install-daemon.js +364 -0
- package/dist/install-daemon.js.map +1 -0
- package/dist/server.js +16 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/_helpers.js.map +1 -1
- package/dist/tools/apps.js +256 -0
- package/dist/tools/apps.js.map +1 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/projects.js +12 -0
- package/dist/tools/projects.js.map +1 -1
- package/dist/tools/workflows.js +62 -54
- package/dist/tools/workflows.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,9 +43,37 @@ Or set `DEPLOYIK_URL` / `DEPLOYIK_TOKEN` env vars and pass `--yes`.
|
|
|
43
43
|
| Command | What it does |
|
|
44
44
|
|---|---|
|
|
45
45
|
| `install` | MCP registration + skill files (default) |
|
|
46
|
+
| `install --daemon` | Long-lived launchd daemon — one HTTP process for every Claude window (macOS only, see below) |
|
|
46
47
|
| `install-mcp` | MCP registration only |
|
|
47
48
|
| `install-skill` | Skill files only |
|
|
48
49
|
| `uninstall` | Removes the `deployik` MCP entry from every Claude config |
|
|
50
|
+
| `uninstall --daemon` | Stops + removes the launchd daemon and clears the HTTP entry from Claude configs |
|
|
51
|
+
| `daemon` | Runs the HTTP daemon in the foreground (for testing) |
|
|
52
|
+
|
|
53
|
+
## Daemon mode (one process, every Claude window)
|
|
54
|
+
|
|
55
|
+
By default each Claude Code window spawns its own stdio child for every configured MCP. After a few open windows you can easily have 10+ idle `node` processes eating ~100 MB each. The daemon mode collapses this to a single long-lived HTTP MCP server bound to `127.0.0.1:8788`.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx -y @lovinka/deployik-mcp install --daemon --token=dpk_xxx
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
What it does:
|
|
62
|
+
|
|
63
|
+
- Writes a launchd plist at `~/Library/LaunchAgents/com.lovinka.deployik-mcp.plist` with `KeepAlive=true`, `RunAtLoad=true`, and `DEPLOYIK_URL` / `DEPLOYIK_TOKEN` in `EnvironmentVariables` (file mode 0600 — token only readable by your user).
|
|
64
|
+
- Stages the runtime into `~/.deployik-mcp/runtime/` so launchd can read it on every macOS regardless of TCC (Transparency, Consent, Control) restrictions on `~/Documents`, `~/Desktop`, etc.
|
|
65
|
+
- Runs `launchctl bootstrap gui/$UID <plist>` to start the daemon immediately.
|
|
66
|
+
- Rewrites the `deployik` entry in `~/.claude.json` (and the Claude Desktop config) from a stdio command to `{ "type": "http", "url": "http://127.0.0.1:8788/mcp" }`.
|
|
67
|
+
|
|
68
|
+
After install, **restart any open Claude windows** so they pick up the HTTP entry. From then on, opening N windows still uses **one** daemon process.
|
|
69
|
+
|
|
70
|
+
Tools that need the client's filesystem (`init_in_repo`, `show_binding`) are skipped in HTTP mode since the daemon has no per-repo context. Project resolution still works via explicit `project_id` / `slug` / single-project workspace.
|
|
71
|
+
|
|
72
|
+
Logs: `~/Library/Logs/deployik-mcp.{out,err}.log`.
|
|
73
|
+
|
|
74
|
+
To go back to per-window stdio: `npx -y @lovinka/deployik-mcp uninstall --daemon`, then re-run `install` without `--daemon`.
|
|
75
|
+
|
|
76
|
+
> Linux note: launchd is macOS-only. On Linux, run the daemon under `systemd --user` pointing at `node <prefix>/lib/node_modules/@lovinka/deployik-mcp/dist/daemon.js` and add the matching HTTP entry to your client config manually.
|
|
49
77
|
|
|
50
78
|
### Manual install (if you prefer to edit JSON yourself)
|
|
51
79
|
|
|
@@ -68,7 +96,8 @@ Get a token at **Account → Access tokens** in Deployik. The token is shown onc
|
|
|
68
96
|
|
|
69
97
|
## What it does
|
|
70
98
|
|
|
71
|
-
- **~
|
|
99
|
+
- **~50 thin tools** — one per Deployik HTTP endpoint (projects, deployments, env vars, secrets, domains, auto-build, password protection, volumes, analytics, email, dashboard groups, tokens, GitHub).
|
|
100
|
+
- **App bundles** — group several projects into one **app** and operate on it as a unit: `list_apps`, `create_app`, `get_app_health`, `update_app` (rename / toggle `deploy_ordered`), `delete_app`, `add_project_to_app`, `remove_project_from_app`; app-level env/secrets (`list_app_env_vars` / `set_app_env_var` / `delete_app_env_var` + secret variants, inherited by every member); and coordinated deploys: `deploy_app` (ordered, health-gated, fire-and-forget), `deploy_app_and_wait` (waits for the release outcome), `list_app_releases`, `rollback_app`. Member projects also gain `build_filter_enabled` / `watch_paths` (monorepo fan-out filtering) and `deploy_order` on create/update.
|
|
72
101
|
- **12 workflow tools** — `setup_project_from_repo`, `deploy_project`, `set_secret`, `tail_latest_logs`, `debug_failed_deployment`, `get_project_health`, `init_in_repo`, `whats_my_url`, `whats_broken`, `redeploy`, and more.
|
|
73
102
|
- **Dockerfile-aware project creation** — generated presets cover Next.js, Vite, Astro, static sites, and Node APIs; user-provided Dockerfiles are supported by choosing `framework: "static"`, setting `root_directory` to the Dockerfile folder, and setting `port` to the container listen port.
|
|
74
103
|
- **Bundled knowledge** — Deployik's how-to recipes ship as MCP prompts (`deployik_recipe_*`), plus three tools: `list_recipes`, `get_recipe(topic)`, and **`find_help(question)`** which routes free-form English ("where do I set the Stripe key for the live site?") to the right recipe automatically.
|
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// HTTP daemon entrypoint.
|
|
2
|
+
//
|
|
3
|
+
// Runs ONE long-lived process bound to 127.0.0.1, so every Claude Code
|
|
4
|
+
// window/session shares the same server instead of each spawning its own
|
|
5
|
+
// stdio child. Wired up via `deployik-mcp install --daemon`, which writes
|
|
6
|
+
// a launchd plist and points Claude's MCP config at this URL.
|
|
7
|
+
//
|
|
8
|
+
// Stateless transport — the SDK requires a fresh transport per request in
|
|
9
|
+
// stateless mode (reusing one throws "Stateless transport cannot be reused").
|
|
10
|
+
// So each POST /mcp instantiates a new McpServer + transport pair. The build
|
|
11
|
+
// is in-memory only (no I/O), takes sub-millisecond, and avoids the session
|
|
12
|
+
// bookkeeping a stateful map would require. Identity comes from the daemon's
|
|
13
|
+
// process env, not per-session.
|
|
14
|
+
import { createServer } from "node:http";
|
|
15
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
16
|
+
import { buildServer } from "./server.js";
|
|
17
|
+
import { ConfigError } from "./config/env.js";
|
|
18
|
+
import { VERSION } from "./version.js";
|
|
19
|
+
const DEFAULT_PORT = 8788;
|
|
20
|
+
const DEFAULT_HOST = "127.0.0.1";
|
|
21
|
+
const MCP_PATH = "/mcp";
|
|
22
|
+
const HEALTH_PATH = "/healthz";
|
|
23
|
+
export async function startDaemon() {
|
|
24
|
+
const port = parseInt(process.env.DEPLOYIK_DAEMON_PORT ?? "", 10) || DEFAULT_PORT;
|
|
25
|
+
const host = process.env.DEPLOYIK_DAEMON_HOST?.trim() || DEFAULT_HOST;
|
|
26
|
+
// Validate config up front so a bad token / missing URL fails the launchd
|
|
27
|
+
// bootstrap step (visible in the install output) instead of throwing on
|
|
28
|
+
// every request.
|
|
29
|
+
buildServer(process.env, process.cwd(), { mode: "http" });
|
|
30
|
+
const httpServer = createServer((req, res) => {
|
|
31
|
+
// Wrap in a promise so async errors land in the .catch — Node's HTTP
|
|
32
|
+
// request callback type is synchronous void, async throws otherwise
|
|
33
|
+
// become unhandled rejections.
|
|
34
|
+
void handleRequest(req, res).catch((err) => {
|
|
35
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
36
|
+
if (!res.headersSent) {
|
|
37
|
+
sendJson(res, 500, { error: "internal", message });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
try {
|
|
41
|
+
res.end();
|
|
42
|
+
}
|
|
43
|
+
catch { /* socket already torn down */ }
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
async function handleRequest(req, res) {
|
|
48
|
+
// Localhost-only daemon, but cheap sanity check anyway: refuse anything
|
|
49
|
+
// not sourced from this machine. Catches stray docker bridges or a future
|
|
50
|
+
// misconfigured listener pointing at 0.0.0.0.
|
|
51
|
+
const remote = req.socket.remoteAddress ?? "";
|
|
52
|
+
if (!isLocal(remote)) {
|
|
53
|
+
sendJson(res, 403, { error: "forbidden", reason: `non-local remote: ${remote}` });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const url = new URL(req.url ?? "/", `http://${host}:${port}`);
|
|
57
|
+
if (url.pathname === HEALTH_PATH) {
|
|
58
|
+
sendJson(res, 200, { ok: true, version: VERSION });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (url.pathname !== MCP_PATH) {
|
|
62
|
+
sendJson(res, 404, { error: "not_found", path: url.pathname });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Stateless: fresh server + transport per request. The whole thing is
|
|
66
|
+
// in-memory wiring (no network calls during buildServer), so the cost
|
|
67
|
+
// is the tool-registration loop — still sub-millisecond in practice.
|
|
68
|
+
const { server } = buildServer(process.env, process.cwd(), { mode: "http" });
|
|
69
|
+
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
70
|
+
try {
|
|
71
|
+
await server.connect(transport);
|
|
72
|
+
await transport.handleRequest(req, res);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
transport.close().catch(() => { });
|
|
76
|
+
server.close().catch(() => { });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
await new Promise((resolve, reject) => {
|
|
80
|
+
httpServer.once("error", reject);
|
|
81
|
+
httpServer.listen(port, host, () => {
|
|
82
|
+
httpServer.off("error", reject);
|
|
83
|
+
resolve();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
process.stderr.write(`deployik-mcp ${VERSION} daemon listening on http://${host}:${port}${MCP_PATH}\n`);
|
|
87
|
+
const shutdown = (signal) => {
|
|
88
|
+
process.stderr.write(`deployik-mcp daemon: received ${signal}, shutting down\n`);
|
|
89
|
+
httpServer.close();
|
|
90
|
+
process.exit(0);
|
|
91
|
+
};
|
|
92
|
+
process.once("SIGINT", () => shutdown("SIGINT"));
|
|
93
|
+
process.once("SIGTERM", () => shutdown("SIGTERM"));
|
|
94
|
+
process.once("SIGHUP", () => shutdown("SIGHUP"));
|
|
95
|
+
}
|
|
96
|
+
function sendJson(res, status, body) {
|
|
97
|
+
res.statusCode = status;
|
|
98
|
+
res.setHeader("Content-Type", "application/json");
|
|
99
|
+
res.end(JSON.stringify(body));
|
|
100
|
+
}
|
|
101
|
+
function isLocal(addr) {
|
|
102
|
+
// Strip IPv6-mapped-v4 prefix so "::ffff:127.0.0.1" compares cleanly.
|
|
103
|
+
const a = addr.replace(/^::ffff:/, "");
|
|
104
|
+
return a === "127.0.0.1" || a === "::1" || a === "localhost";
|
|
105
|
+
}
|
|
106
|
+
// Allow `node dist/daemon.js` to start directly without going through index.ts.
|
|
107
|
+
// `import.meta.url` check makes the file safe to import as a library too.
|
|
108
|
+
const invokedDirectly = import.meta.url === `file://${process.argv[1]}`;
|
|
109
|
+
if (invokedDirectly) {
|
|
110
|
+
startDaemon().catch((err) => {
|
|
111
|
+
if (err instanceof ConfigError) {
|
|
112
|
+
process.stderr.write(`deployik-mcp daemon: ${err.message}\n`);
|
|
113
|
+
process.exit(2);
|
|
114
|
+
}
|
|
115
|
+
process.stderr.write(`deployik-mcp daemon: ${err.message}\n`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
2
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
5
|
import { buildServer } from "./server.js";
|
|
4
6
|
import { ConfigError } from "./config/env.js";
|
|
5
7
|
import { installSkill } from "./install-skill.js";
|
|
6
8
|
import { installMcp, uninstallMcp } from "./install-mcp.js";
|
|
7
9
|
import { installAll } from "./install.js";
|
|
10
|
+
import { installDaemon, uninstallDaemon, DEFAULT_DAEMON_PORT } from "./install-daemon.js";
|
|
11
|
+
import { startDaemon } from "./daemon.js";
|
|
8
12
|
import { VERSION } from "./version.js";
|
|
9
13
|
const HELP = `deployik-mcp ${VERSION}
|
|
10
14
|
|
|
11
15
|
USAGE
|
|
12
16
|
deployik-mcp Start the MCP server over stdio (default).
|
|
17
|
+
deployik-mcp daemon Run the HTTP daemon in the foreground
|
|
18
|
+
(binds 127.0.0.1:${DEFAULT_DAEMON_PORT} by default; for testing).
|
|
13
19
|
deployik-mcp install Register the MCP server in Claude config
|
|
14
20
|
AND copy the bundled skill (recommended).
|
|
21
|
+
deployik-mcp install --daemon Install as a long-lived launchd daemon
|
|
22
|
+
(one HTTP process, shared by every Claude
|
|
23
|
+
window). Rewrites Claude configs to use
|
|
24
|
+
http://127.0.0.1:${DEFAULT_DAEMON_PORT}/mcp. macOS only.
|
|
15
25
|
deployik-mcp install-mcp Only register the MCP server in Claude config.
|
|
16
26
|
deployik-mcp install-skill Only copy the Deployik skill files.
|
|
17
27
|
deployik-mcp uninstall Remove the 'deployik' MCP server entry from
|
|
18
28
|
every Claude config it lives in.
|
|
29
|
+
deployik-mcp uninstall --daemon Stop the launchd daemon, remove the plist,
|
|
30
|
+
and clear the HTTP entry from Claude configs.
|
|
19
31
|
deployik-mcp --help, -h Show this message.
|
|
20
32
|
deployik-mcp --version, -v Print version and exit.
|
|
21
33
|
|
|
@@ -61,6 +73,8 @@ function parseFlags(argv) {
|
|
|
61
73
|
let yes = false;
|
|
62
74
|
let url;
|
|
63
75
|
let token;
|
|
76
|
+
let daemon = false;
|
|
77
|
+
let port;
|
|
64
78
|
for (const arg of argv) {
|
|
65
79
|
if (arg === "--global")
|
|
66
80
|
scope = "global";
|
|
@@ -68,12 +82,19 @@ function parseFlags(argv) {
|
|
|
68
82
|
scope = "local";
|
|
69
83
|
else if (arg === "--yes" || arg === "-y")
|
|
70
84
|
yes = true;
|
|
85
|
+
else if (arg === "--daemon")
|
|
86
|
+
daemon = true;
|
|
71
87
|
else if (arg.startsWith("--url="))
|
|
72
88
|
url = arg.slice("--url=".length);
|
|
73
89
|
else if (arg.startsWith("--token="))
|
|
74
90
|
token = arg.slice("--token=".length);
|
|
91
|
+
else if (arg.startsWith("--port=")) {
|
|
92
|
+
const n = parseInt(arg.slice("--port=".length), 10);
|
|
93
|
+
if (Number.isFinite(n) && n > 0)
|
|
94
|
+
port = n;
|
|
95
|
+
}
|
|
75
96
|
}
|
|
76
|
-
return { scope, yes, url, token };
|
|
97
|
+
return { scope, yes, url, token, daemon, ...(port !== undefined ? { port } : {}) };
|
|
77
98
|
}
|
|
78
99
|
async function main() {
|
|
79
100
|
const argv = process.argv.slice(2);
|
|
@@ -87,8 +108,16 @@ async function main() {
|
|
|
87
108
|
}
|
|
88
109
|
const sub = argv[0];
|
|
89
110
|
const rest = argv.slice(1);
|
|
111
|
+
if (sub === "daemon") {
|
|
112
|
+
await startDaemon();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
90
115
|
if (sub === "install") {
|
|
91
116
|
const flags = parseFlags(rest);
|
|
117
|
+
if (flags.daemon) {
|
|
118
|
+
const code = installDaemonCommand(flags);
|
|
119
|
+
process.exit(code);
|
|
120
|
+
}
|
|
92
121
|
const code = await installAll(flags);
|
|
93
122
|
process.exit(code);
|
|
94
123
|
}
|
|
@@ -104,6 +133,10 @@ async function main() {
|
|
|
104
133
|
}
|
|
105
134
|
if (sub === "uninstall") {
|
|
106
135
|
const flags = parseFlags(rest);
|
|
136
|
+
if (flags.daemon) {
|
|
137
|
+
uninstallDaemonCommand();
|
|
138
|
+
process.exit(0);
|
|
139
|
+
}
|
|
107
140
|
const res = uninstallMcp({ scope: flags.scope });
|
|
108
141
|
for (const w of res.written)
|
|
109
142
|
process.stdout.write(` ✓ removed from ${w.path}${w.backupPath ? ` (backup → ${w.backupPath})` : ""}\n`);
|
|
@@ -125,6 +158,27 @@ async function main() {
|
|
|
125
158
|
try {
|
|
126
159
|
const { server } = buildServer();
|
|
127
160
|
const transport = new StdioServerTransport();
|
|
161
|
+
// The SDK's StdioServerTransport only listens for stdin 'data' + 'error'
|
|
162
|
+
// (see node_modules/@modelcontextprotocol/sdk/.../server/stdio.js). When
|
|
163
|
+
// the MCP client (Claude Code, Claude Desktop) closes the stdio pipe on
|
|
164
|
+
// shutdown, stdin emits 'end' but nothing exits the process — the data
|
|
165
|
+
// listener keeps the event loop alive forever, and the npm exec wrapper
|
|
166
|
+
// stays parked waiting on its child. Result: zombie process per closed
|
|
167
|
+
// session. Wire our own exit triggers so the daemon dies cleanly.
|
|
168
|
+
let shuttingDown = false;
|
|
169
|
+
const shutdown = (code = 0) => {
|
|
170
|
+
if (shuttingDown)
|
|
171
|
+
return;
|
|
172
|
+
shuttingDown = true;
|
|
173
|
+
void transport.close().catch(() => { });
|
|
174
|
+
process.exit(code);
|
|
175
|
+
};
|
|
176
|
+
transport.onclose = () => shutdown(0);
|
|
177
|
+
process.stdin.once("end", () => shutdown(0));
|
|
178
|
+
process.stdin.once("close", () => shutdown(0));
|
|
179
|
+
process.once("SIGINT", () => shutdown(0));
|
|
180
|
+
process.once("SIGTERM", () => shutdown(0));
|
|
181
|
+
process.once("SIGHUP", () => shutdown(0));
|
|
128
182
|
await server.connect(transport);
|
|
129
183
|
process.stderr.write(`deployik-mcp ${VERSION} ready (stdio)\n`);
|
|
130
184
|
}
|
|
@@ -137,6 +191,55 @@ async function main() {
|
|
|
137
191
|
process.exit(1);
|
|
138
192
|
}
|
|
139
193
|
}
|
|
194
|
+
function installDaemonCommand(flags) {
|
|
195
|
+
const token = flags.token ?? process.env.DEPLOYIK_TOKEN ?? "";
|
|
196
|
+
if (!token) {
|
|
197
|
+
process.stderr.write(`deployik-mcp install --daemon: missing token.\n` +
|
|
198
|
+
` Pass --token=<dpk_...> or set DEPLOYIK_TOKEN in your environment.\n`);
|
|
199
|
+
return 2;
|
|
200
|
+
}
|
|
201
|
+
const url = flags.url ?? process.env.DEPLOYIK_URL ?? "https://deployik.lovinka.com";
|
|
202
|
+
const sourceDir = resolveMcpSourceDir();
|
|
203
|
+
try {
|
|
204
|
+
const result = installDaemon({
|
|
205
|
+
sourceDir,
|
|
206
|
+
url,
|
|
207
|
+
token,
|
|
208
|
+
...(flags.port !== undefined ? { port: flags.port } : {}),
|
|
209
|
+
});
|
|
210
|
+
process.stdout.write(`\n ✓ wrote plist ${result.plistPath}\n`);
|
|
211
|
+
process.stdout.write(` ${result.loaded ? "✓" : "✗"} launchctl bootstrap${result.loaded ? "" : ` failed: ${result.loadError}`}\n`);
|
|
212
|
+
process.stdout.write(` ✓ daemon URL ${result.url}\n`);
|
|
213
|
+
for (const w of result.configsWritten) {
|
|
214
|
+
process.stdout.write(` ✓ rewrote ${w.path}${w.backupPath ? ` (backup → ${w.backupPath})` : ""}\n`);
|
|
215
|
+
}
|
|
216
|
+
for (const s of result.configsSkipped) {
|
|
217
|
+
process.stdout.write(` · skipped ${s.path} — ${s.reason}\n`);
|
|
218
|
+
}
|
|
219
|
+
process.stdout.write(`\n Restart Claude Code to pick up the HTTP MCP entry.\n`);
|
|
220
|
+
process.stdout.write(` Logs: ~/Library/Logs/deployik-mcp.{out,err}.log\n`);
|
|
221
|
+
return result.loaded ? 0 : 1;
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
process.stderr.write(`deployik-mcp install --daemon: ${err.message}\n`);
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function uninstallDaemonCommand() {
|
|
229
|
+
const result = uninstallDaemon();
|
|
230
|
+
process.stdout.write(` ${result.bootoutOk ? "✓" : "·"} launchctl bootout${result.bootoutError ? ` (${result.bootoutError})` : ""}\n`);
|
|
231
|
+
process.stdout.write(` ${result.plistRemoved ? "✓ removed plist" : "· plist already absent"}\n`);
|
|
232
|
+
for (const c of result.configsCleaned) {
|
|
233
|
+
process.stdout.write(` ${c.removed ? "✓" : "·"} ${c.path}${c.removed ? "" : " (no deployik entry)"}\n`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function resolveMcpSourceDir() {
|
|
237
|
+
// We're running from dist/index.js — the mcp package root is one level up.
|
|
238
|
+
// Works for both local builds and a published npm install
|
|
239
|
+
// (node_modules/@lovinka/deployik-mcp/dist/index.js).
|
|
240
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
241
|
+
return resolve(here, "..");
|
|
242
|
+
}
|
|
140
243
|
// `installMcp` is exported from a sibling module for programmatic use; the
|
|
141
244
|
// re-export here keeps the published `dist/index.js` self-contained for
|
|
142
245
|
// scripts that prefer requiring the entry point.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAqB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,IAAI,GAAG,gBAAgB,OAAO
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|