@plexor-dev/claude-code-plugin-staging 0.1.0-beta.11 → 0.1.0-beta.13

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.
@@ -2,9 +2,7 @@
2
2
  description: Enable or disable Plexor proxy (routes all traffic through Plexor API) (user)
3
3
  ---
4
4
 
5
- # Plexor Enabled
6
-
7
- Toggle Plexor proxy on or off.
5
+ **RULE: Execute this workflow EXACTLY ONCE. After completing all steps, STOP. DO NOT restart the workflow. DO NOT re-execute any commands. DO NOT call any other tools.**
8
6
 
9
7
  ## If argument provided (on/off/true/false)
10
8
 
@@ -14,11 +12,11 @@ Run the command directly with the argument:
14
12
  node ~/.claude/plugins/plexor/commands/plexor-enabled.js <argument>
15
13
  ```
16
14
 
17
- Then display the output and STOP.
15
+ Then present the output to the user and STOP.
18
16
 
19
17
  ## If NO argument provided
20
18
 
21
- **Step 1**: First get current status by running:
19
+ **Step 1**: Get current status by running:
22
20
 
23
21
  ```bash
24
22
  node ~/.claude/plugins/plexor/commands/plexor-enabled.js
@@ -26,14 +24,14 @@ node ~/.claude/plugins/plexor/commands/plexor-enabled.js
26
24
 
27
25
  **Step 2**: Based on the output, use AskUserQuestion to present options:
28
26
 
29
- If currently ENABLED (shows "Enabled" or "Active"):
27
+ If currently ENABLED (shows "Enabled" or "Active"):
30
28
  - Question: "Plexor is currently ON. What would you like to do?"
31
29
  - Header: "Plexor"
32
30
  - Options:
33
31
  1. **Turn OFF** - Disable Plexor routing (connect directly to Anthropic)
34
32
  2. **Keep ON** - No change
35
33
 
36
- If currently DISABLED (shows "Disabled" or "Inactive"):
34
+ If currently DISABLED (shows "Disabled" or "Inactive"):
37
35
  - Question: "Plexor is currently OFF. What would you like to do?"
38
36
  - Header: "Plexor"
39
37
  - Options:
@@ -45,4 +43,4 @@ If currently DISABLED (shows "○ Disabled" or "○ Inactive"):
45
43
  - If "Turn ON" selected: Run `node ~/.claude/plugins/plexor/commands/plexor-enabled.js true`
46
44
  - If "Keep" selected: Do nothing, just confirm current state
47
45
 
48
- **IMPORTANT**: After completing, STOP. Do not read files, explore codebase, or run additional commands.
46
+ After completing all steps, STOP. DO NOT restart the workflow.
@@ -76,6 +76,18 @@ function saveConfig(config) {
76
76
  }
77
77
  }
78
78
 
