@melihmucuk/leash 1.0.10 → 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 CHANGED
@@ -29,6 +29,8 @@ Links:
29
29
 
30
30
  ## Quick Start
31
31
 
32
+ **All platforms except Pi:**
33
+
32
34
  ```bash
33
35
  # Install leash globally
34
36
  npm install -g @melihmucuk/leash
@@ -43,12 +45,17 @@ leash --remove <platform>
43
45
  leash --update
44
46
  ```
45
47
 
46
- | Platform | Command |
47
- | --------------- | --------------------------- |
48
- | OpenCode | `leash --setup opencode` |
49
- | Pi Coding Agent | `leash --setup pi` |
50
- | Claude Code | `leash --setup claude-code` |
51
- | Factory Droid | `leash --setup factory` |
48
+ | Platform | Command |
49
+ | ------------- | --------------------------- |
50
+ | OpenCode | `leash --setup opencode` |
51
+ | Claude Code | `leash --setup claude-code` |
52
+ | Factory Droid | `leash --setup factory` |
53
+
54
+ **Pi Coding Agent:**
55
+
56
+ ```bash
57
+ pi install npm:@melihmucuk/leash
58
+ ```
52
59
 
53
60
  Restart your agent. Done!
54
61
 
package/dist/cli/leash.js CHANGED
@@ -1384,44 +1384,11 @@ function applyEdits(text, edits) {
1384
1384
  }
1385
1385
 
1386
1386
  // packages/cli/lib.ts
