@lovinka/deployik-mcp 0.1.1 → 0.1.5

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 CHANGED
@@ -2,9 +2,52 @@
2
2
 
3
3
  MCP server for [Deployik](https://github.com/lefteq/lovinka-deployik). Lets any MCP-aware AI drive Deployik end-to-end — create projects, set secrets, trigger deployments, debug failed builds, manage domains — without touching the dashboard.
4
4
 
5
- ## Install (one-shot config)
5
+ ## Install (one-shot, no JSON editing)
6
6
 
7
- Add to your MCP client config (Claude Desktop, Claude Code, etc.):
7
+ ```bash
8
+ npx -y @lovinka/deployik-mcp install
9
+ ```
10
+
11
+ Prompts for your Deployik URL and Personal Access Token, then:
12
+
13
+ - Registers the `deployik` MCP server in `~/.claude.json` (Claude Code) **and** the Claude Desktop config (if installed) so every project + every window can use it.
14
+ - Copies the Deployik how-to recipes into `~/.claude/skills/deployik-howto/` so `/skills` surfaces them.
15
+ - Backs up any pre-existing config to `<path>.bak.<timestamp>` before merging.
16
+
17
+ Restart Claude Code / Claude Desktop afterwards.
18
+
19
+ ### Scopes
20
+
21
+ ```bash
22
+ # Global (recommended) — once installed, available everywhere
23
+ npx -y @lovinka/deployik-mcp install --global
24
+
25
+ # Local — writes <cwd>/.mcp.json + <cwd>/.claude/skills/
26
+ # MCP only fires when Claude is opened in this folder
27
+ npx -y @lovinka/deployik-mcp install --local
28
+ ```
29
+
30
+ ### Non-interactive
31
+
32
+ ```bash
33
+ npx -y @lovinka/deployik-mcp install \
34
+ --yes \
35
+ --url=https://deployik.lovinka.com \
36
+ --token=dpk_xxx
37
+ ```
38
+
39
+ Or set `DEPLOYIK_URL` / `DEPLOYIK_TOKEN` env vars and pass `--yes`.
40
+
41
+ ### Granular subcommands
42
+
43
+ | Command | What it does |
44
+ |---|---|
45
+ | `install` | MCP registration + skill files (default) |
46
+ | `install-mcp` | MCP registration only |
47
+ | `install-skill` | Skill files only |
48
+ | `uninstall` | Removes the `deployik` MCP entry from every Claude config |
49
+
50
+ ### Manual install (if you prefer to edit JSON yourself)
8
51
 
9
52
  ```json
10
53
  {
@@ -21,17 +64,17 @@ Add to your MCP client config (Claude Desktop, Claude Code, etc.):
21
64
  }
22
65
  ```
23
66
 
24
- Get a token at **Account → Access tokens** in Deployik. The token is shown once on creation; copy it then.
25
-
26
- For a VPN-only deployment, point `DEPLOYIK_URL` at any reachable host (`http://10.x.x.x:8080`, `https://deployik.internal`, etc.).
67
+ Get a token at **Account → Access tokens** in Deployik. The token is shown once on creation; copy it then. For a VPN-only deployment, point `DEPLOYIK_URL` at any reachable host (`http://10.x.x.x:8080`, `https://deployik.internal`, etc.).
27
68
 
28
69
  ## What it does
29
70
 
30
71
  - **~32 thin tools** — one per Deployik HTTP endpoint (projects, deployments, env vars, secrets, domains, auto-build, password protection, volumes, analytics, email, workspaces, tokens, GitHub).
31
- - **9 workflow tools** — `setup_project_from_repo`, `deploy_project`, `set_secret`, `tail_latest_logs`, `debug_failed_deployment`, `get_project_health`, `init_in_repo`, and more.
32
- - **Bundled knowledge** — Deployik's how-to recipes ship as MCP prompts (`deployik_recipe_*`) and a `get_recipe(topic)` tool, so a fresh AI session can self-onboard.
33
- - **Repo binding** — `init_in_repo` writes a `.deployik/binding.json` (gitignored) so the AI knows which Deployik project this folder maps to without asking.
72
+ - **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
+ - **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.
74
+ - **Repo binding** — first call inside a git repo with a unique-match `origin` auto-writes `.deployik.json` (committed, just project + workspace + schema URL) and gitignores the private `.deployik/` directory. Self-healing `.gitignore`.
34
75
  - **Tiered safety** — destructive operations require `confirm: true`; production-touching operations also require `confirm_name: <project>`. Every destructive call is logged to `.deployik/audit.log`.
76
+ - **Loose English** — `prod` / `live` / `staging` / `dev` / `both` / `everywhere` all normalize to the right scope automatically.
77
+
35
78
 
36
79
  ## Local development
37
80
 
@@ -46,14 +89,28 @@ Test against a local Deployik dev server with `DEPLOYIK_URL=http://127.0.0.1:808
46
89
 
47
90
  ## Files written on the host
48
91
 
49
- When the AI calls `init_in_repo` from inside a repo:
92
+ Project repo state is split into two layers — **public** (commit it) and
93
+ **private** (gitignored, per developer):
50
94
 
51
95
  ```
52
- .deployik/
53
- ├── binding.json project + workspace mapping for this repo
54
- ├── cache.json cached project/workspace list (1h TTL)
55
- ├── token optional token fallback (mode 0600)
56
- └── audit.log destructive-call ledger
96
+ <repo-root>/
97
+ ├── .deployik.json PUBLIC, commit this. Just { project, workspace, $schema }.
98
+ │ Teammates pulling your repo immediately know which
99
+ │ Deployik project this folder deploys to.
100
+ └── .deployik/ PRIVATE. Auto-added to .gitignore (and re-added on every
101
+ MCP call if a teammate clobbers the .gitignore line).
102
+ ├── cache.json Project + workspace list (1h TTL).
103
+ ├── token Optional token fallback (mode 0600) — only used if
104
+ DEPLOYIK_TOKEN env var is unset.
105
+ └── audit.log Append-only ledger of destructive calls (secret values
106
+ redacted automatically).
57
107
  ```
58
108
 
59
- `.gitignore` is auto-appended with `.deployik/` if missing.
109
+ **Automatic binding**: the first time you run any tool inside a git repo whose
110
+ `origin` remote uniquely matches one Deployik project, the MCP writes
111
+ `.deployik.json` silently — no explicit setup needed. If multiple projects
112
+ deploy the same repo (monorepos with several Deployik apps), the MCP returns a
113
+ friendly "which one?" with the candidate slugs.
114
+
115
+ **Manual binding** (also fine): "deployik bind this repo to forge-kpmg" → the
116
+ AI calls `init_in_repo({ project: "forge-kpmg" })` and writes `.deployik.json`.
@@ -13,6 +13,29 @@ export class DeployikClient {
13
13
  this.userAgent = opts.userAgent ?? "deployik-mcp/0.1.0";
14
14
  }
15
15
  async request(path, opts = {}) {
16
+ // Transient 5xx (commonly SQLITE_BUSY on the Deployik server during a live
17
+ // build pipeline) are auto-retried with exponential backoff. Idempotent
18
+ // methods (GET, PUT, DELETE) and the env/secret upsert POST endpoints are
19
+ // safe to retry — they all use ON CONFLICT or full-set replacement.
20
+ const method = opts.method ?? "GET";
21
+ const maxAttempts = retryableMethod(method, path) ? 4 : 1;
22
+ let lastErr;
23
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
24
+ try {
25
+ return await this.requestOnce(path, opts);
26
+ }
27
+ catch (err) {
28
+ if (err instanceof ApiError && err.status >= 500 && err.status < 600 && attempt < maxAttempts) {
29
+ lastErr = err;
30
+ await sleep(Math.min(150 * 2 ** (attempt - 1), 1500));
31
+ continue;
32
+ }
33
+ throw err;
34
+ }
35
+ }
36
+ throw lastErr;
37
+ }
38
+ async requestOnce(path, opts) {
16
39
  const url = this.buildUrl(path, opts.query);
17
40
  const headers = {
18
41
  Authorization: `Bearer ${this.token}`,
@@ -103,4 +126,17 @@ export class DeployikClient {
103
126
  return `${this.baseUrl}/api/deployments/${encodeURIComponent(deploymentId)}/screenshot`;
104
127
  }
105
128
  }
129
+ function retryableMethod(method, path) {
130
+ // GET / PUT / DELETE are HTTP-idempotent.
131
+ if (method === "GET" || method === "PUT" || method === "DELETE")
132
+ return true;
133
+ // The Deployik env/secret single-upsert POST endpoints are application-level
134
+ // idempotent (UPSERT with ON CONFLICT) so retrying a transient 5xx is safe.
135
+ if (method === "POST" && /\/env\b|\/secrets\b/.test(path) && !path.endsWith("/test-smtp"))
136
+ return true;
137
+ return false;
138
+ }
139
+ function sleep(ms) {
140
+ return new Promise((res) => setTimeout(res, ms));
141
+ }
106
142
  //# sourceMappingURL=http.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/client/http.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,15 @@
1
1
  import { appendFileSync, mkdirSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
+ import { ensureGitignore } from "./binding.js";
4
+ function reaffirmGitignore(stateDir) {
5
+ // The state dir lives at <cwd>/.deployik — the cwd is its parent.
6
+ try {
7
+ ensureGitignore(dirname(stateDir));
8
+ }
9
+ catch {
10
+ // best-effort; never block the write
11
+ }
12
+ }
3
13
  const AUDIT_FILE = "audit.log";
4
14
  const SECRET_KEYS = new Set([
5
15
  "value",
@@ -34,6 +44,7 @@ export function redact(args) {
34
44
  export function appendAudit(stateDir, entry) {
35
45
  try {
36
46
  mkdirSync(stateDir, { recursive: true });
47
+ reaffirmGitignore(stateDir);
37
48
  appendFileSync(join(stateDir, AUDIT_FILE), `${JSON.stringify(entry)}\n`, "utf8");
38
49
  }
39
50
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/config/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,OAAO;IACP,QAAQ;IACR,UAAU;IACV,OAAO;IACP,sBAAsB;IACtB,eAAe;IACf,gBAAgB;CACjB,CAAC,CAAC;AAEH,MAAM,UAAU,MAAM,CAAC,IAA6B;IAClD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACvB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,CAAC;iBAAM,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC3B,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;YACjB,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAA4B,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,KAAiB;IAC7D,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,uDAAuD;IACzD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/config/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,SAAS,iBAAiB,CAAC,QAAgB;IACzC,kEAAkE;IAClE,IAAI,CAAC;QACH,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,qCAAqC;IACvC,CAAC;AACH,CAAC;AAYD,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,OAAO;IACP,QAAQ;IACR,UAAU;IACV,OAAO;IACP,sBAAsB;IACtB,eAAe;IACf,gBAAgB;CACjB,CAAC,CAAC;AAEH,MAAM,UAAU,MAAM,CAAC,IAA6B;IAClD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACvB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/B,CAAC;iBAAM,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC3B,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;YACjB,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAA4B,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,KAAiB;IAC7D,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC5B,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnF,CAAC;IAAC,MAAM,CAAC;QACP,uDAAuD;IACzD,CAAC;AACH,CAAC"}
@@ -1,30 +1,75 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
- const BINDING_FILE = "binding.json";
3
+ const PUBLIC_FILE = ".deployik.json";
4
+ const PUBLIC_SCHEMA = "https://lovinka.com/schemas/deployik.json";
4
5
  const GITIGNORE_LINE = ".deployik/";
5
- export function bindingPath(stateDir) {
6
- return join(stateDir, BINDING_FILE);
6
+ export function publicConfigPath(cwd) {
7
+ return join(cwd, PUBLIC_FILE);
7
8
  }
8
- export function readBinding(stateDir) {
9
- const path = bindingPath(stateDir);
10
- if (!existsSync(path))
11
- return undefined;
12
- try {
13
- const raw = readFileSync(path, "utf8");
14
- const parsed = JSON.parse(raw);
15
- if (!parsed || typeof parsed.project !== "string")
16
- return undefined;
17
- return parsed;
9
+ export function legacyBindingPath(stateDir) {
10
+ return join(stateDir, "binding.json");
11
+ }
12
+ export function readBinding(stateDir, cwd) {
13
+ // Prefer the public, committed config at repo root.
14
+ if (cwd) {
15
+ const publicPath = publicConfigPath(cwd);
16
+ if (existsSync(publicPath)) {
17
+ try {
18
+ const raw = readFileSync(publicPath, "utf8");
19
+ const parsed = JSON.parse(raw);
20
+ if (parsed && typeof parsed.project === "string") {
21
+ return {
22
+ project: parsed.project,
23
+ workspace: parsed.workspace,
24
+ defaultEnvironment: parsed.defaultEnvironment,
25
+ };
26
+ }
27
+ }
28
+ catch {
29
+ // fall through to legacy
30
+ }
31
+ }
18
32
  }
19
- catch {
20
- return undefined;
33
+ // Fallback: legacy private binding for repos that bound under the old layout.
34
+ const legacy = legacyBindingPath(stateDir);
35
+ if (existsSync(legacy)) {
36
+ try {
37
+ const raw = readFileSync(legacy, "utf8");
38
+ const parsed = JSON.parse(raw);
39
+ if (!parsed || typeof parsed.project !== "string")
40
+ return undefined;
41
+ return parsed;
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
21
46
  }
47
+ return undefined;
22
48
  }
23
- export function writeBinding(stateDir, binding) {
49
+ export function writeBinding(stateDir, cwd, binding) {
50
+ // Always write to the public, committed file.
51
+ const payload = {
52
+ $schema: PUBLIC_SCHEMA,
53
+ project: binding.project,
54
+ ...(binding.workspace ? { workspace: binding.workspace } : {}),
55
+ ...(binding.defaultEnvironment ? { defaultEnvironment: binding.defaultEnvironment } : {}),
56
+ };
57
+ writeFileSync(publicConfigPath(cwd), `${JSON.stringify(payload, null, 2)}\n`, "utf8");
58
+ // Always (re-)ensure the gitignore protects the private dir, even if the
59
+ // .deployik.json itself is committed. Cheap, defensive — if a teammate
60
+ // dropped the line, the next MCP call patches it back.
61
+ ensureGitignore(cwd);
62
+ // Make sure the private state dir exists so cache.json / token / audit.log
63
+ // have a home, but don't touch the legacy binding file — that stays for
64
+ // backwards compat only.
24
65
  mkdirSync(stateDir, { recursive: true });
25
- writeFileSync(bindingPath(stateDir), `${JSON.stringify(binding, null, 2)}\n`, "utf8");
26
66
  }
27
- /** Append `.deployik/` to the consuming repo's .gitignore if absent. Returns true if it added the line. */
67
+ /**
68
+ * Append `.deployik/` to .gitignore if absent. Idempotent. Returns true if a
69
+ * line was added. Called on every binding write so the protection is
70
+ * self-healing (teammate edits, merge conflicts, manual deletes — all fixed
71
+ * silently next time anything touches `.deployik/`).
72
+ */
28
73
  export function ensureGitignore(cwd) {
29
74
  const gitignorePath = join(cwd, ".gitignore");
30
75
  if (!existsSync(dirname(gitignorePath)))
@@ -41,4 +86,26 @@ export function ensureGitignore(cwd) {
41
86
  appendFileSync(gitignorePath, `${prefix}${GITIGNORE_LINE}\n`, "utf8");
42
87
  return true;
43
88
  }
89
+ /**
90
+ * Verify the public config is sane. Used by `show_binding`-style tools to
91
+ * surface schema issues that would otherwise look like "binding missing".
92
+ */
93
+ export function validatePublicConfig(cwd) {
94
+ const path = publicConfigPath(cwd);
95
+ if (!existsSync(path))
96
+ return { ok: false, reason: "missing" };
97
+ try {
98
+ const raw = readFileSync(path, "utf8");
99
+ const parsed = JSON.parse(raw);
100
+ if (!parsed || typeof parsed !== "object")
101
+ return { ok: false, reason: "not an object" };
102
+ if (typeof parsed.project !== "string" || parsed.project.length === 0) {
103
+ return { ok: false, reason: "missing 'project' string" };
104
+ }
105
+ return { ok: true };
106
+ }
107
+ catch (err) {
108
+ return { ok: false, reason: `parse error: ${err.message}` };
109
+ }
110
+ }
44
111
  //# sourceMappingURL=binding.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/config/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQ1C,MAAM,YAAY,GAAG,cAAc,CAAC;AACpC,MAAM,cAAc,GAAG,YAAY,CAAC;AAEpC,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACpE,OAAO,MAAqB,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,OAAoB;IACjE,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,aAAa,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACxF,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,QAAQ,GAAG,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,cAAc,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,EAAE,CAAC;YAC/E,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5E,cAAc,CAAC,aAAa,EAAE,GAAG,MAAM,GAAG,cAAc,IAAI,EAAE,MAAM,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"binding.js","sourceRoot":"","sources":["../../src/config/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA8B1C,MAAM,WAAW,GAAG,gBAAgB,CAAC;AACrC,MAAM,aAAa,GAAG,2CAA2C,CAAC;AAClE,MAAM,cAAc,GAAG,YAAY,CAAC;AAEpC,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,OAAO,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,GAAY;IACxD,oDAAoD;IACpD,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;gBAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC/B,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBACjD,OAAO;wBACL,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;qBAC9C,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,yBAAyB;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IACD,8EAA8E;IAC9E,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;gBAAE,OAAO,SAAS,CAAC;YACpE,OAAO,MAAqB,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,GAAW,EAAE,OAAoB;IAC9E,8CAA8C;IAC9C,MAAM,OAAO,GAAG;QACd,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1F,CAAC;IACF,aAAa,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEtF,yEAAyE;IACzE,uEAAuE;IACvE,uDAAuD;IACvD,eAAe,CAAC,GAAG,CAAC,CAAC;IAErB,2EAA2E;IAC3E,wEAAwE;IACxE,yBAAyB;IACzB,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9B,QAAQ,GAAG,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,cAAc,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,EAAE,CAAC;YAC/E,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5E,cAAc,CAAC,aAAa,EAAE,GAAG,MAAM,GAAG,cAAc,IAAI,EAAE,MAAM,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC/D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QACzF,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;QAC3D,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAiB,GAAa,CAAC,OAAO,EAAE,EAAE,CAAC;IACzE,CAAC;AACH,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
+ import { ensureGitignore } from "./binding.js";
3
4
  const CACHE_FILE = "cache.json";
4
5
  const DEFAULT_TTL_SECONDS = 60 * 60; // 1h
5
6
  export function cachePath(stateDir) {
@@ -22,6 +23,13 @@ export function readCache(stateDir) {
22
23
  }
23
24
  export function writeCache(stateDir, data) {
24
25
  mkdirSync(stateDir, { recursive: true });
26
+ // Self-heal .gitignore on every cache write — cheap, defensive.
27
+ try {
28
+ ensureGitignore(dirname(stateDir));
29
+ }
30
+ catch {
31
+ // best-effort
32
+ }
25
33
  const full = {
26
34
  version: 1,
27
35
  fetchedAt: new Date().toISOString(),
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/config/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAyBjC,MAAM,UAAU,GAAG,YAAY,CAAC;AAChC,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;AAE1C,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,OAAO,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;QAC5C,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,IAAuF;IAClI,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,IAAI,GAAc;QACtB,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,mBAAmB;QAClD,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC;IACF,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA4B;IACvD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;AACxD,CAAC"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/config/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAyB/C,MAAM,UAAU,GAAG,YAAY,CAAC;AAChC,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;AAE1C,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,OAAO,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;QAC5C,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3C,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,IAAuF;IAClI,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,gEAAgE;IAChE,IAAI,CAAC;QACH,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IACD,MAAM,IAAI,GAAc;QACtB,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,mBAAmB;QAClD,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC;IACF,aAAa,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA4B;IACvD,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;AACxD,CAAC"}
package/dist/index.js CHANGED
@@ -2,12 +2,126 @@
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import { buildServer } from "./server.js";
4
4
  import { ConfigError } from "./config/env.js";
5
+ import { installSkill } from "./install-skill.js";
6
+ import { installMcp, uninstallMcp } from "./install-mcp.js";
7
+ import { installAll } from "./install.js";
8
+ import { VERSION } from "./version.js";
9
+ const HELP = `deployik-mcp ${VERSION}
10
+
11
+ USAGE
12
+ deployik-mcp Start the MCP server over stdio (default).
13
+ deployik-mcp install Register the MCP server in Claude config
14
+ AND copy the bundled skill (recommended).
15
+ deployik-mcp install-mcp Only register the MCP server in Claude config.
16
+ deployik-mcp install-skill Only copy the Deployik skill files.
17
+ deployik-mcp uninstall Remove the 'deployik' MCP server entry from
18
+ every Claude config it lives in.
19
+ deployik-mcp --help, -h Show this message.
20
+ deployik-mcp --version, -v Print version and exit.
21
+
22
+ SCOPES (default: --global)
23
+ --global Install to user-level Claude configs:
24
+ • ~/.claude.json (Claude Code)
25
+ • ~/Library/Application Support/… (Claude Desktop, mac)
26
+ • %APPDATA%/Claude/… (Claude Desktop, win)
27
+ • ~/.config/Claude/… (Claude Desktop, linux)
28
+ Once installed, every project + every
29
+ Claude window has the deployik tools.
30
+ --local Install to the current project only:
31
+ • <cwd>/.mcp.json
32
+ • <cwd>/.claude/skills/deployik-howto/
33
+
34
+ FLAGS
35
+ --yes, -y Skip confirmation prompts (use defaults).
36
+ --url=<url> Deployik URL (default: https://deployik.lovinka.com).
37
+ --token=<dpk_...> Personal Access Token. Required for install
38
+ unless DEPLOYIK_TOKEN env var is set.
39
+
40
+ ENVIRONMENT
41
+ DEPLOYIK_URL Used as the URL default when not passed.
42
+ DEPLOYIK_TOKEN Used as the token default when not passed.
43
+ DEPLOYIK_TIMEOUT_MS Per-request timeout in ms (default 30000).
44
+
45
+ EXAMPLES
46
+ npx -y @lovinka/deployik-mcp install
47
+ Interactive global install: prompts for URL + token, writes Claude
48
+ Code + Claude Desktop configs, copies skill files.
49
+
50
+ npx -y @lovinka/deployik-mcp install --yes --token=dpk_xxx
51
+ Non-interactive global install with default URL.
52
+
53
+ npx -y @lovinka/deployik-mcp install --local --token=dpk_xxx
54
+ Project-scoped install: writes .mcp.json + .claude/skills/ in cwd.
55
+
56
+ npx -y @lovinka/deployik-mcp uninstall
57
+ Removes the 'deployik' MCP server entry from every global Claude config.
58
+ `;
59
+ function parseFlags(argv) {
60
+ let scope = "global";
61
+ let yes = false;
62
+ let url;
63
+ let token;
64
+ for (const arg of argv) {
65
+ if (arg === "--global")
66
+ scope = "global";
67
+ else if (arg === "--local")
68
+ scope = "local";
69
+ else if (arg === "--yes" || arg === "-y")
70
+ yes = true;
71
+ else if (arg.startsWith("--url="))
72
+ url = arg.slice("--url=".length);
73
+ else if (arg.startsWith("--token="))
74
+ token = arg.slice("--token=".length);
75
+ }
76
+ return { scope, yes, url, token };
77
+ }
5
78
  async function main() {
79
+ const argv = process.argv.slice(2);
80
+ if (argv.includes("--help") || argv.includes("-h")) {
81
+ process.stdout.write(HELP);
82
+ process.exit(0);
83
+ }
84
+ if (argv.includes("--version") || argv.includes("-v")) {
85
+ process.stdout.write(`${VERSION}\n`);
86
+ process.exit(0);
87
+ }
88
+ const sub = argv[0];
89
+ const rest = argv.slice(1);
90
+ if (sub === "install") {
91
+ const flags = parseFlags(rest);
92
+ const code = await installAll(flags);
93
+ process.exit(code);
94
+ }
95
+ if (sub === "install-mcp") {
96
+ const flags = parseFlags(rest);
97
+ const code = await installAll({ ...flags, skipSkill: true });
98
+ process.exit(code);
99
+ }
100
+ if (sub === "install-skill") {
101
+ const flags = parseFlags(rest);
102
+ const code = await installSkill({ scope: flags.scope, yes: flags.yes });
103
+ process.exit(code);
104
+ }
105
+ if (sub === "uninstall") {
106
+ const flags = parseFlags(rest);
107
+ const res = uninstallMcp({ scope: flags.scope });
108
+ for (const w of res.written)
109
+ process.stdout.write(` ✓ removed from ${w.path}${w.backupPath ? ` (backup → ${w.backupPath})` : ""}\n`);
110
+ for (const s of res.skipped)
111
+ process.stdout.write(` · ${s.path} — ${s.reason}\n`);
112
+ if (res.written.length === 0)
113
+ process.stdout.write(`Nothing removed.\n`);
114
+ process.exit(0);
115
+ }
116
+ if (sub && !sub.startsWith("-")) {
117
+ process.stderr.write(`Unknown subcommand: ${sub}\nRun \`deployik-mcp --help\` for usage.\n`);
118
+ process.exit(2);
119
+ }
6
120
  try {
7
121
  const { server } = buildServer();
8
122
  const transport = new StdioServerTransport();
9
123
  await server.connect(transport);
10
- process.stderr.write("deployik-mcp ready (stdio)\n");
124
+ process.stderr.write(`deployik-mcp ${VERSION} ready (stdio)\n`);
11
125
  }
12
126
  catch (err) {
13
127
  if (err instanceof ConfigError) {
@@ -18,5 +132,9 @@ async function main() {
18
132
  process.exit(1);
19
133
  }
20
134
  }
135
+ // `installMcp` is exported from a sibling module for programmatic use; the
136
+ // re-export here keeps the published `dist/index.js` self-contained for
137
+ // scripts that prefer requiring the entry point.
138
+ export { installMcp };
21
139
  main();
22
140
  //# sourceMappingURL=index.js.map
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;AAE9C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;YAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAkB,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}