@plexor-dev/claude-code-plugin-staging 0.1.0-beta.28 → 0.1.0-beta.29
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/track-response.js +1 -2
- package/lib/supervisor.js +67 -14
- package/package.json +1 -1
package/hooks/track-response.js
CHANGED
|
@@ -232,8 +232,7 @@ async function main() {
|
|
|
232
232
|
// Phase 1 supervisor UX: concise single-line routing summary
|
|
233
233
|
supervisor.emit(response, plexorMeta);
|
|
234
234
|
|
|
235
|
-
//
|
|
236
|
-
emitCompactWarning(response, plexorMeta);
|
|
235
|
+
// Context warnings now handled by supervisor.emit() (Phase 5) to avoid duplicates
|
|
237
236
|
|
|
238
237
|
// Issue #701: Track ALL responses, not just when enabled
|
|
239
238
|
// This ensures session stats are always accurate
|
package/lib/supervisor.js
CHANGED
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
* decisions to the developer without requiring them to parse verbose logs.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
|
|
27
30
|
const CYAN = '\x1b[36m';
|
|
28
31
|
const YELLOW = '\x1b[33m';
|
|
29
32
|
const RED = '\x1b[31m';
|
|
@@ -32,6 +35,8 @@ const RESET = '\x1b[0m';
|
|
|
32
35
|
|
|
33
36
|
const CONTEXT_WARNING_THRESHOLD = 70000;
|
|
34
37
|
const CONTEXT_COMPACT_THRESHOLD = 80000;
|
|
38
|
+
const SESSION_STATE_PATH = path.join(process.env.HOME || '', '.plexor', 'supervisor-session.json');
|
|
39
|
+
const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 min — start fresh if idle
|
|
35
40
|
|
|
36
41
|
class SupervisorEmitter {
|
|
37
42
|
/**
|
|
@@ -46,11 +51,54 @@ class SupervisorEmitter {
|
|
|
46
51
|
this.enabled = opts.enabled !== false;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
// Phase 5: Session-level state
|
|
54
|
+
// Phase 5: Session-level state — restored from disk across hook invocations
|
|
55
|
+
this._loadSessionState();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Load persisted session state from disk. Resets if stale (>30 min idle).
|
|
60
|
+
*/
|
|
61
|
+
_loadSessionState() {
|
|
62
|
+
try {
|
|
63
|
+
const raw = fs.readFileSync(SESSION_STATE_PATH, 'utf8');
|
|
64
|
+
const state = JSON.parse(raw);
|
|
65
|
+
const lastTs = state.lastTimestamp || 0;
|
|
66
|
+
if (Date.now() - lastTs > SESSION_TIMEOUT_MS) {
|
|
67
|
+
// Session expired — start fresh
|
|
68
|
+
this._resetSessionState();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this._turnCount = state.turnCount || 0;
|
|
72
|
+
this._contextTokens = state.contextTokens || 0; // current context window size
|
|
73
|
+
this._cumulativeCost = state.cumulativeCost || 0;
|
|
74
|
+
this._providerHistory = state.providerHistory || [];
|
|
75
|
+
} catch {
|
|
76
|
+
this._resetSessionState();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_resetSessionState() {
|
|
50
81
|
this._turnCount = 0;
|
|
51
|
-
this.
|
|
82
|
+
this._contextTokens = 0;
|
|
52
83
|
this._cumulativeCost = 0;
|
|
53
|
-
this._providerHistory = [];
|
|
84
|
+
this._providerHistory = [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Persist session state to disk for cross-process continuity.
|
|
89
|
+
*/
|
|
90
|
+
_saveSessionState() {
|
|
91
|
+
try {
|
|
92
|
+
const dir = path.dirname(SESSION_STATE_PATH);
|
|
93
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
94
|
+
fs.writeFileSync(SESSION_STATE_PATH, JSON.stringify({
|
|
95
|
+
turnCount: this._turnCount,
|
|
96
|
+
contextTokens: this._contextTokens,
|
|
97
|
+
cumulativeCost: this._cumulativeCost,
|
|
98
|
+
providerHistory: this._providerHistory.slice(-20), // keep last 20
|
|
99
|
+
lastTimestamp: Date.now(),
|
|
100
|
+
}));
|
|
101
|
+
} catch { /* best-effort persistence */ }
|
|
54
102
|
}
|
|
55
103
|
|
|
56
104
|
/**
|
|
@@ -253,11 +301,13 @@ class SupervisorEmitter {
|
|
|
253
301
|
_accumulateSessionState(response, plexorMeta) {
|
|
254
302
|
this._turnCount++;
|
|
255
303
|
|
|
256
|
-
//
|
|
304
|
+
// Context window size — prompt_tokens IS the current context size (not cumulative).
|
|
305
|
+
// Each turn's prompt_tokens includes the full conversation context.
|
|
257
306
|
const usage = response?.usage || response?.plexor?.usage || {};
|
|
258
307
|
const promptTokens = Number(usage.prompt_tokens) || 0;
|
|
259
|
-
|
|
260
|
-
|
|
308
|
+
if (promptTokens > 0) {
|
|
309
|
+
this._contextTokens = promptTokens; // replace, not accumulate
|
|
310
|
+
}
|
|
261
311
|
|
|
262
312
|
// Cumulative cost
|
|
263
313
|
const costUsd = Number(
|
|
@@ -290,12 +340,12 @@ class SupervisorEmitter {
|
|
|
290
340
|
*/
|
|
291
341
|
_emitSessionNarration() {
|
|
292
342
|
// Session summary line — every turn
|
|
293
|
-
const tokenStr = this._formatTokenCount(this.
|
|
343
|
+
const tokenStr = this._formatTokenCount(this._contextTokens);
|
|
294
344
|
const costStr = this._cumulativeCost < 0.01
|
|
295
345
|
? `$${this._cumulativeCost.toFixed(4)}`
|
|
296
346
|
: `$${this._cumulativeCost.toFixed(2)}`;
|
|
297
347
|
process.stderr.write(
|
|
298
|
-
`${MAGENTA}[PLEXOR: Session: ${this._turnCount} turns, ${costStr} cost, ${tokenStr}
|
|
348
|
+
`${MAGENTA}[PLEXOR: Session: ${this._turnCount} turns, ${costStr} cost, ${tokenStr} context]${RESET}\n`
|
|
299
349
|
);
|
|
300
350
|
|
|
301
351
|
// Provider reliability digest — every 5th turn
|
|
@@ -306,18 +356,21 @@ class SupervisorEmitter {
|
|
|
306
356
|
}
|
|
307
357
|
}
|
|
308
358
|
|
|
309
|
-
// Context warning at 70K tokens
|
|
310
|
-
if (this.
|
|
311
|
-
const kTokens = Math.round(this.
|
|
359
|
+
// Context warning at 70K tokens (uses real context window size, not cumulative)
|
|
360
|
+
if (this._contextTokens >= CONTEXT_COMPACT_THRESHOLD) {
|
|
361
|
+
const kTokens = Math.round(this._contextTokens / 1000);
|
|
312
362
|
process.stderr.write(
|
|
313
363
|
`${YELLOW}[PLEXOR: Context at ${kTokens}K \u2014 recommend /compact to prevent errors]${RESET}\n`
|
|
314
364
|
);
|
|
315
|
-
} else if (this.
|
|
316
|
-
const kTokens = Math.round(this.
|
|
365
|
+
} else if (this._contextTokens >= CONTEXT_WARNING_THRESHOLD) {
|
|
366
|
+
const kTokens = Math.round(this._contextTokens / 1000);
|
|
317
367
|
process.stderr.write(
|
|
318
368
|
`${YELLOW}[PLEXOR: Context at ${kTokens}K tokens \u2014 approaching provider limits]${RESET}\n`
|
|
319
369
|
);
|
|
320
370
|
}
|
|
371
|
+
|
|
372
|
+
// Persist state for next hook invocation
|
|
373
|
+
this._saveSessionState();
|
|
321
374
|
}
|
|
322
375
|
|
|
323
376
|
/**
|
|
@@ -358,7 +411,7 @@ class SupervisorEmitter {
|
|
|
358
411
|
// ---- Phase 5 accessors (for testing) ----
|
|
359
412
|
|
|
360
413
|
get turnCount() { return this._turnCount; }
|
|
361
|
-
get cumulativeTokens() { return this.
|
|
414
|
+
get cumulativeTokens() { return this._contextTokens; }
|
|
362
415
|
get cumulativeCost() { return this._cumulativeCost; }
|
|
363
416
|
|
|
364
417
|
// ---- private helpers ----
|
package/package.json
CHANGED