kastell 2.2.4 → 2.2.6

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.
Files changed (199) hide show
  1. package/.claude-plugin/marketplace.json +18 -18
  2. package/.claude-plugin/plugin.json +45 -38
  3. package/CHANGELOG.md +1313 -1266
  4. package/LICENSE +201 -201
  5. package/NOTICE +5 -5
  6. package/README.md +1 -1
  7. package/README.tr.md +1 -1
  8. package/bin/kastell +2 -2
  9. package/bin/kastell-mcp +5 -5
  10. package/dist/adapters/coolify.js +92 -92
  11. package/dist/adapters/dokploy.js +99 -99
  12. package/dist/commands/fix.d.ts +2 -0
  13. package/dist/commands/fix.d.ts.map +1 -1
  14. package/dist/commands/fix.js +26 -1
  15. package/dist/commands/fix.js.map +1 -1
  16. package/dist/commands/interactive/plugins.d.ts.map +1 -1
  17. package/dist/commands/interactive/plugins.js +26 -2
  18. package/dist/commands/interactive/plugins.js.map +1 -1
  19. package/dist/commands/plugin.d.ts.map +1 -1
  20. package/dist/commands/plugin.js +6 -2
  21. package/dist/commands/plugin.js.map +1 -1
  22. package/dist/core/audit/commands.d.ts +13 -2
  23. package/dist/core/audit/commands.d.ts.map +1 -1
  24. package/dist/core/audit/commands.js +39 -2
  25. package/dist/core/audit/commands.js.map +1 -1
  26. package/dist/core/audit/explainCheck.d.ts +1 -0
  27. package/dist/core/audit/explainCheck.d.ts.map +1 -1
  28. package/dist/core/audit/explainCheck.js +1 -1
  29. package/dist/core/audit/explainCheck.js.map +1 -1
  30. package/dist/core/audit/fix-history.d.ts +3 -1
  31. package/dist/core/audit/fix-history.d.ts.map +1 -1
  32. package/dist/core/audit/fix-history.js +6 -2
  33. package/dist/core/audit/fix-history.js.map +1 -1
  34. package/dist/core/audit/fix.d.ts.map +1 -1
  35. package/dist/core/audit/fix.js +22 -0
  36. package/dist/core/audit/fix.js.map +1 -1
  37. package/dist/core/audit/formatters/badge.js +20 -20
  38. package/dist/core/audit/index.d.ts.map +1 -1
  39. package/dist/core/audit/index.js +12 -3
  40. package/dist/core/audit/index.js.map +1 -1
  41. package/dist/core/audit/listChecks.d.ts.map +1 -1
  42. package/dist/core/audit/listChecks.js +24 -0
  43. package/dist/core/audit/listChecks.js.map +1 -1
  44. package/dist/core/audit/pluginAudit.d.ts +8 -0
  45. package/dist/core/audit/pluginAudit.d.ts.map +1 -0
  46. package/dist/core/audit/pluginAudit.js +134 -0
  47. package/dist/core/audit/pluginAudit.js.map +1 -0
  48. package/dist/core/audit/pluginFix.d.ts +19 -0
  49. package/dist/core/audit/pluginFix.d.ts.map +1 -0
  50. package/dist/core/audit/pluginFix.js +122 -0
  51. package/dist/core/audit/pluginFix.js.map +1 -0
  52. package/dist/core/audit/snapshot.d.ts +4 -4
  53. package/dist/core/audit/types.d.ts +2 -1
  54. package/dist/core/audit/types.d.ts.map +1 -1
  55. package/dist/core/completions.js +631 -631
  56. package/dist/core/plugin.d.ts +6 -0
  57. package/dist/core/plugin.d.ts.map +1 -1
  58. package/dist/core/plugin.js +2 -0
  59. package/dist/core/plugin.js.map +1 -1
  60. package/dist/index.js +7 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/mcp/index.js +1 -1
  63. package/dist/mcp/index.js.map +1 -1
  64. package/dist/mcp/pluginTools.d.ts +5 -0
  65. package/dist/mcp/pluginTools.d.ts.map +1 -0
  66. package/dist/mcp/pluginTools.js +54 -0
  67. package/dist/mcp/pluginTools.js.map +1 -0
  68. package/dist/mcp/prompts/workflows.d.ts +17 -0
  69. package/dist/mcp/prompts/workflows.d.ts.map +1 -0
  70. package/dist/mcp/prompts/workflows.js +73 -0
  71. package/dist/mcp/prompts/workflows.js.map +1 -0
  72. package/dist/mcp/resources/checks.d.ts +4 -0
  73. package/dist/mcp/resources/checks.d.ts.map +1 -0
  74. package/dist/mcp/resources/checks.js +49 -0
  75. package/dist/mcp/resources/checks.js.map +1 -0
  76. package/dist/mcp/resources/servers.d.ts +4 -0
  77. package/dist/mcp/resources/servers.d.ts.map +1 -0
  78. package/dist/mcp/resources/servers.js +59 -0
  79. package/dist/mcp/resources/servers.js.map +1 -0
  80. package/dist/mcp/server.d.ts +1 -1
  81. package/dist/mcp/server.d.ts.map +1 -1
  82. package/dist/mcp/server.js +68 -35
  83. package/dist/mcp/server.js.map +1 -1
  84. package/dist/mcp/tools/serverAudit.d.ts +1 -1
  85. package/dist/mcp/tools/serverExplain.d.ts.map +1 -1
  86. package/dist/mcp/tools/serverExplain.js.map +1 -1
  87. package/dist/mcp/tools/serverFix.d.ts.map +1 -1
  88. package/dist/mcp/tools/serverFix.js +7 -1
  89. package/dist/mcp/tools/serverFix.js.map +1 -1
  90. package/dist/mcp/tools/serverFleet.d.ts.map +1 -1
  91. package/dist/mcp/tools/serverFleet.js.map +1 -1
  92. package/dist/mcp/tools/serverInfo.d.ts +1 -1
  93. package/dist/mcp/tools/serverInfo.js +1 -1
  94. package/dist/mcp/tools/serverManage.d.ts +2 -1
  95. package/dist/mcp/tools/serverManage.d.ts.map +1 -1
  96. package/dist/mcp/tools/serverManage.js +50 -5
  97. package/dist/mcp/tools/serverManage.js.map +1 -1
  98. package/dist/mcp/tools/serverPlugin.d.ts +3 -0
  99. package/dist/mcp/tools/serverPlugin.d.ts.map +1 -1
  100. package/dist/mcp/tools/serverPlugin.js +11 -1
  101. package/dist/mcp/tools/serverPlugin.js.map +1 -1
  102. package/dist/mcp/tools/serverProvision.d.ts +5 -5
  103. package/dist/mcp/tools/serverProvision.d.ts.map +1 -1
  104. package/dist/mcp/tools/serverProvision.js +31 -9
  105. package/dist/mcp/tools/serverProvision.js.map +1 -1
  106. package/dist/mcp/tools/serverSecure.d.ts.map +1 -1
  107. package/dist/mcp/tools/serverSecure.js +30 -1
  108. package/dist/mcp/tools/serverSecure.js.map +1 -1
  109. package/dist/mcp/utils.d.ts +25 -0
  110. package/dist/mcp/utils.d.ts.map +1 -1
  111. package/dist/mcp/utils.js +36 -0
  112. package/dist/mcp/utils.js.map +1 -1
  113. package/dist/mcp-bundle.mjs +102301 -0
  114. package/dist/plugin/handlerResolver.d.ts +2 -0
  115. package/dist/plugin/handlerResolver.d.ts.map +1 -0
  116. package/dist/plugin/handlerResolver.js +16 -0
  117. package/dist/plugin/handlerResolver.js.map +1 -0
  118. package/dist/plugin/loader.d.ts.map +1 -1
  119. package/dist/plugin/loader.js +41 -4
  120. package/dist/plugin/loader.js.map +1 -1
  121. package/dist/plugin/registerCommands.d.ts +4 -0
  122. package/dist/plugin/registerCommands.d.ts.map +1 -0
  123. package/dist/plugin/registerCommands.js +45 -0
  124. package/dist/plugin/registerCommands.js.map +1 -0
  125. package/dist/plugin/registry.d.ts +20 -1
  126. package/dist/plugin/registry.d.ts.map +1 -1
  127. package/dist/plugin/registry.js +51 -1
  128. package/dist/plugin/registry.js.map +1 -1
  129. package/dist/plugin/sdk/constants.d.ts +2 -0
  130. package/dist/plugin/sdk/constants.d.ts.map +1 -1
  131. package/dist/plugin/sdk/constants.js +2 -0
  132. package/dist/plugin/sdk/constants.js.map +1 -1
  133. package/dist/plugin/sdk/types.d.ts +74 -1
  134. package/dist/plugin/sdk/types.d.ts.map +1 -1
  135. package/dist/plugin/validate.d.ts +2 -1
  136. package/dist/plugin/validate.d.ts.map +1 -1
  137. package/dist/plugin/validate.js +106 -1
  138. package/dist/plugin/validate.js.map +1 -1
  139. package/dist/utils/cloudInit.js +58 -58
  140. package/dist/utils/fileLock.d.ts +5 -1
  141. package/dist/utils/fileLock.d.ts.map +1 -1
  142. package/dist/utils/fileLock.js +70 -15
  143. package/dist/utils/fileLock.js.map +1 -1
  144. package/dist/utils/paths.d.ts +0 -1
  145. package/dist/utils/paths.d.ts.map +1 -1
  146. package/dist/utils/paths.js +1 -2
  147. package/dist/utils/paths.js.map +1 -1
  148. package/dist/utils/secureWrite.d.ts.map +1 -1
  149. package/dist/utils/secureWrite.js +3 -38
  150. package/dist/utils/secureWrite.js.map +1 -1
  151. package/dist/utils/version.d.ts.map +1 -1
  152. package/dist/utils/version.js +19 -4
  153. package/dist/utils/version.js.map +1 -1
  154. package/kastell-plugin/.claude-plugin/plugin.json +20 -20
  155. package/kastell-plugin/.mcp.json +15 -8
  156. package/kastell-plugin/README.md +113 -113
  157. package/kastell-plugin/agents/kastell-auditor.md +77 -77
  158. package/kastell-plugin/agents/scripts/bucket_mapper.sh +101 -101
  159. package/kastell-plugin/agents/scripts/trend_report.sh +91 -91
  160. package/kastell-plugin/hooks/destroy-block.cjs +31 -31
  161. package/kastell-plugin/hooks/hooks.json +57 -57
  162. package/kastell-plugin/hooks/pre-commit-audit-guard.cjs +75 -75
  163. package/kastell-plugin/hooks/session-audit.cjs +86 -86
  164. package/kastell-plugin/hooks/session-log.cjs +56 -56
  165. package/kastell-plugin/hooks/stop-quality-check.cjs +72 -72
  166. package/kastell-plugin/skills/kastell-careful/SKILL.md +64 -64
  167. package/kastell-plugin/skills/kastell-ops/SKILL.md +139 -139
  168. package/kastell-plugin/skills/kastell-ops/references/commands.md +45 -45
  169. package/kastell-plugin/skills/kastell-ops/references/mcp-tools.md +50 -50
  170. package/kastell-plugin/skills/kastell-ops/references/patterns.md +145 -145
  171. package/kastell-plugin/skills/kastell-ops/references/pitfalls.md +136 -136
  172. package/kastell-plugin/skills/kastell-ops/scripts/check_coverage.sh +101 -101
  173. package/kastell-plugin/skills/kastell-ops/scripts/fleet_report.sh +73 -73
  174. package/kastell-plugin/skills/kastell-ops/scripts/parse_audit.sh +76 -76
  175. package/kastell-plugin/skills/kastell-research/SKILL.md +90 -90
  176. package/kastell-plugin/skills/kastell-scaffold/SKILL.md +104 -104
  177. package/kastell-plugin/skills/kastell-scaffold/references/template-audit-check.md +150 -150
  178. package/kastell-plugin/skills/kastell-scaffold/references/template-command.md +80 -80
  179. package/kastell-plugin/skills/kastell-scaffold/references/template-mcp-tool.md +72 -72
  180. package/kastell-plugin/skills/kastell-scaffold/references/template-provider.md +67 -67
  181. package/kastell-plugin/skills/kastell-scaffold/scripts/scaffold.sh +180 -180
  182. package/kastell-plugin/skills/kastell-scaffold/templates/check-test.ts.tpl +27 -27
  183. package/kastell-plugin/skills/kastell-scaffold/templates/check.ts.tpl +50 -50
  184. package/kastell-plugin/skills/kastell-scaffold/templates/command-core.ts.tpl +18 -18
  185. package/kastell-plugin/skills/kastell-scaffold/templates/command-test.ts.tpl +17 -17
  186. package/kastell-plugin/skills/kastell-scaffold/templates/command.ts.tpl +25 -25
  187. package/kastell-plugin/skills/kastell-scaffold/templates/mcp-tool-test.ts.tpl +30 -30
  188. package/kastell-plugin/skills/kastell-scaffold/templates/mcp-tool.ts.tpl +29 -29
  189. package/kastell-plugin/skills/kastell-scaffold/templates/provider-test.ts.tpl +34 -34
  190. package/kastell-plugin/skills/kastell-scaffold/templates/provider.ts.tpl +32 -32
  191. package/package.json +125 -122
  192. package/dist/commands/interactive.d.ts +0 -11
  193. package/dist/commands/interactive.d.ts.map +0 -1
  194. package/dist/commands/interactive.js +0 -1079
  195. package/dist/commands/interactive.js.map +0 -1
  196. package/dist/core/lock.d.ts +0 -66
  197. package/dist/core/lock.d.ts.map +0 -1
  198. package/dist/core/lock.js +0 -556
  199. package/dist/core/lock.js.map +0 -1
