@a1hvdy/cc-openclaw 0.27.0 → 0.27.1

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.
@@ -102,6 +102,8 @@ export class BaseOneShotSession extends EventEmitter {
102
102
  isReady: this._isReady,
103
103
  startTime: this._startTime,
104
104
  lastActivity: this._stats.lastActivity,
105
+ // v0.27.x — oneshot engine doesn't separate progress; mirror lastActivity.
106
+ lastProgressAt: this._stats.lastActivity,
105
107
  contextPercent: 0,
106
108
  retries: 0,
107
109
  sessionId: this.sessionId,
@@ -797,6 +797,9 @@ export class PersistentCustomSession extends EventEmitter {
797
797
  isReady: this._isReady,
798
798
  startTime: this._startTime,
799
799
  lastActivity: this._stats.lastActivity,
800
+ // v0.27.x — custom engine doesn't separate progress from activity; mirror
801
+ // lastActivity so the shared watchdog behaves exactly as before for it.
802
+ lastProgressAt: this._stats.lastActivity,
800
803
  contextPercent: this.engineConfig.persistent
801
804
  ? Math.min(100, Math.round(((this._stats.tokensIn + this._stats.tokensOut) / ctxWindow) * 100))
802
805
  : 0,
@@ -25,6 +25,8 @@ interface InternalStats {
25
25
  costUsd: number;
26
26
  startTime: string | null;
27
27
  lastActivity: string | null;
28
+ /** v0.27.x — last PROGRESS event ts (excludes api_retry); watchdog keys off it. */
29
+ lastProgressAt: string | null;
28
30
  history: Array<{
29
31
  time: string;
30
32
  type: string;
@@ -58,6 +58,7 @@ export class PersistentClaudeSession extends EventEmitter {
58
58
  costUsd: 0,
59
59
  startTime: null,
60
60
  lastActivity: null,
61
+ lastProgressAt: null,
61
62
  history: [],
62
63
  retries: 0,
63
64
  lastRetryError: undefined,
@@ -346,6 +347,16 @@ export class PersistentClaudeSession extends EventEmitter {
346
347
  _handleEvent(event) {
347
348
  const type = event.type;
348
349
  this.stats.lastActivity = new Date().toISOString();
350
+ // v0.27.x — progress signal for the stalled-session watchdog. Every event
351
+ // EXCEPT `system/api_retry` counts as progress. api_retry fires during an
352
+ // API retry-storm WITHOUT producing output; counting it as activity (as
353
+ // lastActivity does) defeated the watchdog — it never saw 180s of
354
+ // no-progress, so a stalled/retrying model call hung to the 900s envelope
355
+ // (the gateway's `recovery=none lastProgressAge=353s`). Keying the watchdog
356
+ // off lastProgressAt fast-fails it at the threshold instead.
357
+ const isApiRetry = type === 'system' && event.subtype === 'api_retry';
358
+ if (!isApiRetry)
359
+ this.stats.lastProgressAt = this.stats.lastActivity;
349
360
  // Track history (keep last 100)
350
361
  this.stats.history.push({ time: this.stats.lastActivity, type, event });
351
362
  if (this.stats.history.length > MAX_HISTORY_ITEMS)
@@ -769,6 +780,7 @@ export class PersistentClaudeSession extends EventEmitter {
769
780
  isReady: this._isReady,
770
781
  startTime: this.stats.startTime,
771
782
  lastActivity: this.stats.lastActivity,
783
+ lastProgressAt: this.stats.lastProgressAt,
772
784
  // v0.6.0: contextPercent now reflects ACTUAL per-turn context occupancy
773
785
  // (input + cache-read tokens from the last `result` event), not lifetime
774
786
  // cumulative tokens. Pre-fix it saturated at 100% by turn 3 of any
@@ -22,9 +22,11 @@
22
22
  export interface WatchdogManagedSession {
23
23
  session: {
24
24
  isBusy: boolean;
25
- /** Returns at least { lastActivity }. Other stats fields are ignored. */
25
+ /** Returns at least { lastActivity, lastProgressAt }. The watchdog prefers
26
+ * lastProgressAt (excludes api_retry pings); other stats fields ignored. */
26
27
  getStats(): {
27
28
  lastActivity?: string | null | undefined;
29
+ lastProgressAt?: string | null | undefined;
28
30
  };
29
31
  stop(): void;
30
32
  };
@@ -46,18 +46,20 @@ export function watchStalledSessions(opts) {
46
46
  if (!managed.session.isBusy)
47
47
  continue;
48
48
  const stats = managed.session.getStats();
49
- const lastActivityIso = stats.lastActivity;
50
- const lastEventMs = lastActivityIso
51
- ? new Date(lastActivityIso).getTime()
52
- : managed.lastActivity;
49
+ // v0.27.x prefer the PROGRESS timestamp (real output: text/tool/result),
50
+ // which excludes `system/api_retry` pings. Keying off lastActivity let a
51
+ // retry-storm reset the clock forever so the watchdog never fired. Fall back
52
+ // to lastActivity, then the SessionManager wall-clock.
53
+ const progressIso = stats.lastProgressAt ?? stats.lastActivity;
54
+ const lastEventMs = progressIso ? new Date(progressIso).getTime() : managed.lastActivity;
53
55
  const ageMs = now - lastEventMs;
54
56
  if (ageMs <= thresholdMs)
55
57
  continue;
56
- opts.logger.warn(`[watchdog] killing stalled session ${name} (busy, no subprocess event for ${Math.round(ageMs / 1000)}s, threshold=${Math.round(thresholdMs / 1000)}s)`);
58
+ opts.logger.warn(`[watchdog] killing stalled session ${name} (busy, no progress for ${Math.round(ageMs / 1000)}s, threshold=${Math.round(thresholdMs / 1000)}s)`);
57
59
  try {
58
60
  trajectory.emit('session_stalled_killed', {
59
61
  ageMs,
60
- lastActivity: lastActivityIso,
62
+ lastProgressAt: progressIso,
61
63
  thresholdMs,
62
64
  model: managed.config.model,
63
65
  cwd: managed.cwd,
@@ -184,6 +184,12 @@ export interface SessionStats {
184
184
  isReady: boolean;
185
185
  startTime: string | null;
186
186
  lastActivity: string | null;
187
+ /** v0.27.x — wall-clock ISO of the last PROGRESS event (text / tool_use /
188
+ * tool_result / thinking / result / init) — i.e. the subprocess produced
189
+ * real output. Distinct from lastActivity, which also moves on non-progress
190
+ * events like `system/api_retry`. The stalled-session watchdog keys off this
191
+ * so an API retry-storm (no output) is fast-failed instead of looking busy. */
192
+ lastProgressAt: string | null;
187
193
  /**
188
194
  * Approximate context window utilization (0-100).
189
195
  * Estimated as (tokensIn + tokensOut) / 200,000 * 100.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a1hvdy/cc-openclaw",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "A1xAI's Anthropic CLI bridge plugin for OpenClaw",
5
5
  "author": "@a1cy",
6
6
  "license": "MIT",