79
+ function isPlexorApiKey(token) {
80
+ return typeof token === 'string' && token.startsWith('plx_') && token.length >= 20;
81
+ }
82
+
83
+ function isJwtToken(token) {
84
+ if (typeof token !== 'string' || !token.startsWith('eyJ')) {
85
+ return false;
86
+ }
87
+ const parts = token.split('.');
88
+ return parts.length === 3 && parts.every(part => part.length > 0);
89
+ }
90
+
79
91
  function validateApiKey(apiUrl, apiKey) {
80
92
  return new Promise((resolve, reject) => {
81
93
  const url = new URL(`${apiUrl}/v1/user`);
@@ -119,6 +131,56 @@ function validateApiKey(apiUrl, apiKey) {
119
131
  });
120
132
  }
121
133
 
134
+ function validateJwtToken(apiUrl, jwtToken) {
135
+ return new Promise((resolve, reject) => {
136
+ const url = new URL(`${apiUrl}/v1/auth/me`);
137
+ const isHttps = url.protocol === 'https:';
138
+ const lib = isHttps ? https : http;
139
+
140
+ const options = {
141
+ hostname: url.hostname,
142
+ port: url.port || (isHttps ? 443 : 80),
143
+ path: url.pathname,
144
+ method: 'GET',
145
+ headers: {
146
+ 'Authorization': `Bearer ${jwtToken}`
147
+ }
148
+ };
149
+
150
+ const req = lib.request(options, (res) => {
151
+ let data = '';
152
+ res.on('data', chunk => data += chunk);
153
+ res.on('end', () => {
154
+ if (res.statusCode === 200) {
155
+ try {
156
+ resolve(JSON.parse(data));
157
+ } catch {
158
+ reject(new Error('Invalid response from server'));
159
+ }
160
+ } else if (res.statusCode === 401) {
161
+ reject(new Error('Invalid login token'));
162
+ } else {
163
+ reject(new Error(`Server error: ${res.statusCode}`));
164
+ }
165
+ });
166
+ });
167
+
168
+ req.on('error', (err) => reject(new Error(`Connection failed: ${err.message}`)));
169
+ req.setTimeout(10000, () => {
170
+ req.destroy();
171
+ reject(new Error('Connection timeout'));
172
+ });
173
+ req.end();
174
+ });
175
+ }
176
+
177
+ function validateCredential(apiUrl, credential) {
178
+ if (isJwtToken(credential)) {
179
+ return validateJwtToken(apiUrl, credential);
180
+ }
181
+ return validateApiKey(apiUrl, credential);
182
+ }
183
+
122
184
  /**
123
185
  * Read API key from stdin (for piped input)
124
186
  * @returns {Promise<string>} The API key read from stdin
@@ -220,10 +282,10 @@ async function main() {
220
282
  console.log('');
221
283
  }
222
284
 
223
- // Validate key format
224
- if (!apiKey.startsWith('plx_') || apiKey.length < 20) {
225
- console.error(`Error: Invalid API key format`);
226
- console.error(`API keys start with "plx_" and are at least 20 characters`);
285
+ // Validate credential format (Plexor API key OR login JWT)
286
+ if (!isPlexorApiKey(apiKey) && !isJwtToken(apiKey)) {
287
+ console.error(`Error: Invalid credential format`);
288
+ console.error(`Expected Plexor API key ("plx_...") or login token ("eyJ...")`);
227
289
  process.exit(1);
228
290
  }
229
291
 
@@ -232,7 +294,7 @@ async function main() {
232
294
  console.log('Validating API key...');
233
295
 
234
296
  try {
235
- const user = await validateApiKey(apiUrl, apiKey);
297
+ const user = await validateCredential(apiUrl, apiKey);
236
298
 
237
299
  config.auth = config.auth || {};
238
300
  config.auth.api_key = apiKey;
@@ -2,26 +2,10 @@
2
2
  description: Authenticate with Plexor to enable optimization (user)
3
3
  ---
4
4
 
5
- # Plexor Login
5
+ **RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
6
6
 
7
- Run this command to authenticate with Plexor:
7
+ Pass the API key as argument (format: `plx_your_api_key_here`).
8
8
 
9
9
  ```bash
10
- node ~/.claude/plugins/plexor/commands/plexor-login.js
10
+ node ~/.claude/plugins/plexor/commands/plexor-login.js $ARGUMENTS
11
11
  ```
12
-
13
- To login with an API key:
14
-
15
- ```bash
16
- node ~/.claude/plugins/plexor/commands/plexor-login.js plx_your_api_key_here
17
- ```
18
-
19
- Use the Bash tool to execute this command.
20
-
21
- **IMPORTANT**: After running this command and displaying the output, STOP. Do not:
22
- - Read any files
23
- - Explore the codebase
24
- - Run additional commands
25
- - Ask follow-up questions
26
-
27
- The command output is the complete response. Simply show the output and wait for the user's next input.
@@ -2,26 +2,8 @@
2
2
  description: Log out from Plexor and clear credentials (user)
3
3
  ---
4
4
 
5
- # Plexor Logout
6
-
7
- Run this command to log out and clear credentials:
8
-
9
- ```bash
10
- node ~/.claude/plugins/plexor/commands/plexor-logout.js
11
- ```
12
-
13
- To also clear the cache:
5
+ **RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
14
6
 
15
7
  ```bash
16
- node ~/.claude/plugins/plexor/commands/plexor-logout.js --clear-cache
8
+ node ~/.claude/plugins/plexor/commands/plexor-logout.js $ARGUMENTS
17
9
  ```
18
-
19
- Use the Bash tool to execute this command.
20
-
21
- **IMPORTANT**: After running this command and displaying the output, STOP. Do not:
22
- - Read any files
23
- - Explore the codebase
24
- - Run additional commands
25
- - Ask follow-up questions
26
-
27
- The command output is the complete response. Simply show the output and wait for the user's next input.
@@ -2,6 +2,8 @@
2
2
  description: First-time setup wizard for Plexor with Claude Code (user)
3
3
  ---
4
4
 
5
+ **RULE: Execute this workflow EXACTLY ONCE. After completing all steps, STOP. DO NOT restart the workflow. DO NOT re-execute any commands. DO NOT call any other tools.**
6
+
5
7
  # Plexor Setup Wizard
6
8
 
7
9
  Guide users through first-time Plexor setup. **No manual environment variable configuration required!**
@@ -165,8 +167,9 @@ Commands:
165
167
  Changes take effect immediately in all Claude Code sessions!
166
168
  ```
167
169
 
168
- **IMPORTANT NOTES**:
170
+ **NOTES**:
169
171
  - The `~/.claude/settings.json` env block is the KEY mechanism that routes Claude Code through Plexor
170
172
  - ANTHROPIC_AUTH_TOKEN takes precedence over ANTHROPIC_API_KEY (use AUTH_TOKEN for the Plexor key)
171
173
  - Changes take effect immediately - no shell restart needed
172
- - After completing setup, STOP. Do not run additional commands.
174
+
175
+ After completing all steps, STOP. DO NOT restart the workflow. DO NOT re-execute any commands.
@@ -270,15 +270,9 @@ ${line(`└── Cost saved: $${sessionCostSaved}`)}
270
270
  const routingIndicator = routing.active ? '🟢 PLEXOR MODE: ON' : '🔴 PLEXOR MODE: OFF';
271
271
  const envLabel = routing.isStaging ? '(staging)' : '(production)';
272
272
 
273
- // Check for environment mismatch
274
- const envMismatch = checkEnvironmentMismatch(apiUrl, routing.baseUrl);
275
- const mismatchWarning = envMismatch
276
- ? ` ⚠ Warning: Config uses ${envMismatch.config} but routing is ${envMismatch.routing}\n`
277
- : '';
278
-
279
- if (mismatchWarning) {
280
- console.log(mismatchWarning);
281
- }
273
+ // Note: Environment mismatch warning removed - it caused false positives during
274
+ // concurrent operations and transient states. The partial state and config/routing
275
+ // mismatch warnings below provide more actionable feedback.
282
276
 
283
277
  // Check for partial routing state (Plexor URL without valid auth)
284
278
  const partialState = detectPartialState();
@@ -2,20 +2,8 @@
2
2
  description: Show Plexor optimization statistics and savings (user)
3
3
  ---
4
4
 
5
- # Plexor Status
6
-
7
- Run this command to display Plexor statistics:
5
+ **RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
8
6
 
9
7
  ```bash
10
8
  node ~/.claude/plugins/plexor/commands/plexor-status.js
11
9
  ```
12
-
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.
@@ -192,6 +192,25 @@ function removeConfigDirectory() {
192
192
 
193
193
  function main() {
194
194
  const args = process.argv.slice(2);
195
+
196
+ // Handle help flag
197
+ if (args.includes('--help') || args.includes('-h')) {
198
+ console.log('');
199
+ console.log(' Usage: plexor-uninstall [options]');
200
+ console.log('');
201
+ console.log(' Cleans up Plexor integration before npm uninstall.');
202
+ console.log('');
203
+ console.log(' Options:');
204
+ console.log(' --remove-config, -c Also remove ~/.plexor/ config directory');
205
+ console.log(' --quiet, -q Suppress output messages');
206
+ console.log(' --help, -h Show this help message');
207
+ console.log('');
208
+ console.log(' After running this command:');
209
+ console.log(' npm uninstall -g @plexor-dev/claude-code-plugin-staging');
210
+ console.log('');
211
+ process.exit(0);
212
+ }
213
+
195
214
  const removeConfig = args.includes('--remove-config') || args.includes('-c');
196
215
  const quiet = args.includes('--quiet') || args.includes('-q');
197
216
 
@@ -3,27 +3,9 @@ name: plexor-uninstall
3
3
  description: Clean up Plexor integration before uninstalling
4
4
  ---
5
5
 
6
- Runs comprehensive cleanup to prepare for npm uninstall.
6
+ **RULE: Execute the bash command below EXACTLY ONCE. After the Bash tool returns output, your ONLY action is to present that output to the user. DO NOT re-execute the command. DO NOT call any other tools.**
7
7
 
8
- **IMPORTANT**: Run this command BEFORE `npm uninstall -g @plexor-dev/claude-code-plugin-staging`
9
-
10
- npm's preuninstall hook does NOT run for global package uninstalls, so this command
11
- must be run manually to ensure proper cleanup.
12
-
13
- This removes:
14
- - Plexor routing from Claude settings (~/.claude/settings.json)
15
- - Slash command files from ~/.claude/commands/
16
- - Plugin directory ~/.claude/plugins/plexor/
17
-
18
- Options:
19
- - `--remove-config` or `-c`: Also remove ~/.plexor/ config directory
20
-
21
- After running this command, run:
22
- ```bash
23
- npm uninstall -g @plexor-dev/claude-code-plugin-staging
24
- ```
25
-
26
- $ARGUMENTS: $ARGUMENTS
8
+ **IMPORTANT**: Run this BEFORE `npm uninstall -g @plexor-dev/claude-code-plugin-staging`. Pass `--remove-config` to also remove ~/.plexor/ config directory.
27
9
 
28
10
  ```bash
29
11
  node ~/.claude/plugins/plexor/commands/plexor-uninstall.js $ARGUMENTS 2>&1 || plexor-uninstall $ARGUMENTS 2>&1
@@ -179,6 +179,17 @@ async function main() {
179
179
  input = await readStdin();
180
180
  request = JSON.parse(input);
181
181
 
182
+ // Issue #2042: Check for slash commands FIRST, before ANY other processing
183
+ // Slash commands must pass through completely clean — no metadata injection
184
+ // Adding _plexor_client or _plexor to slash command requests adds context noise
185
+ // that causes the model to re-execute commands in a loop
186
+ // Note: session.recordPassthrough() intentionally omitted — slash commands are
187
+ // not API requests and should not pollute session analytics
188
+ if (isSlashCommand(request)) {
189
+ logger.debug('Slash command detected, clean passthrough (no metadata)');
190
+ return output(request); // Completely clean — no metadata added
191
+ }
192
+
182
193
  // Phase 3 Hypervisor Mode Detection
183
194
  // When ANTHROPIC_BASE_URL points to Plexor, all intelligence is server-side
184
195
  // The plugin just passes through - server handles optimization, routing, quality
@@ -202,25 +213,6 @@ async function main() {
202
213
  });
203
214
  }
204
215
 
205
- // CRITICAL: Check for slash commands FIRST (before agentic check)
206
- // Slash commands like /plexor-status should pass through unchanged
207
- // Must check before isAgenticRequest since all Claude Code requests have tools
208
- if (isSlashCommand(request)) {
209
- logger.debug('Slash command detected, passing through unchanged');
210
- session.recordPassthrough();
211
- return output({
212
- ...request,
213
- plexor_cwd: process.cwd(),
214
- _plexor: {
215
- request_id: generateRequestId('slash'), // Issue #701: Add request_id for tracking
216
- source: 'passthrough_slash_command',
217
- reason: 'slash_command_detected',
218
- cwd: process.cwd(),
219
- latency_ms: Date.now() - startTime
220
- }
221
- });
222
- }
223
-
224
216
  // CRITICAL: Skip optimization for CLI commands requiring tool execution
225
217
  // Azure CLI, AWS CLI, kubectl, etc. need tools to be preserved
226
218
  if (requiresToolExecution(request)) {
@@ -578,12 +570,16 @@ function isSlashCommand(request) {
578
570
  }
579
571
 
580
572
  // Check for system messages with skill instructions
573
+ // Issue #2042: Updated to match new RULE-based .md format (old H1 headers removed)
581
574
  for (const msg of messages) {
582
575
  if (msg.role === 'system') {
583
576
  const content = typeof msg.content === 'string' ? msg.content : '';
584
577
  if (/# Plexor (?:Status|Login|Logout|Mode|Provider|Enabled|Settings)/i.test(content)) {
585
578
  return true;
586
579
  }
580
+ if (/plexor\/commands\/plexor-/i.test(content)) {
581
+ return true;
582
+ }
587
583
  }
588
584
  }
589
585
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plexor-dev/claude-code-plugin-staging",
3
- "version": "0.1.0-beta.11",
3
+ "version": "0.1.0-beta.13",
4
4
  "description": "STAGING - LLM cost optimization plugin for Claude Code (internal testing)",
5
5
  "main": "lib/constants.js",
6
6
  "bin": {