agentinel 1.0.0 → 1.0.2
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 +17 -10
- package/dist/asen.js +118 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,10 +77,10 @@ The AI reads this, realizes the package is fake or malicious, and intelligently
|
|
|
77
77
|
|
|
78
78
|
What about installs that never go through an agent? (e.g., You typing `npm install` manually).
|
|
79
79
|
|
|
80
|
-
Agentinel provides an opt-in **PATH shim**.
|
|
80
|
+
Agentinel provides an opt-in **PATH shim**. By default, running `npx asen init` installs this shim automatically.
|
|
81
81
|
|
|
82
82
|
```sh
|
|
83
|
-
npx asen init
|
|
83
|
+
npx asen init
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
This puts a tiny, fail-open wrapper script earlier in your `PATH`. When you type `npm install`, the shim checks the package first. If it's safe, the real `npm` command runs instantly.
|
|
@@ -153,28 +153,28 @@ Agentinel hard-blocks the install and returns an error payload to the agent. The
|
|
|
153
153
|
|
|
154
154
|
Here are all the commands you can run via `npx asen <command>`:
|
|
155
155
|
|
|
156
|
-
### `npx asen init [--shim]`
|
|
157
|
-
Wires up agent hooks and git hooks in the current repo.
|
|
156
|
+
### `npx asen init [--no-shim]`
|
|
157
|
+
Wires up agent hooks and git hooks in the current repo, and installs the global PATH shim for human terminal protection.
|
|
158
158
|
```bash
|
|
159
159
|
$ npx asen init
|
|
160
160
|
wrote .agentinel.json
|
|
161
161
|
registered the Claude Code PreToolUse hook in .claude/settings.json
|
|
162
162
|
installed the git pre-commit hook in .git/hooks
|
|
163
|
+
wrote shims for npm, npx, pnpm, yarn, bun in /Users/user/.agentinel/bin
|
|
164
|
+
added the shims to PATH in /Users/user/.zshrc
|
|
165
|
+
Mode is warn, so a risky package typed at the terminal will be reported, not blocked.
|
|
166
|
+
Open a new terminal, or run \`asen unshim\` to undo this.
|
|
163
167
|
|
|
164
168
|
agentinel is set up. New npm packages will be checked before they land.
|
|
165
169
|
Default mode is warn. Set "mode": "strict" in .agentinel.json to block instead.
|
|
166
170
|
```
|
|
167
171
|
|
|
168
|
-
When used with `--shim`, it wires up hooks
|
|
172
|
+
When used with `--no-shim`, it wires up hooks but skips installing the global PATH shim.
|
|
169
173
|
```bash
|
|
170
|
-
$ npx asen init --shim
|
|
174
|
+
$ npx asen init --no-shim
|
|
171
175
|
wrote .agentinel.json
|
|
172
176
|
registered the Claude Code PreToolUse hook in .claude/settings.json
|
|
173
177
|
installed the git pre-commit hook in .git/hooks
|
|
174
|
-
wrote shims for npm, npx, pnpm, yarn, bun in /Users/user/.agentinel/bin
|
|
175
|
-
added the shims to PATH in /Users/user/.zshrc
|
|
176
|
-
Mode is warn, so a risky package typed at the terminal will be reported, not blocked.
|
|
177
|
-
Open a new terminal, or run \`asen unshim\` to undo this.
|
|
178
178
|
|
|
179
179
|
agentinel is set up. New npm packages will be checked before they land.
|
|
180
180
|
Default mode is warn. Set "mode": "strict" in .agentinel.json to block instead.
|
|
@@ -208,6 +208,13 @@ $ npx asen mode strict
|
|
|
208
208
|
set mode to strict in .agentinel.json
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
+
### `npx asen uninstall`
|
|
212
|
+
Completely removes all Agentinel hooks from your repository config files (`.claude`, `.gemini`, `.github`, etc.) and removes global shims.
|
|
213
|
+
```bash
|
|
214
|
+
$ npx asen uninstall
|
|
215
|
+
agentinel has been completely uninstalled from this repository.
|
|
216
|
+
```
|
|
217
|
+
|
|
211
218
|
### `npx asen unshim`
|
|
212
219
|
Removes the global PATH shim.
|
|
213
220
|
```bash
|
package/dist/asen.js
CHANGED
|
@@ -1496,9 +1496,102 @@ function runMode(targetMode) {
|
|
|
1496
1496
|
return 0;
|
|
1497
1497
|
}
|
|
1498
1498
|
|
|
1499
|
-
// src/
|
|
1500
|
-
import { existsSync as existsSync6 } from "fs";
|
|
1499
|
+
// src/commands/uninstall.ts
|
|
1500
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
1501
1501
|
import { join as join6 } from "path";
|
|
1502
|
+
var HOOK_MARKER2 = "agentinel";
|
|
1503
|
+
var HOOK_SUBCOMMAND2 = "hook claude-code";
|
|
1504
|
+
function runUninstall() {
|
|
1505
|
+
const repoRoot = repoRootOrCwd();
|
|
1506
|
+
unwireClaudeCodeHook(repoRoot);
|
|
1507
|
+
unwireCodexHook(repoRoot);
|
|
1508
|
+
unwireCopilotHook(repoRoot);
|
|
1509
|
+
unwireGeminiHook(repoRoot);
|
|
1510
|
+
unwirePreCommitHook(repoRoot);
|
|
1511
|
+
removeShim();
|
|
1512
|
+
console.log("agentinel has been completely uninstalled from this repository.");
|
|
1513
|
+
return 0;
|
|
1514
|
+
}
|
|
1515
|
+
function unwireClaudeCodeHook(repoRoot) {
|
|
1516
|
+
const path = join6(repoRoot, ".claude", "settings.json");
|
|
1517
|
+
if (!existsSync6(path)) return;
|
|
1518
|
+
const file = readJson2(path);
|
|
1519
|
+
if (file === null) return;
|
|
1520
|
+
const hooks = asRecord3(file.hooks);
|
|
1521
|
+
if (!hooks || !Array.isArray(hooks.PreToolUse)) return;
|
|
1522
|
+
const preToolUse = hooks.PreToolUse;
|
|
1523
|
+
hooks.PreToolUse = preToolUse.filter((hook) => !JSON.stringify(hook).includes(HOOK_SUBCOMMAND2));
|
|
1524
|
+
if (hooks.PreToolUse.length === 0) {
|
|
1525
|
+
delete hooks.PreToolUse;
|
|
1526
|
+
}
|
|
1527
|
+
if (Object.keys(hooks).length === 0) {
|
|
1528
|
+
delete file.hooks;
|
|
1529
|
+
}
|
|
1530
|
+
writeJson2(path, file);
|
|
1531
|
+
console.log("removed Claude Code hook");
|
|
1532
|
+
}
|
|
1533
|
+
function unwireCodexHook(repoRoot) {
|
|
1534
|
+
const path = join6(repoRoot, ".codex", "hooks.json");
|
|
1535
|
+
if (!existsSync6(path)) return;
|
|
1536
|
+
const file = readJson2(path);
|
|
1537
|
+
if (file === null) return;
|
|
1538
|
+
const hooks = asRecord3(file.hooks);
|
|
1539
|
+
if (!hooks || !Array.isArray(hooks.PreToolUse)) return;
|
|
1540
|
+
const preToolUse = hooks.PreToolUse;
|
|
1541
|
+
hooks.PreToolUse = preToolUse.filter((hook) => !JSON.stringify(hook).includes("hook codex"));
|
|
1542
|
+
writeJson2(path, file);
|
|
1543
|
+
console.log("removed Codex hook");
|
|
1544
|
+
}
|
|
1545
|
+
function unwireCopilotHook(repoRoot) {
|
|
1546
|
+
const path = join6(repoRoot, ".github", "hooks", "agentinel.json");
|
|
1547
|
+
if (!existsSync6(path)) return;
|
|
1548
|
+
const file = readJson2(path);
|
|
1549
|
+
if (file === null) return;
|
|
1550
|
+
const hooks = asRecord3(file.hooks);
|
|
1551
|
+
if (!hooks || !Array.isArray(hooks.preToolUse)) return;
|
|
1552
|
+
const preToolUse = hooks.preToolUse;
|
|
1553
|
+
hooks.preToolUse = preToolUse.filter((hook) => !JSON.stringify(hook).includes("hook copilot"));
|
|
1554
|
+
writeJson2(path, file);
|
|
1555
|
+
console.log("removed Copilot hook");
|
|
1556
|
+
}
|
|
1557
|
+
function unwireGeminiHook(repoRoot) {
|
|
1558
|
+
const path = join6(repoRoot, ".gemini", "settings.json");
|
|
1559
|
+
if (!existsSync6(path)) return;
|
|
1560
|
+
const file = readJson2(path);
|
|
1561
|
+
if (file === null) return;
|
|
1562
|
+
const hooks = asRecord3(file.hooks);
|
|
1563
|
+
if (!hooks || !Array.isArray(hooks.BeforeTool)) return;
|
|
1564
|
+
const beforeTool = hooks.BeforeTool;
|
|
1565
|
+
hooks.BeforeTool = beforeTool.filter((hook) => !JSON.stringify(hook).includes("hook gemini"));
|
|
1566
|
+
writeJson2(path, file);
|
|
1567
|
+
console.log("removed Gemini hook");
|
|
1568
|
+
}
|
|
1569
|
+
function unwirePreCommitHook(repoRoot) {
|
|
1570
|
+
if (!existsSync6(join6(repoRoot, ".git"))) return;
|
|
1571
|
+
const path = join6(hooksDirectory(repoRoot), "pre-commit");
|
|
1572
|
+
if (!existsSync6(path)) return;
|
|
1573
|
+
const existing = readFileSync6(path, "utf8");
|
|
1574
|
+
if (!existing.includes(HOOK_MARKER2)) return;
|
|
1575
|
+
rmSync2(path);
|
|
1576
|
+
console.log("removed git pre-commit hook");
|
|
1577
|
+
}
|
|
1578
|
+
function readJson2(path) {
|
|
1579
|
+
try {
|
|
1580
|
+
return asRecord3(JSON.parse(readFileSync6(path, "utf8"))) ?? {};
|
|
1581
|
+
} catch {
|
|
1582
|
+
return null;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
function writeJson2(path, value) {
|
|
1586
|
+
writeFileSync4(path, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
1587
|
+
}
|
|
1588
|
+
function asRecord3(value) {
|
|
1589
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// src/hooks/claude-code.ts
|
|
1593
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1594
|
+
import { join as join7 } from "path";
|
|
1502
1595
|
|
|
1503
1596
|
// src/checks/package-guard/resolve.ts
|
|
1504
1597
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
@@ -1582,7 +1675,7 @@ function candidatesFor(command, repoRoot) {
|
|
|
1582
1675
|
}
|
|
1583
1676
|
function isLocalTool(repoRoot, name) {
|
|
1584
1677
|
const binary = name.includes("/") ? name.split("/").pop() : name;
|
|
1585
|
-
return
|
|
1678
|
+
return existsSync7(join7(repoRoot, "node_modules", ".bin", binary));
|
|
1586
1679
|
}
|
|
1587
1680
|
function warn(verdicts) {
|
|
1588
1681
|
const summary = plainSummary(verdicts);
|
|
@@ -1796,25 +1889,41 @@ async function runPreCommitHook() {
|
|
|
1796
1889
|
}
|
|
1797
1890
|
|
|
1798
1891
|
// bin/asen.ts
|
|
1892
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
1893
|
+
import { dirname as dirname2, join as join8 } from "path";
|
|
1894
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1895
|
+
function getVersion() {
|
|
1896
|
+
try {
|
|
1897
|
+
const file = fileURLToPath2(import.meta.url);
|
|
1898
|
+
const pkgPath = join8(dirname2(file), "..", "package.json");
|
|
1899
|
+
const pkg = JSON.parse(readFileSync7(pkgPath, "utf8"));
|
|
1900
|
+
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
1901
|
+
} catch {
|
|
1902
|
+
return "unknown";
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1799
1905
|
var USAGE = `asen, a guard for AI coding agent workflows
|
|
1800
1906
|
|
|
1801
|
-
asen init [--shim]
|
|
1907
|
+
asen init [--no-shim] set up the hooks and config in this repo
|
|
1802
1908
|
asen check [pkg...] check staged dependencies, or specific packages
|
|
1803
1909
|
asen allow <pkg> --reason "..." allowlist a flagged package, with a logged reason
|
|
1804
1910
|
asen mode <warn|strict> switch Agentinel's operating mode
|
|
1911
|
+
asen uninstall remove all agent hooks from this repository
|
|
1805
1912
|
asen unshim remove the PATH shims that --shim installed
|
|
1806
1913
|
`;
|
|
1807
1914
|
async function main(argv2) {
|
|
1808
1915
|
const [command, ...rest] = argv2;
|
|
1809
1916
|
switch (command) {
|
|
1810
1917
|
case "init":
|
|
1811
|
-
return runInit({ shim: rest.includes("--shim") });
|
|
1918
|
+
return runInit({ shim: !rest.includes("--no-shim") });
|
|
1812
1919
|
case "check":
|
|
1813
1920
|
return runCheck(positionals(rest));
|
|
1814
1921
|
case "allow":
|
|
1815
1922
|
return runAllow(positionals(rest)[0], readFlag(rest, "--reason"));
|
|
1816
1923
|
case "mode":
|
|
1817
1924
|
return runMode(positionals(rest)[0]);
|
|
1925
|
+
case "uninstall":
|
|
1926
|
+
return runUninstall();
|
|
1818
1927
|
case "unshim":
|
|
1819
1928
|
return removeShim();
|
|
1820
1929
|
// Not documented in the usage text on purpose. These are what the installed hooks call.
|
|
@@ -1823,6 +1932,10 @@ async function main(argv2) {
|
|
|
1823
1932
|
// What the PATH shims call, with the whole command line as one argument.
|
|
1824
1933
|
case "check-command":
|
|
1825
1934
|
return runCheckCommand(rest[0]);
|
|
1935
|
+
case "--version":
|
|
1936
|
+
case "-v":
|
|
1937
|
+
console.log(`agentinel v${getVersion()}`);
|
|
1938
|
+
return 0;
|
|
1826
1939
|
case "--help":
|
|
1827
1940
|
case "-h":
|
|
1828
1941
|
case void 0:
|