@melihmucuk/leash 1.0.9 → 1.0.11
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 +13 -6
- package/dist/cli/leash.js +1799 -0
- package/package.json +22 -13
- package/bin/leash.js +0 -204
- package/bin/lib.js +0 -225
- package/packages/core/lib/version-checker.js +0 -44
package/package.json
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melihmucuk/leash",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Security guardrails for AI coding agents",
|
|
6
6
|
"bin": {
|
|
7
|
-
"leash": "
|
|
7
|
+
"leash": "dist/cli/leash.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"dist/"
|
|
11
|
-
"bin/",
|
|
12
|
-
"!bin/test/",
|
|
13
|
-
"packages/core/lib/version-checker.js"
|
|
10
|
+
"dist/"
|
|
14
11
|
],
|
|
15
12
|
"author": "Melih Mucuk",
|
|
16
13
|
"license": "MIT",
|
|
@@ -28,31 +25,43 @@
|
|
|
28
25
|
"plugin",
|
|
29
26
|
"hooks",
|
|
30
27
|
"file-system",
|
|
31
|
-
"protection"
|
|
28
|
+
"protection",
|
|
29
|
+
"pi-package"
|
|
32
30
|
],
|
|
31
|
+
"pi": {
|
|
32
|
+
"extensions": [
|
|
33
|
+
"./dist/pi/leash.js"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
33
36
|
"homepage": "https://github.com/melihmucuk/leash",
|
|
34
37
|
"bugs": {
|
|
35
38
|
"url": "https://github.com/melihmucuk/leash/issues"
|
|
36
39
|
},
|
|
37
40
|
"repository": {
|
|
38
41
|
"type": "git",
|
|
39
|
-
"url": "https://github.com/melihmucuk/leash.git"
|
|
42
|
+
"url": "git+https://github.com/melihmucuk/leash.git"
|
|
40
43
|
},
|
|
41
44
|
"scripts": {
|
|
42
|
-
"test": "npm run build:core && node --test 'packages/core/test/*.test.js' '
|
|
45
|
+
"test": "npm run build:core && npm run build:cli-lib && node --test 'packages/core/test/*.test.js' 'packages/cli/test/*.test.js'",
|
|
43
46
|
"typecheck": "tsc --noEmit",
|
|
44
|
-
"build": "npm run build:core && npm run build:opencode && npm run build:pi && npm run build:claude-code && npm run build:factory",
|
|
47
|
+
"build": "npm run build:core && npm run build:cli && npm run build:opencode && npm run build:pi && npm run build:claude-code && npm run build:factory",
|
|
45
48
|
"build:core": "esbuild packages/core/*.ts --outdir=packages/core/lib --platform=node --format=esm",
|
|
49
|
+
"build:cli-lib": "esbuild packages/cli/lib.ts --outdir=packages/cli/lib --platform=node --format=esm --main-fields=module,main",
|
|
50
|
+
"build:cli": "esbuild packages/cli/leash.ts --bundle --outfile=dist/cli/leash.js --platform=node --format=esm --main-fields=module,main --banner:js='#!/usr/bin/env node'",
|
|
46
51
|
"build:opencode": "esbuild packages/opencode/leash.ts --bundle --outfile=dist/opencode/leash.js --platform=node --format=esm --external:@opencode-ai/plugin",
|
|
47
52
|
"build:pi": "esbuild packages/pi/leash.ts --bundle --outfile=dist/pi/leash.js --platform=node --format=esm --external:@mariozechner/pi-coding-agent",
|
|
48
53
|
"build:claude-code": "esbuild packages/claude-code/leash.ts --bundle --outfile=dist/claude-code/leash.js --platform=node --format=esm",
|
|
49
54
|
"build:factory": "esbuild packages/factory/leash.ts --bundle --outfile=dist/factory/leash.js --platform=node --format=esm"
|
|
50
55
|
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@mariozechner/pi-coding-agent": "*"
|
|
58
|
+
},
|
|
51
59
|
"devDependencies": {
|
|
52
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
53
|
-
"@opencode-ai/plugin": "^1.
|
|
60
|
+
"@mariozechner/pi-coding-agent": "^0.37.8",
|
|
61
|
+
"@opencode-ai/plugin": "^1.1.4",
|
|
54
62
|
"@types/node": "^22.19.3",
|
|
55
63
|
"esbuild": "^0.27.2",
|
|
64
|
+
"jsonc-parser": "^3.3.1",
|
|
56
65
|
"typescript": "^5.9.3"
|
|
57
66
|
}
|
|
58
|
-
}
|
|
67
|
+
}
|
package/bin/leash.js
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { existsSync } from "fs";
|
|
4
|
-
import { dirname, join } from "path";
|
|
5
|
-
import { homedir } from "os";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
import { execSync } from "child_process";
|
|
8
|
-
import { PLATFORMS, setupPlatform, removePlatform } from "./lib.js";
|
|
9
|
-
import { checkForUpdates } from "../packages/core/lib/version-checker.js";
|
|
10
|
-
|
|
11
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
|
|
13
|
-
function getDistPath() {
|
|
14
|
-
return join(__dirname, "..", "dist");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function getConfigPath(platformKey) {
|
|
18
|
-
const platform = PLATFORMS[platformKey];
|
|
19
|
-
if (!platform) return null;
|
|
20
|
-
|
|
21
|
-
// Support multiple config paths (first existing wins, fallback to last)
|
|
22
|
-
if (platform.configPaths) {
|
|
23
|
-
for (const p of platform.configPaths) {
|
|
24
|
-
const full = join(homedir(), p);
|
|
25
|
-
if (existsSync(full)) return full;
|
|
26
|
-
}
|
|
27
|
-
return join(homedir(), platform.configPaths.at(-1));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return join(homedir(), platform.configPath);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function getLeashPath(platformKey) {
|
|
34
|
-
const platform = PLATFORMS[platformKey];
|
|
35
|
-
return platform ? join(getDistPath(), platform.distPath) : null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function setup(platformKey) {
|
|
39
|
-
const configPath = getConfigPath(platformKey);
|
|
40
|
-
const leashPath = getLeashPath(platformKey);
|
|
41
|
-
|
|
42
|
-
if (!configPath || !leashPath) {
|
|
43
|
-
console.error(`Unknown platform: ${platformKey}`);
|
|
44
|
-
console.error(`Available: ${Object.keys(PLATFORMS).join(", ")}`);
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!existsSync(leashPath)) {
|
|
49
|
-
console.error(`Leash not found at: ${leashPath}`);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const result = setupPlatform(platformKey, configPath, leashPath);
|
|
54
|
-
|
|
55
|
-
if (result.error) {
|
|
56
|
-
console.error(result.error);
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (result.skipped) {
|
|
61
|
-
console.log(`[ok] Leash already installed for ${result.platform}`);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
console.log(`[ok] Config: ${result.configPath}`);
|
|
66
|
-
console.log(`[ok] Leash installed for ${result.platform}`);
|
|
67
|
-
console.log(`[ok] Restart ${result.platform} to apply changes`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function remove(platformKey) {
|
|
71
|
-
const configPath = getConfigPath(platformKey);
|
|
72
|
-
|
|
73
|
-
if (!configPath) {
|
|
74
|
-
console.error(`Unknown platform: ${platformKey}`);
|
|
75
|
-
console.error(`Available: ${Object.keys(PLATFORMS).join(", ")}`);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const result = removePlatform(platformKey, configPath);
|
|
80
|
-
|
|
81
|
-
if (result.error) {
|
|
82
|
-
console.error(result.error);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (result.notFound) {
|
|
87
|
-
console.log(`[ok] No config found for ${result.platform}`);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (result.notInstalled) {
|
|
92
|
-
console.log(`[ok] Leash not found in ${result.platform} config`);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
console.log(`[ok] Leash removed from ${result.platform}`);
|
|
97
|
-
console.log(`[ok] Restart ${result.platform} to apply changes`);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function showPath(platformKey) {
|
|
101
|
-
const leashPath = getLeashPath(platformKey);
|
|
102
|
-
|
|
103
|
-
if (!leashPath) {
|
|
104
|
-
console.error(`Unknown platform: ${platformKey}`);
|
|
105
|
-
console.error(`Available: ${Object.keys(PLATFORMS).join(", ")}`);
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
console.log(leashPath);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function update() {
|
|
113
|
-
console.log("Checking for updates...");
|
|
114
|
-
|
|
115
|
-
const result = await checkForUpdates();
|
|
116
|
-
|
|
117
|
-
if (!result.hasUpdate) {
|
|
118
|
-
console.log(`[ok] Already up to date (v${result.currentVersion})`);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log(`[ok] Update available: v${result.currentVersion} → v${result.latestVersion}`);
|
|
123
|
-
console.log("[ok] Updating...");
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
execSync("npm update -g @melihmucuk/leash", { stdio: "inherit" });
|
|
127
|
-
console.log("[ok] Update complete");
|
|
128
|
-
} catch {
|
|
129
|
-
console.error("[error] Update failed. Try manually: npm update -g @melihmucuk/leash");
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function showHelp() {
|
|
135
|
-
console.log(`
|
|
136
|
-
leash - Security guardrails for AI coding agents
|
|
137
|
-
|
|
138
|
-
Usage:
|
|
139
|
-
leash --setup <platform> Install leash for a platform
|
|
140
|
-
leash --remove <platform> Remove leash from a platform
|
|
141
|
-
leash --path <platform> Show leash path for a platform
|
|
142
|
-
leash --update Update leash to latest version
|
|
143
|
-
leash --help Show this help
|
|
144
|
-
|
|
145
|
-
Platforms:
|
|
146
|
-
opencode OpenCode
|
|
147
|
-
pi Pi Coding Agent
|
|
148
|
-
claude-code Claude Code
|
|
149
|
-
factory Factory Droid
|
|
150
|
-
|
|
151
|
-
Examples:
|
|
152
|
-
leash --setup opencode
|
|
153
|
-
leash --remove claude-code
|
|
154
|
-
leash --path pi
|
|
155
|
-
leash --update
|
|
156
|
-
`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const args = process.argv.slice(2);
|
|
160
|
-
const command = args[0];
|
|
161
|
-
const platform = args[1];
|
|
162
|
-
|
|
163
|
-
switch (command) {
|
|
164
|
-
case "--setup":
|
|
165
|
-
case "-s":
|
|
166
|
-
if (!platform) {
|
|
167
|
-
console.error("Missing platform argument");
|
|
168
|
-
showHelp();
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
setup(platform);
|
|
172
|
-
break;
|
|
173
|
-
case "--remove":
|
|
174
|
-
case "-r":
|
|
175
|
-
if (!platform) {
|
|
176
|
-
console.error("Missing platform argument");
|
|
177
|
-
showHelp();
|
|
178
|
-
process.exit(1);
|
|
179
|
-
}
|
|
180
|
-
remove(platform);
|
|
181
|
-
break;
|
|
182
|
-
case "--path":
|
|
183
|
-
case "-p":
|
|
184
|
-
if (!platform) {
|
|
185
|
-
console.error("Missing platform argument");
|
|
186
|
-
showHelp();
|
|
187
|
-
process.exit(1);
|
|
188
|
-
}
|
|
189
|
-
showPath(platform);
|
|
190
|
-
break;
|
|
191
|
-
case "--update":
|
|
192
|
-
case "-u":
|
|
193
|
-
await update();
|
|
194
|
-
break;
|
|
195
|
-
case "--help":
|
|
196
|
-
case "-h":
|
|
197
|
-
case undefined:
|
|
198
|
-
showHelp();
|
|
199
|
-
break;
|
|
200
|
-
default:
|
|
201
|
-
console.error(`Unknown command: ${command}`);
|
|
202
|
-
showHelp();
|
|
203
|
-
process.exit(1);
|
|
204
|
-
}
|
package/bin/lib.js
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2
|
-
import { dirname } from "path";
|
|
3
|
-
|
|
4
|
-
export const PLATFORMS = {
|
|
5
|
-
opencode: {
|
|
6
|
-
name: "OpenCode",
|
|
7
|
-
configPaths: [
|
|
8
|
-
".config/opencode/opencode.jsonc",
|
|
9
|
-
".config/opencode/opencode.json",
|
|
10
|
-
],
|
|
11
|
-
distPath: "opencode/leash.js",
|
|
12
|
-
setup: (config, leashPath) => {
|
|
13
|
-
config.plugin = config.plugin || [];
|
|
14
|
-
if (config.plugin.some((p) => p.includes("leash"))) {
|
|
15
|
-
return { skipped: true };
|
|
16
|
-
}
|
|
17
|
-
config.plugin.push(leashPath);
|
|
18
|
-
return { skipped: false };
|
|
19
|
-
},
|
|
20
|
-
remove: (config) => {
|
|
21
|
-
if (!config.plugin) return false;
|
|
22
|
-
const before = config.plugin.length;
|
|
23
|
-
config.plugin = config.plugin.filter((p) => !p.includes("leash"));
|
|
24
|
-
return config.plugin.length < before;
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
pi: {
|
|
28
|
-
name: "Pi",
|
|
29
|
-
configPath: ".pi/agent/settings.json",
|
|
30
|
-
distPath: "pi/leash.js",
|
|
31
|
-
setup: (config, leashPath) => {
|
|
32
|
-
config.extensions = config.extensions || [];
|
|
33
|
-
if (config.extensions.some((e) => e.includes("leash"))) {
|
|
34
|
-
return { skipped: true };
|
|
35
|
-
}
|
|
36
|
-
config.extensions.push(leashPath);
|
|
37
|
-
return { skipped: false };
|
|
38
|
-
},
|
|
39
|
-
remove: (config) => {
|
|
40
|
-
if (!config.extensions) return false;
|
|
41
|
-
const before = config.extensions.length;
|
|
42
|
-
config.extensions = config.extensions.filter((e) => !e.includes("leash"));
|
|
43
|
-
return config.extensions.length < before;
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
"claude-code": {
|
|
47
|
-
name: "Claude Code",
|
|
48
|
-
configPath: ".claude/settings.json",
|
|
49
|
-
distPath: "claude-code/leash.js",
|
|
50
|
-
setup: (config, leashPath) => {
|
|
51
|
-
config.hooks = config.hooks || {};
|
|
52
|
-
const hookCommand = { type: "command", command: `node ${leashPath}` };
|
|
53
|
-
|
|
54
|
-
// Check if already installed in either hook
|
|
55
|
-
const inSessionStart = config.hooks.SessionStart?.some((entry) =>
|
|
56
|
-
entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
57
|
-
);
|
|
58
|
-
const inPreToolUse = config.hooks.PreToolUse?.some((entry) =>
|
|
59
|
-
entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
60
|
-
);
|
|
61
|
-
if (inSessionStart && inPreToolUse) {
|
|
62
|
-
return { skipped: true };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Add SessionStart hook
|
|
66
|
-
if (!inSessionStart) {
|
|
67
|
-
config.hooks.SessionStart = config.hooks.SessionStart || [];
|
|
68
|
-
config.hooks.SessionStart.push({
|
|
69
|
-
hooks: [hookCommand],
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Add PreToolUse hook
|
|
74
|
-
if (!inPreToolUse) {
|
|
75
|
-
config.hooks.PreToolUse = config.hooks.PreToolUse || [];
|
|
76
|
-
config.hooks.PreToolUse.push({
|
|
77
|
-
matcher: "Bash|Write|Edit",
|
|
78
|
-
hooks: [hookCommand],
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return { skipped: false };
|
|
83
|
-
},
|
|
84
|
-
remove: (config) => {
|
|
85
|
-
if (!config.hooks) return false;
|
|
86
|
-
let removed = false;
|
|
87
|
-
|
|
88
|
-
if (config.hooks.SessionStart) {
|
|
89
|
-
const before = config.hooks.SessionStart.length;
|
|
90
|
-
config.hooks.SessionStart = config.hooks.SessionStart.filter(
|
|
91
|
-
(entry) => !entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
92
|
-
);
|
|
93
|
-
if (config.hooks.SessionStart.length < before) removed = true;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (config.hooks.PreToolUse) {
|
|
97
|
-
const before = config.hooks.PreToolUse.length;
|
|
98
|
-
config.hooks.PreToolUse = config.hooks.PreToolUse.filter(
|
|
99
|
-
(entry) => !entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
100
|
-
);
|
|
101
|
-
if (config.hooks.PreToolUse.length < before) removed = true;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return removed;
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
factory: {
|
|
108
|
-
name: "Factory",
|
|
109
|
-
configPath: ".factory/settings.json",
|
|
110
|
-
distPath: "factory/leash.js",
|
|
111
|
-
setup: (config, leashPath) => {
|
|
112
|
-
config.hooks = config.hooks || {};
|
|
113
|
-
const hookCommand = { type: "command", command: `node ${leashPath}` };
|
|
114
|
-
|
|
115
|
-
// Check if already installed in either hook
|
|
116
|
-
const inSessionStart = config.hooks.SessionStart?.some((entry) =>
|
|
117
|
-
entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
118
|
-
);
|
|
119
|
-
const inPreToolUse = config.hooks.PreToolUse?.some((entry) =>
|
|
120
|
-
entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
121
|
-
);
|
|
122
|
-
if (inSessionStart && inPreToolUse) {
|
|
123
|
-
return { skipped: true };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Add SessionStart hook
|
|
127
|
-
if (!inSessionStart) {
|
|
128
|
-
config.hooks.SessionStart = config.hooks.SessionStart || [];
|
|
129
|
-
config.hooks.SessionStart.push({
|
|
130
|
-
hooks: [hookCommand],
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Add PreToolUse hook
|
|
135
|
-
if (!inPreToolUse) {
|
|
136
|
-
config.hooks.PreToolUse = config.hooks.PreToolUse || [];
|
|
137
|
-
config.hooks.PreToolUse.push({
|
|
138
|
-
matcher: "Execute|Write|Edit",
|
|
139
|
-
hooks: [hookCommand],
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return { skipped: false };
|
|
144
|
-
},
|
|
145
|
-
remove: (config) => {
|
|
146
|
-
if (!config.hooks) return false;
|
|
147
|
-
let removed = false;
|
|
148
|
-
|
|
149
|
-
if (config.hooks.SessionStart) {
|
|
150
|
-
const before = config.hooks.SessionStart.length;
|
|
151
|
-
config.hooks.SessionStart = config.hooks.SessionStart.filter(
|
|
152
|
-
(entry) => !entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
153
|
-
);
|
|
154
|
-
if (config.hooks.SessionStart.length < before) removed = true;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (config.hooks.PreToolUse) {
|
|
158
|
-
const before = config.hooks.PreToolUse.length;
|
|
159
|
-
config.hooks.PreToolUse = config.hooks.PreToolUse.filter(
|
|
160
|
-
(entry) => !entry.hooks?.some((h) => h.command?.includes("leash"))
|
|
161
|
-
);
|
|
162
|
-
if (config.hooks.PreToolUse.length < before) removed = true;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return removed;
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
export function readConfig(configPath) {
|
|
171
|
-
if (!existsSync(configPath)) {
|
|
172
|
-
return {};
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
176
|
-
} catch {
|
|
177
|
-
return {};
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function writeConfig(configPath, config) {
|
|
182
|
-
const dir = dirname(configPath);
|
|
183
|
-
if (!existsSync(dir)) {
|
|
184
|
-
mkdirSync(dir, { recursive: true });
|
|
185
|
-
}
|
|
186
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export function setupPlatform(platformKey, configPath, leashPath) {
|
|
190
|
-
const platform = PLATFORMS[platformKey];
|
|
191
|
-
if (!platform) {
|
|
192
|
-
return { error: `Unknown platform: ${platformKey}` };
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const config = readConfig(configPath);
|
|
196
|
-
const result = platform.setup(config, leashPath);
|
|
197
|
-
|
|
198
|
-
if (result.skipped) {
|
|
199
|
-
return { skipped: true, platform: platform.name };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
writeConfig(configPath, config);
|
|
203
|
-
return { success: true, platform: platform.name, configPath };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export function removePlatform(platformKey, configPath) {
|
|
207
|
-
const platform = PLATFORMS[platformKey];
|
|
208
|
-
if (!platform) {
|
|
209
|
-
return { error: `Unknown platform: ${platformKey}` };
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!existsSync(configPath)) {
|
|
213
|
-
return { notFound: true, platform: platform.name };
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const config = readConfig(configPath);
|
|
217
|
-
const removed = platform.remove(config);
|
|
218
|
-
|
|
219
|
-
if (!removed) {
|
|
220
|
-
return { notInstalled: true, platform: platform.name };
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
writeConfig(configPath, config);
|
|
224
|
-
return { success: true, platform: platform.name };
|
|
225
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from "fs";
|
|
2
|
-
import { dirname, join } from "path";
|
|
3
|
-
import { fileURLToPath } from "url";
|
|
4
|
-
function getVersion() {
|
|
5
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const candidates = [
|
|
7
|
-
join(__dirname, "..", "..", "package.json"),
|
|
8
|
-
join(__dirname, "..", "..", "..", "package.json")
|
|
9
|
-
];
|
|
10
|
-
for (const path of candidates) {
|
|
11
|
-
if (existsSync(path)) {
|
|
12
|
-
try {
|
|
13
|
-
const pkg = JSON.parse(readFileSync(path, "utf-8"));
|
|
14
|
-
if (pkg.name === "@melihmucuk/leash") {
|
|
15
|
-
return pkg.version;
|
|
16
|
-
}
|
|
17
|
-
} catch {
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return "0.0.0";
|
|
22
|
-
}
|
|
23
|
-
const CURRENT_VERSION = getVersion();
|
|
24
|
-
const NPM_REGISTRY_URL = "https://registry.npmjs.org/@melihmucuk/leash/latest";
|
|
25
|
-
async function checkForUpdates() {
|
|
26
|
-
try {
|
|
27
|
-
const response = await fetch(NPM_REGISTRY_URL);
|
|
28
|
-
if (!response.ok) {
|
|
29
|
-
return { hasUpdate: false, currentVersion: CURRENT_VERSION };
|
|
30
|
-
}
|
|
31
|
-
const data = await response.json();
|
|
32
|
-
return {
|
|
33
|
-
hasUpdate: data.version !== CURRENT_VERSION,
|
|
34
|
-
latestVersion: data.version,
|
|
35
|
-
currentVersion: CURRENT_VERSION
|
|
36
|
-
};
|
|
37
|
-
} catch {
|
|
38
|
-
return { hasUpdate: false, currentVersion: CURRENT_VERSION };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
export {
|
|
42
|
-
CURRENT_VERSION,
|
|
43
|
-
checkForUpdates
|
|
44
|
-
};
|