@superbfowle/bash-history-mcp-test 0.1.0
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/CLAUDE.md +106 -0
- package/README.md +201 -0
- package/bun.lock +208 -0
- package/cli.ts +12 -0
- package/index.ts +95 -0
- package/opencode.ts +58 -0
- package/package.json +17 -0
- package/server.ts +244 -0
- package/tsconfig.json +29 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
|
|
2
|
+
Default to using Bun instead of Node.js.
|
|
3
|
+
|
|
4
|
+
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
|
|
5
|
+
- Use `bun test` instead of `jest` or `vitest`
|
|
6
|
+
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
|
|
7
|
+
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
|
|
8
|
+
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
|
|
9
|
+
- Bun automatically loads .env, so don't use dotenv.
|
|
10
|
+
|
|
11
|
+
## APIs
|
|
12
|
+
|
|
13
|
+
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
|
|
14
|
+
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
|
|
15
|
+
- `Bun.redis` for Redis. Don't use `ioredis`.
|
|
16
|
+
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
|
|
17
|
+
- `WebSocket` is built-in. Don't use `ws`.
|
|
18
|
+
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
|
|
19
|
+
- Bun.$`ls` instead of execa.
|
|
20
|
+
|
|
21
|
+
## Testing
|
|
22
|
+
|
|
23
|
+
Use `bun test` to run tests.
|
|
24
|
+
|
|
25
|
+
```ts#index.test.ts
|
|
26
|
+
import { test, expect } from "bun:test";
|
|
27
|
+
|
|
28
|
+
test("hello world", () => {
|
|
29
|
+
expect(1).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Frontend
|
|
34
|
+
|
|
35
|
+
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
|
|
36
|
+
|
|
37
|
+
Server:
|
|
38
|
+
|
|
39
|
+
```ts#index.ts
|
|
40
|
+
import index from "./index.html"
|
|
41
|
+
|
|
42
|
+
Bun.serve({
|
|
43
|
+
routes: {
|
|
44
|
+
"/": index,
|
|
45
|
+
"/api/users/:id": {
|
|
46
|
+
GET: (req) => {
|
|
47
|
+
return new Response(JSON.stringify({ id: req.params.id }));
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
// optional websocket support
|
|
52
|
+
websocket: {
|
|
53
|
+
open: (ws) => {
|
|
54
|
+
ws.send("Hello, world!");
|
|
55
|
+
},
|
|
56
|
+
message: (ws, message) => {
|
|
57
|
+
ws.send(message);
|
|
58
|
+
},
|
|
59
|
+
close: (ws) => {
|
|
60
|
+
// handle close
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
development: {
|
|
64
|
+
hmr: true,
|
|
65
|
+
console: true,
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
|
|
71
|
+
|
|
72
|
+
```html#index.html
|
|
73
|
+
<html>
|
|
74
|
+
<body>
|
|
75
|
+
<h1>Hello, world!</h1>
|
|
76
|
+
<script type="module" src="./frontend.tsx"></script>
|
|
77
|
+
</body>
|
|
78
|
+
</html>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
With the following `frontend.tsx`:
|
|
82
|
+
|
|
83
|
+
```tsx#frontend.tsx
|
|
84
|
+
import React from "react";
|
|
85
|
+
|
|
86
|
+
// import .css files directly and it works
|
|
87
|
+
import './index.css';
|
|
88
|
+
|
|
89
|
+
import { createRoot } from "react-dom/client";
|
|
90
|
+
|
|
91
|
+
const root = createRoot(document.body);
|
|
92
|
+
|
|
93
|
+
export default function Frontend() {
|
|
94
|
+
return <h1>Hello, world!</h1>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
root.render(<Frontend />);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then, run index.ts
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
bun --hot ./index.ts
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.
|
package/README.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Atuin Integration for Claude Code
|
|
2
|
+
|
|
3
|
+
Bidirectional bash history integration between Claude Code and [atuin](https://github.com/atuinsh/atuin).
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
- Claude Code runs bash commands but they don't appear in your shell history
|
|
7
|
+
- Claude Code can't learn from your command patterns
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### Write: Hook
|
|
12
|
+
**Claude Code hook** → writes commands to atuin after Claude executes each bash command
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Post-bash-execution hook calls:
|
|
16
|
+
id=$(atuin history start "$COMMAND")
|
|
17
|
+
atuin history end --exit "$EXIT_CODE" --duration 0 "$id"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Read: MCP Server
|
|
21
|
+
**MCP server** → Claude can query your atuin history
|
|
22
|
+
|
|
23
|
+
Tools:
|
|
24
|
+
- `search_history(query, limit?)` - Find commands matching a pattern
|
|
25
|
+
- `get_recent_history(limit?)` - Get recent commands with timestamps and exit codes
|
|
26
|
+
|
|
27
|
+
## Benefits
|
|
28
|
+
- **Persistent history**: Rerun commands Claude executed from your terminal
|
|
29
|
+
- **Context awareness**: Claude can learn from your command patterns and workflow
|
|
30
|
+
- **Rich metadata**: Timestamps, working directory, exit codes, and duration
|
|
31
|
+
- **Cross-machine sync**: History syncs across machines (if atuin sync is enabled)
|
|
32
|
+
|
|
33
|
+
## Setup
|
|
34
|
+
|
|
35
|
+
### Prerequisites
|
|
36
|
+
- [atuin](https://github.com/atuinsh/atuin) installed and configured
|
|
37
|
+
- [Bun](https://bun.sh) installed
|
|
38
|
+
|
|
39
|
+
### Write Hook Installation
|
|
40
|
+
|
|
41
|
+
**Note:** If you've previously installed this package and are updating to a new version, clear Bun's cache first:
|
|
42
|
+
```bash
|
|
43
|
+
bun pm cache rm
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Step 1: Locate your settings file**
|
|
47
|
+
|
|
48
|
+
Claude Code settings are in `~/.claude/settings.json`. Create it if it doesn't exist:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mkdir -p ~/.claude
|
|
52
|
+
touch ~/.claude/settings.json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Step 2: Add the hook configuration**
|
|
56
|
+
|
|
57
|
+
Edit `~/.claude/settings.json` and add:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"hooks": {
|
|
62
|
+
"PostToolUse": [
|
|
63
|
+
{
|
|
64
|
+
"matcher": "Bash",
|
|
65
|
+
"hooks": [
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "bunx github:nitsanavni/bash-history-mcp hook"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**If you already have hooks configured**, merge with your existing configuration:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"hooks": {
|
|
82
|
+
"PostToolUse": [
|
|
83
|
+
{
|
|
84
|
+
"matcher": "Bash",
|
|
85
|
+
"hooks": [
|
|
86
|
+
{
|
|
87
|
+
"type": "command",
|
|
88
|
+
"command": "bunx github:nitsanavni/bash-history-mcp hook"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
// ... your other PostToolUse hooks
|
|
93
|
+
]
|
|
94
|
+
// ... your other hook types (PreToolUse, etc.)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Step 3: Restart Claude Code**
|
|
100
|
+
|
|
101
|
+
The hook will be active in your next Claude Code session.
|
|
102
|
+
|
|
103
|
+
**Step 4: Verify it's working**
|
|
104
|
+
|
|
105
|
+
After Claude runs some bash commands:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
atuin history last
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
You should see the commands Claude executed.
|
|
112
|
+
|
|
113
|
+
### How It Works
|
|
114
|
+
|
|
115
|
+
After each bash command Claude executes:
|
|
116
|
+
1. Hook receives JSON with command and exit code via stdin
|
|
117
|
+
2. Calls `atuin history start "$COMMAND"` to get an entry ID
|
|
118
|
+
3. Calls `atuin history end --exit $EXIT --duration 0 $ID`
|
|
119
|
+
4. Fails silently if atuin is unavailable
|
|
120
|
+
|
|
121
|
+
### Troubleshooting
|
|
122
|
+
|
|
123
|
+
**Hook not running?**
|
|
124
|
+
```bash
|
|
125
|
+
# Check if hook is registered
|
|
126
|
+
claude --debug
|
|
127
|
+
# Run a command in Claude and look for hook execution logs
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Commands not appearing in atuin?**
|
|
131
|
+
```bash
|
|
132
|
+
# Test atuin manually
|
|
133
|
+
atuin history start "test command"
|
|
134
|
+
atuin history last
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### MCP Server Installation
|
|
138
|
+
|
|
139
|
+
**Note:** If you've previously installed this package and are updating to a new version, clear Bun's cache first:
|
|
140
|
+
```bash
|
|
141
|
+
bun pm cache rm
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Configure Claude Code to use the MCP server:**
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
claude mcp add -s user bash-history bunx -- github:nitsanavni/bash-history-mcp mcp
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or manually add to `~/.claude/settings.json`:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"mcpServers": {
|
|
155
|
+
"bash-history": {
|
|
156
|
+
"command": "bunx",
|
|
157
|
+
"args": ["github:nitsanavni/bash-history-mcp", "mcp"]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Available Tools:**
|
|
164
|
+
|
|
165
|
+
- `search_history(query, limit?)` - Search for commands matching a pattern
|
|
166
|
+
```
|
|
167
|
+
Example: search_history("git commit", 5)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- `get_recent_history(limit?)` - Get recent commands
|
|
171
|
+
```
|
|
172
|
+
Example: get_recent_history(10)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### OpenCode Plugin Installation
|
|
176
|
+
|
|
177
|
+
**Note:** If you've previously installed this package and are updating to a new version, clear Bun's cache first:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
bun pm cache rm
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Add to your opencode config:**
|
|
184
|
+
|
|
185
|
+
Edit your `opencode.json` (either in `~/.config/opencode/` or project root) and add:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"$schema": "https://opencode.ai/config.json",
|
|
190
|
+
"plugin": ["bash-history-mcp"]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The plugin will automatically log all bash commands executed by opencode to your atuin history.
|
|
195
|
+
|
|
196
|
+
## Implementation Status
|
|
197
|
+
|
|
198
|
+
1. ✅ Write hook with atuin integration
|
|
199
|
+
2. ✅ Test hook integration
|
|
200
|
+
3. ✅ MCP server with read-only atuin access
|
|
201
|
+
4. ✅ OpenCode plugin
|
package/bun.lock
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "bash-history-mcp",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@modelcontextprotocol/sdk": "^1.19.1",
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@types/bun": "latest",
|
|
11
|
+
},
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"typescript": "^5",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
"packages": {
|
|
18
|
+
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.19.1", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-3Y2h3MZKjec1eAqSTBclATlX+AbC6n1LgfVzRMJLt3v6w0RCYgwLrjbxPDbhsYHt6Wdqc/aCceNJYgj448ELQQ=="],
|
|
19
|
+
|
|
20
|
+
"@types/bun": ["@types/bun@1.2.23", "", { "dependencies": { "bun-types": "1.2.23" } }, "sha512-le8ueOY5b6VKYf19xT3McVbXqLqmxzPXHsQT/q9JHgikJ2X22wyTW3g3ohz2ZMnp7dod6aduIiq8A14Xyimm0A=="],
|
|
21
|
+
|
|
22
|
+
"@types/node": ["@types/node@24.6.2", "", { "dependencies": { "undici-types": "~7.13.0" } }, "sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang=="],
|
|
23
|
+
|
|
24
|
+
"@types/react": ["@types/react@19.2.0", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-1LOH8xovvsKsCBq1wnT4ntDUdCJKmnEakhsuoUSy6ExlHCkGP2hqnatagYTgFk6oeL0VU31u7SNjunPN+GchtA=="],
|
|
25
|
+
|
|
26
|
+
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
|
27
|
+
|
|
28
|
+
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
|
29
|
+
|
|
30
|
+
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
|
|
31
|
+
|
|
32
|
+
"bun-types": ["bun-types@1.2.23", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-R9f0hKAZXgFU3mlrA0YpE/fiDvwV0FT9rORApt2aQVWSuJDzZOyB5QLc0N/4HF57CS8IXJ6+L5E4W1bW6NS2Aw=="],
|
|
33
|
+
|
|
34
|
+
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
|
35
|
+
|
|
36
|
+
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
|
37
|
+
|
|
38
|
+
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
|
39
|
+
|
|
40
|
+
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
|
|
41
|
+
|
|
42
|
+
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
|
43
|
+
|
|
44
|
+
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
|
45
|
+
|
|
46
|
+
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
|
47
|
+
|
|
48
|
+
"cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
|
|
49
|
+
|
|
50
|
+
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
|
51
|
+
|
|
52
|
+
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
|
53
|
+
|
|
54
|
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
|
55
|
+
|
|
56
|
+
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
|
57
|
+
|
|
58
|
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
|
59
|
+
|
|
60
|
+
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
|
61
|
+
|
|
62
|
+
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
|
63
|
+
|
|
64
|
+
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
|
65
|
+
|
|
66
|
+
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
|
67
|
+
|
|
68
|
+
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
|
69
|
+
|
|
70
|
+
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
|
71
|
+
|
|
72
|
+
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
|
73
|
+
|
|
74
|
+
"eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
|
|
75
|
+
|
|
76
|
+
"eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
|
|
77
|
+
|
|
78
|
+
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
|
|
79
|
+
|
|
80
|
+
"express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="],
|
|
81
|
+
|
|
82
|
+
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
83
|
+
|
|
84
|
+
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
|
85
|
+
|
|
86
|
+
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
|
87
|
+
|
|
88
|
+
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
|
89
|
+
|
|
90
|
+
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
|
91
|
+
|
|
92
|
+
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
|
93
|
+
|
|
94
|
+
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
|
95
|
+
|
|
96
|
+
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
|
97
|
+
|
|
98
|
+
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
|
99
|
+
|
|
100
|
+
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
|
101
|
+
|
|
102
|
+
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
|
103
|
+
|
|
104
|
+
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
|
105
|
+
|
|
106
|
+
"iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="],
|
|
107
|
+
|
|
108
|
+
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
|
109
|
+
|
|
110
|
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
|
111
|
+
|
|
112
|
+
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
|
113
|
+
|
|
114
|
+
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
|
115
|
+
|
|
116
|
+
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
|
117
|
+
|
|
118
|
+
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
|
119
|
+
|
|
120
|
+
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
|
121
|
+
|
|
122
|
+
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
|
123
|
+
|
|
124
|
+
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
|
125
|
+
|
|
126
|
+
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
|
127
|
+
|
|
128
|
+
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
129
|
+
|
|
130
|
+
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
|
131
|
+
|
|
132
|
+
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
|
133
|
+
|
|
134
|
+
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
|
135
|
+
|
|
136
|
+
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
|
137
|
+
|
|
138
|
+
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
|
139
|
+
|
|
140
|
+
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
|
141
|
+
|
|
142
|
+
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
|
143
|
+
|
|
144
|
+
"path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
|
|
145
|
+
|
|
146
|
+
"pkce-challenge": ["pkce-challenge@5.0.0", "", {}, "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="],
|
|
147
|
+
|
|
148
|
+
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
|
149
|
+
|
|
150
|
+
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
|
151
|
+
|
|
152
|
+
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
|
153
|
+
|
|
154
|
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
|
155
|
+
|
|
156
|
+
"raw-body": ["raw-body@3.0.1", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.7.0", "unpipe": "1.0.0" } }, "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA=="],
|
|
157
|
+
|
|
158
|
+
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
|
159
|
+
|
|
160
|
+
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
|
161
|
+
|
|
162
|
+
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
|
163
|
+
|
|
164
|
+
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
|
|
165
|
+
|
|
166
|
+
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
|
|
167
|
+
|
|
168
|
+
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
|
169
|
+
|
|
170
|
+
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
|
171
|
+
|
|
172
|
+
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
|
173
|
+
|
|
174
|
+
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
|
175
|
+
|
|
176
|
+
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
|
177
|
+
|
|
178
|
+
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
|
179
|
+
|
|
180
|
+
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
|
181
|
+
|
|
182
|
+
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
|
183
|
+
|
|
184
|
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
|
185
|
+
|
|
186
|
+
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
|
187
|
+
|
|
188
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
189
|
+
|
|
190
|
+
"undici-types": ["undici-types@7.13.0", "", {}, "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ=="],
|
|
191
|
+
|
|
192
|
+
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
|
193
|
+
|
|
194
|
+
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
|
195
|
+
|
|
196
|
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
|
197
|
+
|
|
198
|
+
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
|
199
|
+
|
|
200
|
+
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
|
201
|
+
|
|
202
|
+
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
|
203
|
+
|
|
204
|
+
"zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="],
|
|
205
|
+
|
|
206
|
+
"body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
|
207
|
+
}
|
|
208
|
+
}
|
package/cli.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
const subcommand = process.argv[2];
|
|
4
|
+
|
|
5
|
+
if (subcommand === "hook") {
|
|
6
|
+
await import("./index.ts");
|
|
7
|
+
} else if (subcommand === "mcp") {
|
|
8
|
+
await import("./server.ts");
|
|
9
|
+
} else {
|
|
10
|
+
console.error(`Usage: bash-history-mcp <hook|mcp>`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
package/index.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Claude Code PostToolUse hook for atuin integration
|
|
5
|
+
* Adds bash commands to atuin history
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { realpath } from "node:fs/promises";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
|
|
12
|
+
export { OpencodeBashHistoryPlugin } from "./opencode.ts";
|
|
13
|
+
|
|
14
|
+
interface ToolInput {
|
|
15
|
+
command: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface HookInput {
|
|
21
|
+
tool_name: string;
|
|
22
|
+
tool_input: ToolInput;
|
|
23
|
+
tool_response?: {
|
|
24
|
+
exit_code?: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function main() {
|
|
29
|
+
try {
|
|
30
|
+
// Read JSON from stdin
|
|
31
|
+
const input = await Bun.stdin.text();
|
|
32
|
+
const data: HookInput = JSON.parse(input);
|
|
33
|
+
|
|
34
|
+
// Only process Bash tool calls
|
|
35
|
+
if (data.tool_name !== "Bash") {
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const command = data.tool_input.command;
|
|
40
|
+
const exitCode = data.tool_response?.exit_code ?? 0;
|
|
41
|
+
|
|
42
|
+
// Step 1: Start the command to get an ID
|
|
43
|
+
const startProc = Bun.spawn(["atuin", "history", "start", command], {
|
|
44
|
+
stdout: "pipe",
|
|
45
|
+
stderr: "pipe",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const startExitCode = await startProc.exited;
|
|
49
|
+
if (startExitCode !== 0) {
|
|
50
|
+
const stderr = await Bun.readableStreamToText(startProc.stderr);
|
|
51
|
+
console.error(`Failed to start atuin history entry: ${stderr}`);
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const id = (await Bun.readableStreamToText(startProc.stdout)).trim();
|
|
56
|
+
|
|
57
|
+
// Step 2: End the command with the exit code
|
|
58
|
+
const endProc = Bun.spawn(
|
|
59
|
+
["atuin", "history", "end", "--exit", String(exitCode), "--duration", "0", id],
|
|
60
|
+
{
|
|
61
|
+
stderr: "pipe",
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const endExitCode = await endProc.exited;
|
|
66
|
+
if (endExitCode !== 0) {
|
|
67
|
+
const stderr = await Bun.readableStreamToText(endProc.stderr);
|
|
68
|
+
console.error(`Failed to end atuin history entry: ${stderr}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
process.exit(0);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error("Hook error:", error);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function runIfMain(): Promise<void> {
|
|
79
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
80
|
+
const __dirname = dirname(__filename);
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const resolvedMainPath = await realpath(process.argv[1]);
|
|
84
|
+
|
|
85
|
+
// Early guard return if not being run as main module
|
|
86
|
+
if (resolvedMainPath !== __filename) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Only call main if we are the main module
|
|
91
|
+
await main();
|
|
92
|
+
} catch {}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
runIfMain();
|
package/opencode.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
|
|
3
|
+
export const OpencodeBashHistoryPlugin: Plugin = async ({ $ }) => {
|
|
4
|
+
return {
|
|
5
|
+
"tool.execute.after": async (input, output) => {
|
|
6
|
+
if (input.tool !== "bash") {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const command = output.metadata?.args?.command;
|
|
12
|
+
if (!command || typeof command !== "string") {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const exitCode = output.metadata?.exitCode ?? 0;
|
|
17
|
+
|
|
18
|
+
const startProc = Bun.spawn(["atuin", "history", "start", command], {
|
|
19
|
+
stdout: "pipe",
|
|
20
|
+
stderr: "pipe",
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const startExitCode = await startProc.exited;
|
|
24
|
+
if (startExitCode !== 0) {
|
|
25
|
+
const stderr = await Bun.readableStreamToText(startProc.stderr);
|
|
26
|
+
await $.console.error(`Failed to start atuin history entry: ${stderr}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const id = (await Bun.readableStreamToText(startProc.stdout)).trim();
|
|
31
|
+
|
|
32
|
+
const endProc = Bun.spawn(
|
|
33
|
+
[
|
|
34
|
+
"atuin",
|
|
35
|
+
"history",
|
|
36
|
+
"end",
|
|
37
|
+
"--exit",
|
|
38
|
+
String(exitCode),
|
|
39
|
+
"--duration",
|
|
40
|
+
"0",
|
|
41
|
+
id,
|
|
42
|
+
],
|
|
43
|
+
{
|
|
44
|
+
stderr: "pipe",
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const endExitCode = await endProc.exited;
|
|
49
|
+
if (endExitCode !== 0) {
|
|
50
|
+
const stderr = await Bun.readableStreamToText(endProc.stderr);
|
|
51
|
+
await $.console.error(`Failed to end atuin history entry: ${stderr}`);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
await $.console.error(`Bash history plugin error: ${error}`);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@superbfowle/bash-history-mcp-test",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"module": "index.ts",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": "./cli.ts",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@types/bun": "latest"
|
|
9
|
+
},
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"typescript": "^5",
|
|
12
|
+
"@opencode-ai/plugin": "*"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.19.1"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/server.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Atuin MCP Server - Read access to atuin history
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import {
|
|
10
|
+
CallToolRequestSchema,
|
|
11
|
+
ListToolsRequestSchema,
|
|
12
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
|
|
14
|
+
const server = new Server(
|
|
15
|
+
{
|
|
16
|
+
name: "atuin-history",
|
|
17
|
+
version: "0.1.0",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
capabilities: {
|
|
21
|
+
tools: {},
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// List available tools
|
|
27
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
28
|
+
return {
|
|
29
|
+
tools: [
|
|
30
|
+
{
|
|
31
|
+
name: "search_history",
|
|
32
|
+
description: "Search command history using atuin. Returns matching commands with timestamps and context. You can also use atuin directly via bash - try 'atuin --help' to learn more.",
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
query: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Search query to find matching commands",
|
|
39
|
+
},
|
|
40
|
+
limit: {
|
|
41
|
+
type: "number",
|
|
42
|
+
description: "Maximum number of results to return (default: 5)",
|
|
43
|
+
default: 5,
|
|
44
|
+
},
|
|
45
|
+
include_failed: {
|
|
46
|
+
type: "boolean",
|
|
47
|
+
description: "Include commands that failed (non-zero exit code). Default: false",
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
required: ["query"],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "get_recent_history",
|
|
56
|
+
description: "Get recent command history from atuin with timestamps and exit codes. You can also use atuin directly via bash - try 'atuin --help' to learn more.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
type: "object",
|
|
59
|
+
properties: {
|
|
60
|
+
limit: {
|
|
61
|
+
type: "number",
|
|
62
|
+
description: "Number of recent commands to retrieve (default: 5)",
|
|
63
|
+
default: 5,
|
|
64
|
+
},
|
|
65
|
+
include_failed: {
|
|
66
|
+
type: "boolean",
|
|
67
|
+
description: "Include commands that failed (non-zero exit code). Default: false",
|
|
68
|
+
default: false,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Handle tool calls
|
|
78
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
79
|
+
const { name, arguments: args } = request.params;
|
|
80
|
+
|
|
81
|
+
if (name === "search_history") {
|
|
82
|
+
const query = args.query as string;
|
|
83
|
+
const limit = (args.limit as number) || 5;
|
|
84
|
+
const includeFailed = (args.include_failed as boolean) || false;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const proc = Bun.spawn(
|
|
88
|
+
[
|
|
89
|
+
"atuin",
|
|
90
|
+
"search",
|
|
91
|
+
"--limit",
|
|
92
|
+
String(limit * 2), // Request more to account for filtering
|
|
93
|
+
"--search-mode",
|
|
94
|
+
"fuzzy",
|
|
95
|
+
"--filter-mode",
|
|
96
|
+
"global",
|
|
97
|
+
"--format",
|
|
98
|
+
"{exit}\t{command}",
|
|
99
|
+
query,
|
|
100
|
+
],
|
|
101
|
+
{
|
|
102
|
+
stdout: "pipe",
|
|
103
|
+
stderr: "pipe",
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const exitCode = await proc.exited;
|
|
108
|
+
const stdout = await Bun.readableStreamToText(proc.stdout);
|
|
109
|
+
const stderr = await Bun.readableStreamToText(proc.stderr);
|
|
110
|
+
|
|
111
|
+
if (exitCode !== 0) {
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: "text",
|
|
116
|
+
text: `Error searching history: ${stderr}`,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const lines = stdout.trim().split("\n").filter((line) => line.length > 0);
|
|
123
|
+
let commands = lines
|
|
124
|
+
.map((line) => {
|
|
125
|
+
const [exitCodeStr, ...commandParts] = line.split("\t");
|
|
126
|
+
return {
|
|
127
|
+
exitCode: parseInt(exitCodeStr, 10),
|
|
128
|
+
command: commandParts.join("\t"),
|
|
129
|
+
};
|
|
130
|
+
})
|
|
131
|
+
.filter((item) => includeFailed || item.exitCode === 0)
|
|
132
|
+
.map((item) => item.command)
|
|
133
|
+
.slice(0, limit);
|
|
134
|
+
|
|
135
|
+
const atuinCommand = `atuin search --limit ${limit * 2} --search-mode fuzzy --filter-mode global --format "{exit}\\t{command}" "${query}"`;
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: "text",
|
|
141
|
+
text: `Found ${commands.length} matching commands:\n\n${commands.join("\n")}\n\n---\nAtuin command used:\n${atuinCommand}`,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
} catch (error) {
|
|
146
|
+
return {
|
|
147
|
+
content: [
|
|
148
|
+
{
|
|
149
|
+
type: "text",
|
|
150
|
+
text: `Error: ${error}`,
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (name === "get_recent_history") {
|
|
158
|
+
const limit = (args.limit as number) || 5;
|
|
159
|
+
const includeFailed = (args.include_failed as boolean) || false;
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const proc = Bun.spawn(
|
|
163
|
+
[
|
|
164
|
+
"atuin",
|
|
165
|
+
"search",
|
|
166
|
+
"--limit",
|
|
167
|
+
String(limit * 2), // Request more to account for filtering
|
|
168
|
+
"--search-mode",
|
|
169
|
+
"fuzzy",
|
|
170
|
+
"--filter-mode",
|
|
171
|
+
"global",
|
|
172
|
+
"--format",
|
|
173
|
+
"{exit}\t{command}",
|
|
174
|
+
"",
|
|
175
|
+
],
|
|
176
|
+
{
|
|
177
|
+
stdout: "pipe",
|
|
178
|
+
stderr: "pipe",
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const exitCode = await proc.exited;
|
|
183
|
+
const stdout = await Bun.readableStreamToText(proc.stdout);
|
|
184
|
+
const stderr = await Bun.readableStreamToText(proc.stderr);
|
|
185
|
+
|
|
186
|
+
if (exitCode !== 0) {
|
|
187
|
+
return {
|
|
188
|
+
content: [
|
|
189
|
+
{
|
|
190
|
+
type: "text",
|
|
191
|
+
text: `Error getting recent history: ${stderr}`,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const lines = stdout.trim().split("\n").filter((line) => line.length > 0);
|
|
198
|
+
let commands = lines
|
|
199
|
+
.map((line) => {
|
|
200
|
+
const [exitCodeStr, ...commandParts] = line.split("\t");
|
|
201
|
+
return {
|
|
202
|
+
exitCode: parseInt(exitCodeStr, 10),
|
|
203
|
+
command: commandParts.join("\t"),
|
|
204
|
+
};
|
|
205
|
+
})
|
|
206
|
+
.filter((item) => includeFailed || item.exitCode === 0)
|
|
207
|
+
.map((item) => item.command)
|
|
208
|
+
.slice(0, limit);
|
|
209
|
+
|
|
210
|
+
const atuinCommand = `atuin search --limit ${limit * 2} --search-mode fuzzy --filter-mode global --format "{exit}\\t{command}" ""`;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
content: [
|
|
214
|
+
{
|
|
215
|
+
type: "text",
|
|
216
|
+
text: `Recent ${commands.length} commands:\n\n${commands.join("\n")}\n\n---\nAtuin command used:\n${atuinCommand}`,
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
} catch (error) {
|
|
221
|
+
return {
|
|
222
|
+
content: [
|
|
223
|
+
{
|
|
224
|
+
type: "text",
|
|
225
|
+
text: `Error: ${error}`,
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
content: [
|
|
234
|
+
{
|
|
235
|
+
type: "text",
|
|
236
|
+
text: `Unknown tool: ${name}`,
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Start the server
|
|
243
|
+
const transport = new StdioServerTransport();
|
|
244
|
+
await server.connect(transport);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
}
|
|
29
|
+
}
|