@plexor-dev/claude-code-plugin 0.1.0-beta.17 → 0.1.0-beta.19
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/commands/plexor-config.md +2 -0
- package/commands/plexor-enabled.md +2 -0
- package/commands/plexor-login.md +2 -0
- package/commands/plexor-logout.md +2 -0
- package/commands/plexor-mode.md +2 -0
- package/commands/plexor-provider.md +2 -0
- package/commands/plexor-settings.md +2 -0
- package/commands/plexor-status.js +12 -2
- package/commands/plexor-status.md +9 -1
- package/hooks/intercept.js +33 -11
- package/package.json +1 -1
- package/scripts/plexor-cli.sh +31 -24
- package/scripts/postinstall.js +50 -6
package/commands/plexor-login.md
CHANGED
package/commands/plexor-mode.md
CHANGED
|
@@ -92,8 +92,18 @@ async function main() {
|
|
|
92
92
|
const cacheEnabled = localCache ? 'Enabled' : 'Disabled';
|
|
93
93
|
const cacheRate = formatPct((summary.cache_hit_rate || 0) * 100);
|
|
94
94
|
|
|
95
|
-
// Build dashboard URL
|
|
96
|
-
|
|
95
|
+
// Build dashboard URL from API URL
|
|
96
|
+
// API: https://api.plexor.dev or https://staging.api.plexor.dev
|
|
97
|
+
// Dashboard: https://plexor.dev/dashboard or https://staging.plexor.dev/dashboard
|
|
98
|
+
let dashboardUrl = 'https://plexor.dev/dashboard';
|
|
99
|
+
try {
|
|
100
|
+
const url = new URL(apiUrl);
|
|
101
|
+
// Remove 'api.' prefix from hostname if present
|
|
102
|
+
const host = url.hostname.replace(/^api\./, '').replace(/\.api\./, '.');
|
|
103
|
+
dashboardUrl = `${url.protocol}//${host}/dashboard`;
|
|
104
|
+
} catch {
|
|
105
|
+
// If URL parsing fails, use default
|
|
106
|
+
}
|
|
97
107
|
|
|
98
108
|
// Output formatted status - each line is exactly 43 chars inner width
|
|
99
109
|
const line = (content) => ` │ ${content.padEnd(43)}│`;
|
|
@@ -10,4 +10,12 @@ Run this command to display Plexor statistics:
|
|
|
10
10
|
node ~/.claude/plugins/plexor/commands/plexor-status.js
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Use the Bash tool to execute this single command.
|
|
13
|
+
Use the Bash tool to execute this single command.
|
|
14
|
+
|
|
15
|
+
**IMPORTANT**: After running this command and displaying the output, STOP. Do not:
|
|
16
|
+
- Read any files
|
|
17
|
+
- Explore the codebase
|
|
18
|
+
- Run additional commands
|
|
19
|
+
- Ask follow-up questions
|
|
20
|
+
|
|
21
|
+
The command output is the complete response. Simply show the output and wait for the user's next input.
|
package/hooks/intercept.js
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Plexor Interception Hook
|
|
4
|
+
* Plexor Interception Hook - Phase 3 Hypervisor Architecture
|
|
5
5
|
*
|
|
6
|
-
* This script intercepts Claude Code
|
|
7
|
-
*
|
|
6
|
+
* This script intercepts Claude Code requests before they reach the LLM.
|
|
7
|
+
*
|
|
8
|
+
* In HYPERVISOR MODE (ANTHROPIC_BASE_URL points to Plexor):
|
|
9
|
+
* - All requests pass through unchanged
|
|
10
|
+
* - Server handles all optimization, routing, and quality control
|
|
11
|
+
* - Plugin just adds session tracking metadata
|
|
12
|
+
* - This is the recommended setup for best user experience
|
|
13
|
+
*
|
|
14
|
+
* In PLUGIN MODE (direct to Anthropic):
|
|
15
|
+
* - Plugin does local optimization (legacy behavior)
|
|
16
|
+
* - Less reliable due to client-side state management
|
|
8
17
|
*
|
|
9
18
|
* Input: JSON object with messages, model, max_tokens, etc.
|
|
10
|
-
* Output:
|
|
19
|
+
* Output: Passthrough (hypervisor mode) or optimized messages (plugin mode)
|
|
11
20
|
*/
|
|
12
21
|
|
|
13
22
|
const fs = require('fs');
|
|
@@ -170,14 +179,27 @@ async function main() {
|
|
|
170
179
|
input = await readStdin();
|
|
171
180
|
request = JSON.parse(input);
|
|
172
181
|
|
|
173
|
-
//
|
|
174
|
-
//
|
|
182
|
+
// Phase 3 Hypervisor Mode Detection
|
|
183
|
+
// When ANTHROPIC_BASE_URL points to Plexor, all intelligence is server-side
|
|
184
|
+
// The plugin just passes through - server handles optimization, routing, quality
|
|
175
185
|
const baseUrl = process.env.ANTHROPIC_BASE_URL || '';
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
//
|
|
180
|
-
|
|
186
|
+
const isHypervisorMode = baseUrl.includes('plexor') || baseUrl.includes('staging.api');
|
|
187
|
+
|
|
188
|
+
if (isHypervisorMode) {
|
|
189
|
+
// HYPERVISOR MODE: Server handles everything
|
|
190
|
+
// Just pass through with minimal metadata for session tracking
|
|
191
|
+
logger.debug('[Plexor] Hypervisor mode active - server handles all optimization');
|
|
192
|
+
|
|
193
|
+
// Add session tracking metadata (server will use this for analytics)
|
|
194
|
+
return output({
|
|
195
|
+
...request,
|
|
196
|
+
_plexor_client: {
|
|
197
|
+
mode: 'hypervisor',
|
|
198
|
+
plugin_version: '0.1.0-beta.18',
|
|
199
|
+
cwd: process.cwd(),
|
|
200
|
+
timestamp: Date.now(),
|
|
201
|
+
}
|
|
202
|
+
});
|
|
181
203
|
}
|
|
182
204
|
|
|
183
205
|
// CRITICAL: Check for slash commands FIRST (before agentic check)
|
package/package.json
CHANGED
package/scripts/plexor-cli.sh
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Plexor CLI - Claude Code with intelligent optimization
|
|
3
|
+
# This wrapper auto-enables hypervisor mode for direct gateway routing
|
|
3
4
|
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
DIM='\033[2m'
|
|
11
|
-
NC='\033[0m' # No Color
|
|
5
|
+
# Colors
|
|
6
|
+
CYAN='\033[0;36m'
|
|
7
|
+
GREEN='\033[0;32m'
|
|
8
|
+
YELLOW='\033[0;33m'
|
|
9
|
+
DIM='\033[2m'
|
|
10
|
+
NC='\033[0m' # No Color
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
CONFIG_FILE="$HOME/.plexor/config.json"
|
|
13
|
+
|
|
14
|
+
# Auto-configure ANTHROPIC_BASE_URL if Plexor is enabled
|
|
15
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
16
|
+
ENABLED=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('settings',{}).get('enabled', False))" 2>/dev/null)
|
|
17
|
+
API_URL=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('settings',{}).get('apiUrl', ''))" 2>/dev/null)
|
|
18
|
+
API_KEY=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('auth',{}).get('api_key', ''))" 2>/dev/null)
|
|
19
|
+
MODE=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('settings',{}).get('mode', 'balanced'))" 2>/dev/null)
|
|
20
|
+
|
|
21
|
+
if [ "$ENABLED" = "True" ] && [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
|
|
22
|
+
# Set ANTHROPIC_BASE_URL to Plexor gateway (hypervisor mode)
|
|
23
|
+
export ANTHROPIC_BASE_URL="${API_URL}/gateway/anthropic/v1"
|
|
24
|
+
export ANTHROPIC_API_KEY="$API_KEY"
|
|
25
|
+
|
|
26
|
+
# Show Plexor branding
|
|
27
|
+
echo -e "${CYAN}"
|
|
28
|
+
cat << 'EOF'
|
|
16
29
|
____ __
|
|
17
30
|
/ __ \/ /__ _ ______ _____
|
|
18
31
|
/ /_/ / / _ \| |/_/ __ \/ ___/
|
|
@@ -20,19 +33,13 @@ if [[ "$ANTHROPIC_BASE_URL" == *"plexor"* ]]; then
|
|
|
20
33
|
/_/ /_/\___/_/|_|\____/_/
|
|
21
34
|
|
|
22
35
|
EOF
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if [ "$ENABLED" = "true" ]; then
|
|
32
|
-
echo -e "${GREEN}●${NC} Optimization: ${GREEN}Active${NC} (${MODE} mode)"
|
|
33
|
-
else
|
|
34
|
-
echo -e "${YELLOW}○${NC} Optimization: ${DIM}Disabled${NC}"
|
|
35
|
-
fi
|
|
36
|
+
echo -e "${NC}"
|
|
37
|
+
echo -e "${GREEN}●${NC} Hypervisor Mode: ${GREEN}Active${NC}"
|
|
38
|
+
echo -e " Gateway: ${DIM}${ANTHROPIC_BASE_URL}${NC}"
|
|
39
|
+
echo -e " Mode: ${MODE}"
|
|
40
|
+
echo ""
|
|
41
|
+
else
|
|
42
|
+
echo -e "${YELLOW}○${NC} Plexor: ${DIM}Disabled${NC} (run /plexor-login to enable)"
|
|
36
43
|
echo ""
|
|
37
44
|
fi
|
|
38
45
|
fi
|
package/scripts/postinstall.js
CHANGED
|
@@ -11,23 +11,49 @@ const fs = require('fs');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const os = require('os');
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Get the correct home directory, accounting for sudo.
|
|
16
|
+
* When running with sudo, os.homedir() returns /root, but we want
|
|
17
|
+
* the actual user's home directory.
|
|
18
|
+
*/
|
|
19
|
+
function getHomeDir() {
|
|
20
|
+
// Check if running with sudo - SUDO_USER contains the original username
|
|
21
|
+
if (process.env.SUDO_USER) {
|
|
22
|
+
// On Linux/Mac, home directories are typically /home/<user> or /Users/<user>
|
|
23
|
+
const platform = os.platform();
|
|
24
|
+
if (platform === 'darwin') {
|
|
25
|
+
return path.join('/Users', process.env.SUDO_USER);
|
|
26
|
+
} else if (platform === 'linux') {
|
|
27
|
+
return path.join('/home', process.env.SUDO_USER);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return os.homedir();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const HOME_DIR = getHomeDir();
|
|
14
34
|
const COMMANDS_SOURCE = path.join(__dirname, '..', 'commands');
|
|
15
|
-
const CLAUDE_COMMANDS_DIR = path.join(
|
|
16
|
-
const
|
|
35
|
+
const CLAUDE_COMMANDS_DIR = path.join(HOME_DIR, '.claude', 'commands');
|
|
36
|
+
const PLEXOR_PLUGINS_DIR = path.join(HOME_DIR, '.claude', 'plugins', 'plexor', 'commands');
|
|
37
|
+
const PLEXOR_CONFIG_DIR = path.join(HOME_DIR, '.plexor');
|
|
17
38
|
|
|
18
39
|
function main() {
|
|
19
40
|
try {
|
|
20
41
|
// Create ~/.claude/commands/ if not exists
|
|
21
42
|
fs.mkdirSync(CLAUDE_COMMANDS_DIR, { recursive: true });
|
|
22
43
|
|
|
44
|
+
// Create ~/.claude/plugins/plexor/commands/ for JS executors
|
|
45
|
+
fs.mkdirSync(PLEXOR_PLUGINS_DIR, { recursive: true });
|
|
46
|
+
|
|
23
47
|
// Create ~/.plexor/ with secure permissions (owner only)
|
|
24
48
|
fs.mkdirSync(PLEXOR_CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
25
49
|
|
|
26
|
-
// Get list of command files
|
|
27
|
-
const
|
|
50
|
+
// Get list of command files (.md for Claude, .js for executors)
|
|
51
|
+
const mdFiles = fs.readdirSync(COMMANDS_SOURCE)
|
|
28
52
|
.filter(f => f.endsWith('.md'));
|
|
53
|
+
const jsFiles = fs.readdirSync(COMMANDS_SOURCE)
|
|
54
|
+
.filter(f => f.endsWith('.js'));
|
|
29
55
|
|
|
30
|
-
if (
|
|
56
|
+
if (mdFiles.length === 0) {
|
|
31
57
|
console.error('No command files found in package. Installation may be corrupt.');
|
|
32
58
|
process.exit(1);
|
|
33
59
|
}
|
|
@@ -35,7 +61,8 @@ function main() {
|
|
|
35
61
|
const installed = [];
|
|
36
62
|
const backed_up = [];
|
|
37
63
|
|
|
38
|
-
|
|
64
|
+
// Copy .md command files to ~/.claude/commands/
|
|
65
|
+
for (const file of mdFiles) {
|
|
39
66
|
const src = path.join(COMMANDS_SOURCE, file);
|
|
40
67
|
const dest = path.join(CLAUDE_COMMANDS_DIR, file);
|
|
41
68
|
|
|
@@ -55,6 +82,17 @@ function main() {
|
|
|
55
82
|
installed.push(file.replace('.md', ''));
|
|
56
83
|
}
|
|
57
84
|
|
|
85
|
+
// Copy .js executor files to ~/.claude/plugins/plexor/commands/
|
|
86
|
+
const jsInstalled = [];
|
|
87
|
+
for (const file of jsFiles) {
|
|
88
|
+
const src = path.join(COMMANDS_SOURCE, file);
|
|
89
|
+
const dest = path.join(PLEXOR_PLUGINS_DIR, file);
|
|
90
|
+
fs.copyFileSync(src, dest);
|
|
91
|
+
// Make executable
|
|
92
|
+
fs.chmodSync(dest, 0o755);
|
|
93
|
+
jsInstalled.push(file);
|
|
94
|
+
}
|
|
95
|
+
|
|
58
96
|
// Print success message
|
|
59
97
|
console.log('');
|
|
60
98
|
console.log(' ╔═══════════════════════════════════════════════════════════╗');
|
|
@@ -74,6 +112,12 @@ function main() {
|
|
|
74
112
|
backed_up.forEach(f => console.log(` ${f}`));
|
|
75
113
|
}
|
|
76
114
|
|
|
115
|
+
if (jsInstalled.length > 0) {
|
|
116
|
+
console.log('');
|
|
117
|
+
console.log(' Executors installed to ~/.claude/plugins/plexor/commands/:');
|
|
118
|
+
jsInstalled.forEach(f => console.log(` ${f}`));
|
|
119
|
+
}
|
|
120
|
+
|
|
77
121
|
console.log('');
|
|
78
122
|
console.log(' Next steps:');
|
|
79
123
|
console.log(' 1. Open Claude Code');
|