agent-window 1.0.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/hooks/hook.mjs ADDED
@@ -0,0 +1,299 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PreToolUse Hook for Discord Permission Approval
4
+ *
5
+ * This hook intercepts tool calls and:
6
+ * - Auto-approves safe tools (Read, Glob, Grep, etc.)
7
+ * - Requests Discord approval for risky tools (Write, Edit, Bash)
8
+ *
9
+ * Communication with Discord bot via shared file directory.
10
+ */
11
+
12
+ import { readFileSync, writeFileSync, existsSync, unlinkSync, mkdirSync } from 'fs';
13
+ import { join } from 'path';
14
+ import { randomUUID } from 'crypto';
15
+
16
+ // Read input from stdin
17
+ let inputData = '';
18
+ process.stdin.setEncoding('utf8');
19
+
20
+ for await (const chunk of process.stdin) {
21
+ inputData += chunk;
22
+ }
23
+
24
+ const input = JSON.parse(inputData);
25
+ const toolName = input.tool_name || '';
26
+ const toolInput = input.tool_input || {};
27
+ const toolUseId = input.tool_use_id || randomUUID();
28
+
29
+ // Pending directory (shared with Discord bot)
30
+ const PENDING_DIR = process.env.HOOK_PENDING_DIR || '/pending-permissions';
31
+ const TIMEOUT_MS = 120000; // 2 minutes
32
+
33
+ // Auto-approve safe tools (including Write/Edit since user trusts them)
34
+ const AUTO_APPROVE = [
35
+ 'Read', 'Glob', 'Grep', // File reading/search
36
+ 'Write', 'Edit', 'NotebookEdit', // File writing/editing (user trusts these)
37
+ 'WebFetch', 'WebSearch', // Web access
38
+ 'TodoWrite', 'Task', 'TaskOutput', 'AskUserQuestion', // Internal tools
39
+ 'Skill', 'EnterPlanMode', 'ExitPlanMode', // Planning tools
40
+ ];
41
+
42
+ // Always deny dangerous tools
43
+ const ALWAYS_DENY = ['KillShell'];
44
+
45
+ // Bash commands that are safe to auto-approve (read-only or common dev commands)
46
+ const SAFE_BASH_PATTERNS = [
47
+ // File reading/listing
48
+ /^ls\b/,
49
+ /^pwd$/,
50
+ /^cat\b/,
51
+ /^head\b/,
52
+ /^tail\b/,
53
+ /^less\b/,
54
+ /^more\b/,
55
+ /^file\b/,
56
+ /^stat\b/,
57
+ /^wc\b/,
58
+ /^find\b/,
59
+ /^tree\b/,
60
+ /^du\b/,
61
+ /^df\b/,
62
+ /^realpath\b/,
63
+ /^readlink\b/,
64
+ /^dirname\b/,
65
+ /^basename\b/,
66
+
67
+ // Text processing (read-only)
68
+ /^grep\b/,
69
+ /^egrep\b/,
70
+ /^fgrep\b/,
71
+ /^rg\b/,
72
+ /^ag\b/,
73
+ /^awk\b/,
74
+ /^sort\b/,
75
+ /^uniq\b/,
76
+ /^cut\b/,
77
+ /^tr\b/,
78
+ /^diff\b/,
79
+ /^cmp\b/,
80
+ /^comm\b/,
81
+ /^jq\b/,
82
+ /^yq\b/,
83
+ /^xargs\b.*\b(ls|cat|head|grep|echo|wc)\b/,
84
+
85
+ // Git (read-only operations)
86
+ /^git\s+(status|log|diff|branch|show|remote|config|describe|tag|rev-parse|ls-files|ls-tree|blame|shortlog|reflog|stash\s+list)/,
87
+
88
+ // Package managers (read/build/test operations)
89
+ /^npm\s+(list|ls|view|info|outdated|test|run|install|ci|build|start|version)/,
90
+ /^yarn\s+(list|info|outdated|test|run|install|build|start|version)/,
91
+ /^pnpm\s+(list|info|outdated|test|run|install|build|start|version)/,
92
+ /^pip\s+(list|show|freeze|check)/,
93
+ /^pip3\s+(list|show|freeze|check)/,
94
+ /^cargo\s+(build|test|check|run|clippy|fmt|doc|tree|metadata)/,
95
+ /^go\s+(build|test|run|vet|fmt|mod\s+(tidy|download|graph)|version)/,
96
+ /^composer\s+(show|info|outdated|validate)/,
97
+ /^bundle\s+(list|show|outdated|check)/,
98
+ /^mvn\s+(compile|test|package|verify|dependency:tree)/,
99
+ /^gradle\s+(build|test|check|dependencies)/,
100
+
101
+ // Version checks
102
+ /^node\s+(--version|-v)$/,
103
+ /^npm\s+(--version|-v)$/,
104
+ /^python\s*(--version|-V)$/,
105
+ /^python3\s*(--version|-V)$/,
106
+ /^pip\s+(--version|-V)$/,
107
+ /^ruby\s*(--version|-v)$/,
108
+ /^go\s+version$/,
109
+ /^cargo\s+(--version|-V)$/,
110
+ /^rustc\s+(--version|-V)$/,
111
+ /^java\s+(--version|-version)$/,
112
+ /^docker\s+(--version|-v)$/,
113
+
114
+ // Docker (read-only)
115
+ /^docker\s+(ps|images|logs|inspect|stats|top|port|version|info)/,
116
+ /^docker-compose\s+(ps|logs|config|version)/,
117
+
118
+ // System info
119
+ /^which\b/,
120
+ /^whereis\b/,
121
+ /^type\b/,
122
+ /^command\s+-v/,
123
+ /^echo\b/,
124
+ /^printf\b/,
125
+ /^date\b/,
126
+ /^whoami$/,
127
+ /^id\b/,
128
+ /^env$/,
129
+ /^printenv\b/,
130
+ /^hostname$/,
131
+ /^uname\b/,
132
+ /^uptime$/,
133
+ /^free\b/,
134
+ /^top\s+-bn1/,
135
+ /^ps\s+(aux|ef)/,
136
+
137
+ // Network (read-only)
138
+ /^curl\s+(-s\s+)?(-I\s+)?https?:/,
139
+ /^wget\s+(-q\s+)?(-O\s*-\s+)?https?:/,
140
+ /^ping\s+-c\s+\d/,
141
+ /^netstat\b/,
142
+ /^ss\b/,
143
+ /^ifconfig$/,
144
+ /^ip\s+(addr|link|route)/,
145
+
146
+ // Build/test commands (common and safe)
147
+ /^make(\s+\w+)?$/,
148
+ /^cmake\b/,
149
+ /^tsc\b/,
150
+ /^eslint\b/,
151
+ /^prettier\b/,
152
+ /^jest\b/,
153
+ /^vitest\b/,
154
+ /^pytest\b/,
155
+ /^mocha\b/,
156
+ ];
157
+
158
+ // Bash commands that always need approval (destructive)
159
+ const DANGEROUS_BASH_PATTERNS = [
160
+ /\brm\s/, // Remove files
161
+ /\brmdir\b/, // Remove directories
162
+ /\bunlink\b/, // Remove files
163
+ />\s*\/dev\/null/, // Redirect to null (data loss)
164
+ /\bgit\s+(push|reset|rebase|checkout\s+-f|clean)/, // Destructive git
165
+ /\bdocker\s+(rm|rmi|prune|system\s+prune)/, // Docker cleanup
166
+ /\bkill\b/, // Kill processes
167
+ /\bpkill\b/, // Kill processes
168
+ /\bsudo\b/, // Elevated privileges
169
+ ];
170
+
171
+ function sleep(ms) {
172
+ return new Promise(resolve => setTimeout(resolve, ms));
173
+ }
174
+
175
+ function output(decision, reason, updatedInput = null) {
176
+ const result = {
177
+ hookSpecificOutput: {
178
+ hookEventName: 'PreToolUse',
179
+ permissionDecision: decision,
180
+ permissionDecisionReason: reason,
181
+ }
182
+ };
183
+ if (updatedInput) {
184
+ result.hookSpecificOutput.updatedInput = updatedInput;
185
+ }
186
+ console.log(JSON.stringify(result));
187
+ process.exit(0);
188
+ }
189
+
190
+ // Ensure pending directory exists
191
+ try {
192
+ mkdirSync(PENDING_DIR, { recursive: true });
193
+ } catch (e) {}
194
+
195
+ console.error(`[Hook] Tool: ${toolName}, ID: ${toolUseId.substring(0, 8)}...`);
196
+
197
+ // Auto-approve safe tools
198
+ if (AUTO_APPROVE.includes(toolName)) {
199
+ console.error(`[Hook] Auto-approving: ${toolName}`);
200
+ output('allow', `Auto-approved: ${toolName} is a safe operation`);
201
+ }
202
+
203
+ // Always deny dangerous tools
204
+ if (ALWAYS_DENY.includes(toolName)) {
205
+ console.error(`[Hook] Auto-denying: ${toolName}`);
206
+ output('deny', `Denied: ${toolName} is not allowed for security reasons`);
207
+ }
208
+
209
+ // Special handling for Bash commands
210
+ if (toolName === 'Bash') {
211
+ const command = (toolInput.command || '').trim();
212
+ console.error(`[Hook] Bash command: ${command.substring(0, 80)}...`);
213
+
214
+ // Check for dangerous patterns first - these always need approval
215
+ const isDangerous = DANGEROUS_BASH_PATTERNS.some(p => p.test(command));
216
+ if (isDangerous) {
217
+ console.error(`[Hook] Dangerous bash pattern detected, requesting Discord approval`);
218
+ // Fall through to Discord approval (don't exit here)
219
+ } else {
220
+ // Check for safe patterns
221
+ const isSafe = SAFE_BASH_PATTERNS.some(p => p.test(command));
222
+ if (isSafe) {
223
+ console.error(`[Hook] Auto-approving safe bash: ${command.substring(0, 50)}`);
224
+ output('allow', `Auto-approved: Safe bash command`);
225
+ }
226
+ // Not explicitly safe - fall through to Discord approval
227
+ console.error(`[Hook] Bash needs Discord approval: ${command.substring(0, 50)}`);
228
+ }
229
+ }
230
+
231
+ // For other tools, request Discord approval
232
+ const requestId = toolUseId.replace(/[^a-zA-Z0-9]/g, '_').substring(0, 50);
233
+ const requestFile = join(PENDING_DIR, `${requestId}.request.json`);
234
+ const responseFile = join(PENDING_DIR, `${requestId}.response.json`);
235
+
236
+ // Write request file
237
+ const request = {
238
+ tool_use_id: toolUseId,
239
+ tool_name: toolName,
240
+ input: toolInput,
241
+ timestamp: Date.now(),
242
+ };
243
+
244
+ try {
245
+ writeFileSync(requestFile, JSON.stringify(request, null, 2));
246
+ console.error(`[Hook] Waiting for Discord approval: ${toolName}`);
247
+ } catch (e) {
248
+ console.error(`[Hook] Failed to write request: ${e.message}`);
249
+ output('deny', `Permission system error: ${e.message}`);
250
+ }
251
+
252
+ // Poll for response
253
+ const deadline = Date.now() + TIMEOUT_MS;
254
+ let pollCount = 0;
255
+ console.error(`[Hook] Polling for response: ${responseFile}`);
256
+
257
+ while (Date.now() < deadline) {
258
+ pollCount++;
259
+
260
+ // Debug: list files every 10 polls (3 seconds)
261
+ if (pollCount % 10 === 1) {
262
+ try {
263
+ const { readdirSync } = await import('fs');
264
+ const files = readdirSync(PENDING_DIR);
265
+ console.error(`[Hook] Poll #${pollCount}, files in ${PENDING_DIR}: ${files.join(', ') || '(empty)'}`);
266
+ } catch (e) {
267
+ console.error(`[Hook] Poll #${pollCount}, cannot list dir: ${e.message}`);
268
+ }
269
+ }
270
+
271
+ if (existsSync(responseFile)) {
272
+ console.error(`[Hook] Response file found!`);
273
+ try {
274
+ const content = readFileSync(responseFile, 'utf-8');
275
+ console.error(`[Hook] Response content: ${content.substring(0, 100)}`);
276
+ const response = JSON.parse(content);
277
+
278
+ // Clean up files
279
+ try { unlinkSync(requestFile); } catch (e) {}
280
+ try { unlinkSync(responseFile); } catch (e) {}
281
+
282
+ console.error(`[Hook] Got response: ${response.behavior}`);
283
+
284
+ if (response.behavior === 'allow') {
285
+ output('allow', 'User approved via Discord', response.updatedInput);
286
+ } else {
287
+ output('deny', response.message || 'User denied via Discord');
288
+ }
289
+ } catch (e) {
290
+ console.error(`[Hook] Error reading/parsing response: ${e.message}`);
291
+ }
292
+ }
293
+ await sleep(300);
294
+ }
295
+
296
+ // Timeout
297
+ try { unlinkSync(requestFile); } catch (e) {}
298
+ console.error('[Hook] Timeout waiting for approval');
299
+ output('deny', 'Permission request timed out (2 minutes). Please try again.');
@@ -0,0 +1,15 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": ".*",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node /permission-hook/hook.mjs"
10
+ }
11
+ ]
12
+ }
13
+ ]
14
+ }
15
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "agent-window",
3
+ "version": "1.0.0",
4
+ "description": "A window to interact with AI agents through chat interfaces. Simplified interaction, powerful backend capabilities.",
5
+ "type": "module",
6
+ "main": "src/bot.js",
7
+ "bin": {
8
+ "agent-window": "./bin/cli.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node src/bot.js",
12
+ "dev": "node --watch src/bot.js",
13
+ "setup": "node bin/cli.js setup",
14
+ "pm2:start": "pm2 start ecosystem.config.cjs",
15
+ "pm2:stop": "pm2 stop agent-window",
16
+ "pm2:restart": "pm2 restart agent-window",
17
+ "pm2:logs": "pm2 logs agent-window"
18
+ },
19
+ "keywords": [
20
+ "agent",
21
+ "window",
22
+ "discord",
23
+ "slack",
24
+ "bot",
25
+ "claude",
26
+ "ai",
27
+ "cli",
28
+ "docker",
29
+ "sandbox",
30
+ "chat",
31
+ "interface"
32
+ ],
33
+ "author": "",
34
+ "license": "MIT",
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
38
+ "dependencies": {
39
+ "discord.js": "^14.14.1"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/YOUR_USERNAME/AgentWindow"
44
+ }
45
+ }
@@ -0,0 +1,61 @@
1
+ # Claude CLI Sandbox Environment with MCP Permission Support
2
+ FROM node:20-slim
3
+
4
+ # Install system dependencies for Playwright/Chromium (as root)
5
+ RUN apt-get update && apt-get install -y --no-install-recommends \
6
+ # Playwright dependencies
7
+ libglib2.0-0 \
8
+ libnss3 \
9
+ libnspr4 \
10
+ libdbus-1-3 \
11
+ libatk1.0-0 \
12
+ libatk-bridge2.0-0 \
13
+ libcups2 \
14
+ libexpat1 \
15
+ libxcb1 \
16
+ libxkbcommon0 \
17
+ libatspi2.0-0 \
18
+ libx11-6 \
19
+ libxcomposite1 \
20
+ libxdamage1 \
21
+ libxext6 \
22
+ libxfixes3 \
23
+ libxrandr2 \
24
+ libgbm1 \
25
+ libcairo2 \
26
+ libpango-1.0-0 \
27
+ libasound2 \
28
+ # Additional useful tools
29
+ git \
30
+ curl \
31
+ && rm -rf /var/lib/apt/lists/*
32
+
33
+ # Install Claude CLI globally
34
+ RUN npm install -g @anthropic-ai/claude-code
35
+
36
+ # Install MCP SDK for permission server
37
+ RUN npm install -g @modelcontextprotocol/sdk zod
38
+
39
+ # Create directories
40
+ WORKDIR /workspace
41
+ RUN mkdir -p /mcp-server /pending-permissions
42
+
43
+ # Create a flexible home directory that any user can use
44
+ RUN mkdir -p /home/claude/.cache/ms-playwright && chmod -R 777 /home/claude
45
+
46
+ # Install Playwright globally and download Chromium to shared location
47
+ ENV PLAYWRIGHT_BROWSERS_PATH=/home/claude/.cache/ms-playwright
48
+ RUN npm install -g playwright && npx playwright install chromium && chmod -R 777 /home/claude/.cache/ms-playwright
49
+
50
+ # Set environment variables
51
+ ENV TERM=dumb
52
+ ENV CI=true
53
+ ENV NO_COLOR=1
54
+ ENV FORCE_COLOR=0
55
+ ENV NODE_PATH=/usr/local/lib/node_modules
56
+ ENV HOME=/home/claude
57
+ ENV PLAYWRIGHT_BROWSERS_PATH=/home/claude/.cache/ms-playwright
58
+
59
+ # Default command
60
+ ENTRYPOINT ["claude"]
61
+ CMD ["--help"]
@@ -0,0 +1,114 @@
1
+ #!/bin/bash
2
+
3
+ # AgentBridge - Quick Install Script
4
+ #
5
+ # Usage:
6
+ # curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/AgentBridge/main/scripts/install.sh | bash
7
+ #
8
+ # Or:
9
+ # ./scripts/install.sh
10
+
11
+ set -e
12
+
13
+ RED='\033[0;31m'
14
+ GREEN='\033[0;32m'
15
+ YELLOW='\033[1;33m'
16
+ CYAN='\033[0;36m'
17
+ NC='\033[0m'
18
+
19
+ log_info() { echo -e "${CYAN}ℹ️ $1${NC}"; }
20
+ log_success() { echo -e "${GREEN}✅ $1${NC}"; }
21
+ log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
22
+ log_error() { echo -e "${RED}❌ $1${NC}"; }
23
+
24
+ echo ""
25
+ echo -e "${CYAN}"
26
+ echo " _ _ ____ _ _"
27
+ echo " / \\ __ _ ___ _ __ | |_| __ ) _ __(_) __| | __ _ ___"
28
+ echo " / _ \\ / _\` |/ _ \\ '_ \\| __| _ \\| '__| |/ _\` |/ _\` |/ _ \\"
29
+ echo "/ ___ \\ (_| | __/ | | | |_| |_) | | | | (_| | (_| | __/"
30
+ echo "/_/ \\_\\__, |\\___|_| |_|\\__|____/|_| |_|\\__,_|\\__, |\\___|"
31
+ echo " |___/ |___/"
32
+ echo -e "${NC}"
33
+ echo " Bridge AI coding agents to chat platforms"
34
+ echo ""
35
+
36
+ # Check Node.js
37
+ if ! command -v node &> /dev/null; then
38
+ log_error "Node.js not found. Please install Node.js 18+ first."
39
+ echo "Visit: https://nodejs.org/"
40
+ exit 1
41
+ fi
42
+
43
+ NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1)
44
+ if [ "$NODE_VERSION" -lt 18 ]; then
45
+ log_error "Node.js 18+ required. Current: $(node -v)"
46
+ exit 1
47
+ fi
48
+ log_success "Node.js $(node -v)"
49
+
50
+ # Check Docker
51
+ if ! command -v docker &> /dev/null; then
52
+ log_error "Docker not found. Please install Docker first."
53
+ echo "Visit: https://docs.docker.com/get-docker/"
54
+ exit 1
55
+ fi
56
+ log_success "Docker found"
57
+
58
+ # Check PM2
59
+ if ! command -v pm2 &> /dev/null; then
60
+ log_info "Installing PM2..."
61
+ npm install -g pm2
62
+ log_success "PM2 installed"
63
+ else
64
+ log_success "PM2 found"
65
+ fi
66
+
67
+ # Clone or update
68
+ INSTALL_DIR="${INSTALL_DIR:-$HOME/AgentBridge}"
69
+
70
+ if [ -d "$INSTALL_DIR" ]; then
71
+ log_info "Updating existing installation..."
72
+ cd "$INSTALL_DIR"
73
+ git pull origin main
74
+ else
75
+ log_info "Cloning repository..."
76
+ git clone https://github.com/YOUR_USERNAME/AgentBridge.git "$INSTALL_DIR"
77
+ cd "$INSTALL_DIR"
78
+ fi
79
+
80
+ # Install dependencies
81
+ log_info "Installing dependencies..."
82
+ npm install
83
+
84
+ # Build Docker image
85
+ log_info "Building Docker sandbox..."
86
+ docker build -t claude-sandbox ./sandbox
87
+
88
+ # Config check
89
+ if [ ! -f "config/config.json" ]; then
90
+ log_warning "Config not found."
91
+ echo ""
92
+ echo "Create config/config.json:"
93
+ echo " cp config/config.example.json config/config.json"
94
+ echo " nano config/config.json"
95
+ echo ""
96
+ fi
97
+
98
+ # Link CLI
99
+ log_info "Linking CLI..."
100
+ npm link
101
+
102
+ echo ""
103
+ log_success "Installation complete!"
104
+ echo ""
105
+ echo "Next steps:"
106
+ echo " 1. Edit config/config.json"
107
+ echo " 2. Run: agent-bridge start"
108
+ echo ""
109
+ echo "Commands:"
110
+ echo " agent-bridge setup - Interactive setup"
111
+ echo " agent-bridge start - Start"
112
+ echo " agent-bridge logs - View logs"
113
+ echo " agent-bridge --help - Help"
114
+ echo ""