1387
- var PLATFORMS = {
1388
- opencode: {
1389
- name: "OpenCode",
1390
- configPaths: [
1391
- ".config/opencode/opencode.jsonc",
1392
- ".config/opencode/opencode.json"
1393
- ],
1394
- distPath: "opencode/leash.js",
1395
- remove: (config) => {
1396
- if (!config.plugin) return false;
1397
- const before = config.plugin.length;
1398
- config.plugin = config.plugin.filter((p) => !p.includes("leash"));
1399
- return config.plugin.length < before;
1400
- }
1401
- },
1402
- pi: {
1403
- name: "Pi",
1404
- configPath: ".pi/agent/settings.json",
1405
- distPath: "pi/leash.js",
1406
- setup: (config, leashPath) => {
1407
- config.extensions = config.extensions || [];
1408
- if (config.extensions.some((e) => e.includes("leash"))) {
1409
- return { skipped: true };
1410
- }
1411
- config.extensions.push(leashPath);
1412
- return { skipped: false };
1413
- },
1414
- remove: (config) => {
1415
- if (!config.extensions) return false;
1416
- const before = config.extensions.length;
1417
- config.extensions = config.extensions.filter((e) => !e.includes("leash"));
1418
- return config.extensions.length < before;
1419
- }
1420
- },
1421
- "claude-code": {
1422
- name: "Claude Code",
1423
- configPath: ".claude/settings.json",
1424
- distPath: "claude-code/leash.js",
1387
+ function createHookPlatform(opts) {
1388
+ return {
1389
+ name: opts.name,
1390
+ configPath: opts.configPath,
1391
+ distPath: opts.distPath,
1425
1392
  setup: (config, leashPath) => {
1426
1393
  config.hooks = config.hooks || {};
1427
1394
  const hookCommand = { type: "command", command: `node ${leashPath}` };
@@ -1441,7 +1408,7 @@ var PLATFORMS = {
1441
1408
  if (!inPreToolUse) {
1442
1409
  config.hooks.PreToolUse = config.hooks.PreToolUse || [];
1443
1410
  config.hooks.PreToolUse.push({
1444
- matcher: "Bash|Write|Edit",
1411
+ matcher: opts.preToolUseMatcher,
1445
1412
  hooks: [hookCommand]
1446
1413
  });
1447
1414
  }
@@ -1466,56 +1433,50 @@ var PLATFORMS = {
1466
1433
  }
1467
1434
  return removed;
1468
1435
  }
1436
+ };
1437
+ }
1438
+ var PLATFORMS = {
1439
+ opencode: {
1440
+ name: "OpenCode",
1441
+ configPaths: [
1442
+ ".config/opencode/opencode.jsonc",
1443
+ ".config/opencode/opencode.json"
1444
+ ],
1445
+ distPath: "opencode/leash.js"
1446
+ // opencode config is JSONC (supports comments). Generic readConfig/writeConfig use JSON.stringify
1447
+ // which strips comments. setupOpenCode/removeOpenCode handle this via jsonc-parser instead.
1469
1448
  },
1470
- factory: {
1471
- name: "Factory",
1472
- configPath: ".factory/settings.json",
1473
- distPath: "factory/leash.js",
1449
+ pi: {
1450
+ name: "Pi",
1451
+ configPath: ".pi/agent/settings.json",
1452
+ distPath: "pi/leash.js",
1474
1453
  setup: (config, leashPath) => {
1475
- config.hooks = config.hooks || {};
1476
- const hookCommand = { type: "command", command: `node ${leashPath}` };
1477
- const inSessionStart = config.hooks.SessionStart?.some(
1478
- (entry) => entry.hooks?.some((h) => h.command?.includes("leash"))
1479
- );
1480
- const inPreToolUse = config.hooks.PreToolUse?.some(
1481
- (entry) => entry.hooks?.some((h) => h.command?.includes("leash"))
1482
- );
1483
- if (inSessionStart && inPreToolUse) {
1454
+ config.extensions = config.extensions || [];
1455
+ if (config.extensions.some((e) => e.includes("leash"))) {
1484
1456
  return { skipped: true };
1485
1457
  }
1486
- if (!inSessionStart) {
1487
- config.hooks.SessionStart = config.hooks.SessionStart || [];
1488
- config.hooks.SessionStart.push({ hooks: [hookCommand] });
1489
- }
1490
- if (!inPreToolUse) {
1491
- config.hooks.PreToolUse = config.hooks.PreToolUse || [];
1492
- config.hooks.PreToolUse.push({
1493
- matcher: "Execute|Write|Edit",
1494
- hooks: [hookCommand]
1495
- });
1496
- }
1458
+ config.extensions.push(leashPath);
1497
1459
  return { skipped: false };
1498
1460
  },
1499
1461
  remove: (config) => {
1500
- if (!config.hooks) return false;
1501
- let removed = false;
1502
- if (config.hooks.SessionStart) {
1503
- const before = config.hooks.SessionStart.length;
1504
- config.hooks.SessionStart = config.hooks.SessionStart.filter(
1505
- (entry) => !entry.hooks?.some((h) => h.command?.includes("leash"))
1506
- );
1507
- if (config.hooks.SessionStart.length < before) removed = true;
1508
- }
1509
- if (config.hooks.PreToolUse) {
1510
- const before = config.hooks.PreToolUse.length;
1511
- config.hooks.PreToolUse = config.hooks.PreToolUse.filter(
1512
- (entry) => !entry.hooks?.some((h) => h.command?.includes("leash"))
1513
- );
1514
- if (config.hooks.PreToolUse.length < before) removed = true;
1515
- }
1516
- return removed;
1462
+ if (!config.extensions) return false;
1463
+ const before = config.extensions.length;
1464
+ config.extensions = config.extensions.filter((e) => !e.includes("leash"));
1465
+ return config.extensions.length < before;
1517
1466
  }
1518
- }
1467
+ },
1468
+ "claude-code": createHookPlatform({
1469
+ name: "Claude Code",
1470
+ configPath: ".claude/settings.json",
1471
+ distPath: "claude-code/leash.js",
1472
+ preToolUseMatcher: "Bash|Write|Edit"
1473
+ }),
1474
+ factory: createHookPlatform({
1475
+ name: "Factory",
1476
+ configPath: ".factory/settings.json",
1477
+ distPath: "factory/leash.js",
1478
+ preToolUseMatcher: "Execute|Write|Edit"
1479
+ })
1519
1480
  };
1520
1481
  function readConfig(configPath) {
1521
1482
  if (!existsSync(configPath)) {
@@ -1597,6 +1558,9 @@ function setupPlatform(platformKey, configPath, leashPath) {
1597
1558
  return setupOpenCode(configPath, leashPath);
1598
1559
  }
1599
1560
  const config = readConfig(configPath);
1561
+ if (!platform2.setup) {
1562
+ return { error: `Platform ${platformKey} has no setup handler` };
1563
+ }
1600
1564
  const result = platform2.setup(config, leashPath);
1601
1565
  if (result.skipped) {
1602
1566
  return { skipped: true, platform: platform2.name };
@@ -1616,6 +1580,9 @@ function removePlatform(platformKey, configPath) {
1616
1580
  return { notFound: true, platform: platform2.name };
1617
1581
  }
1618
1582
  const config = readConfig(configPath);
1583
+ if (!platform2.remove) {
1584
+ return { error: `Platform ${platformKey} has no remove handler` };
1585
+ }
1619
1586
  const removed = platform2.remove(config);
1620
1587
  if (!removed) {
1621
1588
  return { notInstalled: true, platform: platform2.name };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@melihmucuk/leash",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "type": "module",
5
5
  "description": "Security guardrails for AI coding agents",
6
6
  "bin": {
7
- "leash": "./dist/cli/leash.js"
7
+ "leash": "dist/cli/leash.js"
8
8
  },
9
9
  "files": [
10
10
  "dist/"
@@ -25,15 +25,21 @@
25
25
  "plugin",
26
26
  "hooks",
27
27
  "file-system",
28
- "protection"
28
+ "protection",
29
+ "pi-package"
29
30
  ],
31
+ "pi": {
32
+ "extensions": [
33
+ "./dist/pi/leash.js"
34
+ ]
35
+ },
30
36
  "homepage": "https://github.com/melihmucuk/leash",
31
37
  "bugs": {
32
38
  "url": "https://github.com/melihmucuk/leash/issues"
33
39
  },
34
40
  "repository": {
35
41
  "type": "git",
36
- "url": "https://github.com/melihmucuk/leash.git"
42
+ "url": "git+https://github.com/melihmucuk/leash.git"
37
43
  },
38
44
  "scripts": {
39
45
  "test": "npm run build:core && npm run build:cli-lib && node --test 'packages/core/test/*.test.js' 'packages/cli/test/*.test.js'",
@@ -47,6 +53,9 @@
47
53
  "build:claude-code": "esbuild packages/claude-code/leash.ts --bundle --outfile=dist/claude-code/leash.js --platform=node --format=esm",
48
54
  "build:factory": "esbuild packages/factory/leash.ts --bundle --outfile=dist/factory/leash.js --platform=node --format=esm"
49
55
  },
56
+ "peerDependencies": {
57
+ "@mariozechner/pi-coding-agent": "*"
58
+ },
50
59
  "devDependencies": {
51
60
  "@mariozechner/pi-coding-agent": "^0.37.8",
52
61
  "@opencode-ai/plugin": "^1.1.4",