@@ -1,63 +1,63 @@
1
1
  export function getBareCloudInit(serverName) {
2
2
  const safeName = serverName.toLowerCase().replace(/[^a-z0-9-]/g, "");
3
- return `#!/bin/bash
4
- set +e
5
- touch /var/log/kastell-install.log
6
- chmod 600 /var/log/kastell-install.log
7
- exec > >(tee /var/log/kastell-install.log) 2>&1
8
-
9
- echo "=================================="
10
- echo "Kastell Bare Server Setup"
11
- echo "Server: ${safeName}"
12
- echo "=================================="
13
-
14
- # Wait for network connectivity
15
- echo "Waiting for network connectivity..."
16
- MAX_ATTEMPTS=30
17
- ATTEMPTS=0
18
- while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
19
- if curl -s --max-time 5 https://apt.releases.hashicorp.com > /dev/null 2>&1 || curl -s --max-time 5 https://archive.ubuntu.com > /dev/null 2>&1; then
20
- echo "Network is ready!"
21
- break
22
- fi
23
- ATTEMPTS=$((ATTEMPTS + 1))
24
- echo "Network not ready (attempt $ATTEMPTS/$MAX_ATTEMPTS)..."
25
- sleep 2
26
- done
27
-
28
- # Update system packages
29
- echo "Updating system packages..."
30
- apt-get update -y
31
- DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
32
-
33
- # Install hardening packages
34
- echo "Installing hardening packages (fail2ban, ufw, unattended-upgrades)..."
35
- DEBIAN_FRONTEND=noninteractive apt-get install -y fail2ban ufw unattended-upgrades
36
-
37
- # Configure UFW firewall
38
- echo "Configuring UFW firewall..."
39
- ufw allow 22/tcp
40
- ufw allow 80/tcp
41
- ufw allow 443/tcp
42
- echo "y" | ufw enable || true
43
- ufw status
44
-
45
- # Configure unattended-upgrades for automatic security updates
46
- echo "Configuring unattended-upgrades..."
47
- dpkg-reconfigure -f noninteractive unattended-upgrades
48
-
49
- # Enable and start fail2ban
50
- echo "Enabling fail2ban..."
51
- systemctl enable fail2ban || true
52
- systemctl start fail2ban || true
53
-
54
- echo "=================================="
55
- echo "Bare server setup completed!"
56
- echo "Server: ${safeName}"
57
- echo "=================================="
58
- echo ""
59
- echo "Your server is ready. Connect via SSH:"
60
- echo " ssh root@YOUR_SERVER_IP"
3
+ return `#!/bin/bash
4
+ set +e
5
+ touch /var/log/kastell-install.log
6
+ chmod 600 /var/log/kastell-install.log
7
+ exec > >(tee /var/log/kastell-install.log) 2>&1
8
+
9
+ echo "=================================="
10
+ echo "Kastell Bare Server Setup"
11
+ echo "Server: ${safeName}"
12
+ echo "=================================="
13
+
14
+ # Wait for network connectivity
15
+ echo "Waiting for network connectivity..."
16
+ MAX_ATTEMPTS=30
17
+ ATTEMPTS=0
18
+ while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
19
+ if curl -s --max-time 5 https://apt.releases.hashicorp.com > /dev/null 2>&1 || curl -s --max-time 5 https://archive.ubuntu.com > /dev/null 2>&1; then
20
+ echo "Network is ready!"
21
+ break
22
+ fi
23
+ ATTEMPTS=$((ATTEMPTS + 1))
24
+ echo "Network not ready (attempt $ATTEMPTS/$MAX_ATTEMPTS)..."
25
+ sleep 2
26
+ done
27
+
28
+ # Update system packages
29
+ echo "Updating system packages..."
30
+ apt-get update -y
31
+ DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
32
+
33
+ # Install hardening packages
34
+ echo "Installing hardening packages (fail2ban, ufw, unattended-upgrades)..."
35
+ DEBIAN_FRONTEND=noninteractive apt-get install -y fail2ban ufw unattended-upgrades
36
+
37
+ # Configure UFW firewall
38
+ echo "Configuring UFW firewall..."
39
+ ufw allow 22/tcp
40
+ ufw allow 80/tcp
41
+ ufw allow 443/tcp
42
+ echo "y" | ufw enable || true
43
+ ufw status
44
+
45
+ # Configure unattended-upgrades for automatic security updates
46
+ echo "Configuring unattended-upgrades..."
47
+ dpkg-reconfigure -f noninteractive unattended-upgrades
48
+
49
+ # Enable and start fail2ban
50
+ echo "Enabling fail2ban..."
51
+ systemctl enable fail2ban || true
52
+ systemctl start fail2ban || true
53
+
54
+ echo "=================================="
55
+ echo "Bare server setup completed!"
56
+ echo "Server: ${safeName}"
57
+ echo "=================================="
58
+ echo ""
59
+ echo "Your server is ready. Connect via SSH:"
60
+ echo " ssh root@YOUR_SERVER_IP"
61
61
  `;
62
62
  }
63
63
  //# sourceMappingURL=cloudInit.js.map
@@ -1,4 +1,8 @@
1
- export declare function withFileLock<T>(filePath: string, fn: () => Promise<T> | T): Promise<T>;
1
+ /** Module-local wrapper for testability DO NOT inline `process.kill`. */
2
+ export declare function probeProcess(pid: number): "alive" | "dead" | "unknown";
3
+ type ProbeFn = (pid: number) => "alive" | "dead" | "unknown";
4
+ export declare function withFileLock<T>(filePath: string, fn: () => Promise<T> | T, probe?: ProbeFn): Promise<T>;
2
5
  /** Warn on stderr if a caught error is a permission issue. Returns true if it was a permission error. */
3
6
  export declare function warnIfPermissionError(err: unknown, label: string): boolean;
7
+ export {};
4
8
  //# sourceMappingURL=fileLock.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fileLock.d.ts","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"AAKA,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAyCZ;AAED,yGAAyG;AACzG,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO1E"}
1
+ {"version":3,"file":"fileLock.d.ts","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"AAQA,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAStE;AAoBD,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAsB7D,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EACxB,KAAK,GAAE,OAAsB,GAC5B,OAAO,CAAC,CAAC,CAAC,CA+CZ;AAED,yGAAyG;AACzG,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAO1E"}
@@ -1,21 +1,78 @@
1
- import { mkdirSync, rmdirSync, statSync } from "fs";
2
- import { dirname } from "path";
3
- const STALE_THRESHOLD_MS = 30_000; // 30s
4
- export async function withFileLock(filePath, fn) {
1
+ import { mkdirSync, rmSync, statSync, writeFileSync, readFileSync } from "fs";
2
+ import { dirname, join } from "path";
3
+ import { hostname } from "os";
4
+ const STALE_THRESHOLD_MS = 30_000;
5
+ // Reclaim even when probeProcess reports "alive" (guards against clock drift, zombies, PID reuse).
6
+ const HARD_CEILING_MS = 60_000;
7
+ /** Module-local wrapper for testability — DO NOT inline `process.kill`. */
8
+ export function probeProcess(pid) {
9
+ try {
10
+ process.kill(pid, 0);
11
+ return "alive";
12
+ }
13
+ catch (err) {
14
+ const code = err.code;
15
+ if (code === "ESRCH")
16
+ return "dead";
17
+ return "unknown";
18
+ }
19
+ }
20
+ function readPidFile(lockDir) {
21
+ try {
22
+ const raw = readFileSync(join(lockDir, "owner.pid"), "utf-8");
23
+ const parts = raw.split("@");
24
+ if (parts.length !== 3)
25
+ return null;
26
+ const pid = parseInt(parts[0], 10);
27
+ if (isNaN(pid) || pid <= 0)
28
+ return null;
29
+ return { pid, host: parts[1] };
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ function shouldReclaimStaleLock(lockDir, probe) {
36
+ let mtimeMs;
37
+ try {
38
+ mtimeMs = statSync(lockDir).mtimeMs;
39
+ }
40
+ catch {
41
+ return false; // lock disappeared between checks
42
+ }
43
+ const age = Date.now() - mtimeMs;
44
+ const parsed = readPidFile(lockDir);
45
+ if (parsed && parsed.host === hostname()) {
46
+ const liveness = probe(parsed.pid);
47
+ if (liveness === "dead")
48
+ return true;
49
+ if (liveness === "alive")
50
+ return age > HARD_CEILING_MS;
51
+ // "unknown" → mtime fallback (aggressive: STALE_THRESHOLD_MS)
52
+ }
53
+ // farklı hostname, parse fail, PID file yok, veya "unknown" → mtime fallback
54
+ return age > STALE_THRESHOLD_MS;
55
+ }
56
+ export async function withFileLock(filePath, fn, probe = probeProcess) {
5
57
  const lockDir = filePath + ".lock";
6
58
  const maxRetries = 10;
7
59
  const retryDelay = 200;
8
- // Ensure parent directory exists (CI runners may not have ~/.kastell/)
9
60
  mkdirSync(dirname(lockDir), { recursive: true });
10
61
  for (let i = 0; i < maxRetries; i++) {
11
62
  try {
12
63
  mkdirSync(lockDir);
13
64
  try {
65
+ try {
66
+ writeFileSync(join(lockDir, "owner.pid"), `${process.pid}@${hostname()}@${Date.now()}`, { encoding: "utf-8" });
67
+ }
68
+ catch {
69
+ /* best effort — if PID write fails, mtime fallback still protects */
70
+ }
14
71
  return await fn();
15
72
  }
16
73
  finally {
17
74
  try {
18
- rmdirSync(lockDir);
75
+ rmSync(lockDir, { recursive: true, force: true });
19
76
  }
20
77
  catch {
21
78
  /* best effort */
@@ -24,16 +81,14 @@ export async function withFileLock(filePath, fn) {
24
81
  }
25
82
  catch (err) {
26
83
  if (err.code === "EEXIST") {
27
- // Stale lock detection
28
- try {
29
- const stat = statSync(lockDir);
30
- if (Date.now() - stat.mtimeMs > STALE_THRESHOLD_MS) {
31
- rmdirSync(lockDir);
32
- continue;
84
+ if (shouldReclaimStaleLock(lockDir, probe)) {
85
+ try {
86
+ rmSync(lockDir, { recursive: true, force: true });
33
87
  }
34
- }
35
- catch {
36
- /* lock was released between checks */
88
+ catch {
89
+ /* best effort, retry */
90
+ }
91
+ continue;
37
92
  }
38
93
  await new Promise((r) => setTimeout(r, retryDelay));
39
94
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"fileLock.js","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,MAAM;AAEzC,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAgB,EAChB,EAAwB;IAExB,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,UAAU,GAAG,EAAE,CAAC;IACtB,MAAM,UAAU,GAAG,GAAG,CAAC;IAEvB,uEAAuE;IACvE,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC;gBACH,OAAO,MAAM,EAAE,EAAE,CAAC;YACpB,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC;oBACH,SAAS,CAAC,OAAO,CAAC,CAAC;gBACrB,CAAC;gBAAC,MAAM,CAAC;oBACP,iBAAiB;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrD,uBAAuB;gBACvB,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;oBAC/B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,kBAAkB,EAAE,CAAC;wBACnD,SAAS,CAAC,OAAO,CAAC,CAAC;wBACnB,SAAS;oBACX,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,sCAAsC;gBACxC,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;gBACpD,SAAS;YACX,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,6BAA6B,QAAQ,UAAU,UAAU,UAAU,CACpE,CAAC;AACJ,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,qBAAqB,CAAC,GAAY,EAAE,KAAa;IAC/D,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;IACjD,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"fileLock.js","sourceRoot":"","sources":["../../src/utils/fileLock.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- /** Canonical Kastell config directory: ~/.kastell */
2
1
  export declare const KASTELL_DIR: string;
3
2
  /** Backups directory: ~/.kastell/backups */
4
3
  export declare const BACKUPS_DIR: string;
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAGA,qDAAqD;AACrD,eAAO,MAAM,WAAW,QAA8B,CAAC;AAEvD,4CAA4C;AAC5C,eAAO,MAAM,WAAW,QAA+B,CAAC;AAExD,kDAAkD;AAClD,eAAO,MAAM,YAAY,QAAoC,CAAC;AAE9D,oDAAoD;AACpD,eAAO,MAAM,WAAW,QAA+B,CAAC;AAExD,2DAA2D;AAC3D,eAAO,MAAM,oBAAoB,QAAoC,CAAC"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,QAAyD,CAAC;AAElF,4CAA4C;AAC5C,eAAO,MAAM,WAAW,QAA+B,CAAC;AAExD,kDAAkD;AAClD,eAAO,MAAM,YAAY,QAAoC,CAAC;AAE9D,oDAAoD;AACpD,eAAO,MAAM,WAAW,QAA+B,CAAC;AAExD,2DAA2D;AAC3D,eAAO,MAAM,oBAAoB,QAAoC,CAAC"}
@@ -1,7 +1,6 @@
1
1
  import { homedir } from "os";
2
2
  import { join } from "path";
3
- /** Canonical Kastell config directory: ~/.kastell */
4
- export const KASTELL_DIR = join(homedir(), ".kastell");
3
+ export const KASTELL_DIR = process.env.KASTELL_DIR || join(homedir(), ".kastell");
5
4
  /** Backups directory: ~/.kastell/backups */
6
5
  export const BACKUPS_DIR = join(KASTELL_DIR, "backups");
7
6
  /** Security audit log: ~/.kastell/security.log */
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAEvD,4CAA4C;AAC5C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAExD,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAE9D,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAExD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAElF,4CAA4C;AAC5C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAExD,kDAAkD;AAClD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAE9D,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAExD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"secureWrite.d.ts","sourceRoot":"","sources":["../../src/utils/secureWrite.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAUD,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AA8BD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMrD;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,GACzB,IAAI,CAGN;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAChC,IAAI,CAGN"}
1
+ {"version":3,"file":"secureWrite.d.ts","sourceRoot":"","sources":["../../src/utils/secureWrite.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAOD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMrD;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,GACzB,IAAI,CAGN;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAChC,IAAI,CAGN"}
@@ -1,47 +1,12 @@
1
- import { spawnSync } from "child_process";
2
1
  import { writeFileSync, mkdirSync, chmodSync } from "fs";
3
- import { userInfo } from "os";
4
- import { SecurityLogger } from "./securityLogger.js";
5
- import { extractReason } from "./errors.js";
6
- let cachedUsername;
7
- function getUsername() {
8
- if (!cachedUsername)
9
- cachedUsername = userInfo().username;
10
- return cachedUsername;
11
- }
12
2
  const securedDirs = new Set();
13
3
  export function clearCache() {
14
4
  securedDirs.clear();
15
- cachedUsername = undefined;
16
5
  }
17
6
  function applyPermissions(targetPath, mode) {
18
- if (process.platform === "win32") {
19
- const result = spawnSync("icacls", [
20
- targetPath,
21
- "/inheritance:r",
22
- "/grant:r",
23
- `${getUsername()}:F`,
24
- ]);
25
- if (result.status !== 0) {
26
- SecurityLogger.warn("ACL operation failed", {
27
- path: targetPath,
28
- platform: process.platform,
29
- error: result.stderr?.toString() ?? "unknown",
30
- });
31
- }
32
- }
33
- else {
34
- try {
35
- chmodSync(targetPath, mode);
36
- }
37
- catch (error) {
38
- SecurityLogger.warn("chmod operation failed", {
39
- path: targetPath,
40
- platform: process.platform,
41
- error: extractReason(error),
42
- });
43
- }
44
- }
7
+ if (process.platform === "win32")
8
+ return; // ACL hardening → v2.4 backlog
9
+ chmodSync(targetPath, mode);
45
10
  }
46
11
  export function ensureSecureDir(dirPath) {
47
12
  if (securedDirs.has(dirPath)) {
@@ -1 +1 @@
1
- {"version":3,"file":"secureWrite.js","sourceRoot":"","sources":["../../src/utils/secureWrite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAO5C,IAAI,cAAkC,CAAC;AACvC,SAAS,WAAW;IAClB,IAAI,CAAC,cAAc;QAAE,cAAc,GAAG,QAAQ,EAAE,CAAC,QAAQ,CAAC;IAC1D,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;AAEtC,MAAM,UAAU,UAAU;IACxB,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,cAAc,GAAG,SAAS,CAAC;AAC7B,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAkB,EAAE,IAAmB;IAC/D,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE;YACjC,UAAU;YACV,gBAAgB;YAChB,UAAU;YACV,GAAG,WAAW,EAAE,IAAI;SACrB,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,cAAc,CAAC,IAAI,CAAC,sBAAsB,EAAE;gBAC1C,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,SAAS;aAC9C,CAAC,CAAC;QACL,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,cAAc,CAAC,IAAI,CAAC,wBAAwB,EAAE;gBAC5C,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC;aAC5B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO;IACT,CAAC;IACD,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACjC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,IAAY,EACZ,OAA0B;IAE1B,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,OAAiC;IAEjC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9D,eAAe,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"secureWrite.js","sourceRoot":"","sources":["../../src/utils/secureWrite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAOzD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;AAEtC,MAAM,UAAU,UAAU;IACxB,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAkB,EAAE,IAAmB;IAC/D,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,CAAC,+BAA+B;IACzE,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO;IACT,CAAC;IACD,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACjC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,IAAY,EACZ,OAA0B;IAE1B,aAAa,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,OAAiC;IAEjC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9D,eAAe,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/utils/version.ts"],"names":[],"mappings":"AAMA,wBAAgB,iBAAiB,IAAI,MAAM,CAU1C;AAED,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/utils/version.ts"],"names":[],"mappings":"AAkBA,wBAAgB,iBAAiB,IAAI,MAAM,CAW1C;AAED,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -1,13 +1,28 @@
1
- import { readFileSync } from "fs";
2
- import { join } from "path";
1
+ import { readFileSync, existsSync } from "fs";
2
+ import { join, dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  let cachedVersion = null;
5
+ function findPackageJson() {
6
+ let dir = fileURLToPath(new URL(".", import.meta.url));
7
+ for (let i = 0; i < 5; i++) {
8
+ const candidate = join(dir, "package.json");
9
+ if (existsSync(candidate))
10
+ return candidate;
11
+ const parent = dirname(dir);
12
+ if (parent === dir)
13
+ break;
14
+ dir = parent;
15
+ }
16
+ return null;
17
+ }
5
18
  export function getKastellVersion() {
6
19
  if (cachedVersion !== null)
7
20
  return cachedVersion;
8
21
  try {
9
- const __dirname = fileURLToPath(new URL(".", import.meta.url));
10
- const pkg = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
22
+ const pkgPath = findPackageJson();
23
+ if (!pkgPath)
24
+ return "0.0.0";
25
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
11
26
  cachedVersion = pkg.version;
12
27
  return cachedVersion;
13
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/utils/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,IAAI,aAAa,GAAkB,IAAI,CAAC;AAExC,MAAM,UAAU,iBAAiB;IAC/B,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAa,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAwB,CAAC;QAC5G,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC;QAC5B,OAAO,aAAa,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,EAAE,CAAC;AAEnD,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/utils/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,IAAI,aAAa,GAAkB,IAAI,CAAC;AAExC,SAAS,eAAe;IACtB,IAAI,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAa,CAAC;IACjD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;QAClC,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAwB,CAAC;QAC9E,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC;QAC5B,OAAO,aAAa,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,EAAE,CAAC;AAEnD,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC"}
@@ -1,20 +1,20 @@
1
- {
2
- "name": "kastell",
3
- "version": "2.2.0",
4
- "description": "Autonomous server security and infrastructure management. Provides 13 MCP tools for cloud server provisioning, security auditing (457 checks), hardening, backup, and fleet management across Hetzner, DigitalOcean, Vultr, and Linode.",
5
- "author": {
6
- "name": "kastelldev"
7
- },
8
- "homepage": "https://kastell.dev",
9
- "repository": "https://github.com/kastelldev/kastell",
10
- "keywords": [
11
- "server",
12
- "security",
13
- "infrastructure",
14
- "mcp",
15
- "audit",
16
- "hardening",
17
- "vps",
18
- "cloud"
19
- ]
20
- }
1
+ {
2
+ "name": "kastell",
3
+ "version": "2.2.5",
4
+ "description": "Autonomous server security and infrastructure management. Provides 17 MCP tools for cloud server provisioning, security auditing (457 checks), hardening, backup, and fleet management across Hetzner, DigitalOcean, Vultr, and Linode.",
5
+ "author": {
6
+ "name": "kastelldev"
7
+ },
8
+ "homepage": "https://kastell.dev",
9
+ "repository": "https://github.com/kastelldev/kastell",
10
+ "keywords": [
11
+ "server",
12
+ "security",
13
+ "infrastructure",
14
+ "mcp",
15
+ "audit",
16
+ "hardening",
17
+ "vps",
18
+ "cloud"
19
+ ]
20
+ }
@@ -1,8 +1,15 @@
1
- {
2
- "mcpServers": {
3
- "kastell": {
4
- "command": "node",
5
- "args": ["${CLAUDE_PLUGIN_ROOT}/../../bin/kastell-mcp"]
6
- }
7
- }
8
- }
1
+ {
2
+ "mcpServers": {
3
+ "kastell": {
4
+ "command": "node",
5
+ "args": ["${CLAUDE_PLUGIN_ROOT}/../../dist/mcp-bundle.mjs"],
6
+ "env": {
7
+ "HETZNER_TOKEN": "${HETZNER_TOKEN}",
8
+ "DIGITALOCEAN_TOKEN": "${DIGITALOCEAN_TOKEN}",
9
+ "VULTR_TOKEN": "${VULTR_TOKEN}",
10
+ "LINODE_TOKEN": "${LINODE_TOKEN}",
11
+ "KASTELL_SAFE_MODE": "true"
12
+ }
13
+ }
14
+ }
15
+ }