pi-harness-runtime 1.1.15 → 1.1.16

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.
Files changed (95) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/footer-status.ts +4 -1
  3. package/harness/e2e/glm-quota-scraper.ts +18 -10
  4. package/harness/glm-quota-countdown.ts +36 -25
  5. package/harness/glm-quota-logger.ts +172 -0
  6. package/harness/index.ts +19 -0
  7. package/package.json +1 -1
  8. package/packages/a2a-adapter/package.json +1 -1
  9. package/packages/architecture-generator/package.json +1 -1
  10. package/packages/auth/package.json +1 -1
  11. package/packages/autonomous-refactor/package.json +1 -1
  12. package/packages/autonomous-runtime/package.json +1 -1
  13. package/packages/cache-strategy/package.json +1 -1
  14. package/packages/capability-registry/package.json +1 -1
  15. package/packages/checkpoint/package.json +1 -1
  16. package/packages/cli-plugin-sdk/package.json +1 -1
  17. package/packages/clipboard/package.json +1 -1
  18. package/packages/clipboard-plugin/package.json +1 -1
  19. package/packages/code-generation/package.json +1 -1
  20. package/packages/code-review/package.json +1 -1
  21. package/packages/codex-adapter/package.json +1 -1
  22. package/packages/config-capture/package.json +1 -1
  23. package/packages/context-compiler/package.json +1 -1
  24. package/packages/context-discovery/package.json +1 -1
  25. package/packages/context-manager/package.json +1 -1
  26. package/packages/cookie-sanitizer/package.json +1 -1
  27. package/packages/cost-optimizer/package.json +1 -1
  28. package/packages/dependency-analyzer/package.json +1 -1
  29. package/packages/django-plugin/package.json +1 -1
  30. package/packages/doc-generator/package.json +1 -1
  31. package/packages/evaluation-engine/package.json +1 -1
  32. package/packages/evaluation-runner/package.json +1 -1
  33. package/packages/event-bus/package.json +1 -1
  34. package/packages/event-store/package.json +1 -1
  35. package/packages/experience-replay/package.json +1 -1
  36. package/packages/feedback-collector/package.json +1 -1
  37. package/packages/file-copy-helper/package.json +1 -1
  38. package/packages/framework-detector/package.json +1 -1
  39. package/packages/framework-plugin-sdk/package.json +1 -1
  40. package/packages/frappe-plugin/package.json +1 -1
  41. package/packages/generic-web-plugin/package.json +1 -1
  42. package/packages/health-monitor/package.json +1 -1
  43. package/packages/intent-analyzer/package.json +1 -1
  44. package/packages/knowledge-graph/package.json +1 -1
  45. package/packages/knowledge-retrieval/package.json +1 -1
  46. package/packages/laravel-plugin/package.json +1 -1
  47. package/packages/learning-engine/package.json +1 -1
  48. package/packages/mcp-adapter/package.json +1 -1
  49. package/packages/memory-engine/package.json +1 -1
  50. package/packages/milestone-manager/package.json +1 -1
  51. package/packages/model-registry/package.json +1 -1
  52. package/packages/nextjs-plugin/package.json +1 -1
  53. package/packages/notification/package.json +1 -1
  54. package/packages/observability/package.json +1 -1
  55. package/packages/okf-indexer/package.json +1 -1
  56. package/packages/performance-optimizer/package.json +1 -1
  57. package/packages/privilege-broker/package.json +1 -1
  58. package/packages/project-analyzer/package.json +1 -1
  59. package/packages/project-bootstrap/package.json +1 -1
  60. package/packages/projection-engine/package.json +1 -1
  61. package/packages/prompt-compiler/package.json +1 -1
  62. package/packages/prompt-versioning/package.json +1 -1
  63. package/packages/provider-adapter-sdk/package.json +1 -1
  64. package/packages/provider-router/package.json +1 -1
  65. package/packages/provider-selector/package.json +1 -1
  66. package/packages/providers/package.json +1 -1
  67. package/packages/quota-manager/package.json +1 -1
  68. package/packages/rate-limiter/package.json +1 -1
  69. package/packages/react-vite-plugin/package.json +1 -1
  70. package/packages/release-manager/package.json +1 -1
  71. package/packages/requirement-compiler/package.json +1 -1
  72. package/packages/runtime/package.json +1 -1
  73. package/packages/scheduler/package.json +1 -1
  74. package/packages/scheduler-adapter/package.json +1 -1
  75. package/packages/session/package.json +1 -1
  76. package/packages/session-api/package.json +1 -1
  77. package/packages/session-export/package.json +1 -1
  78. package/packages/shared-context/package.json +1 -1
  79. package/packages/skill-registry/package.json +1 -1
  80. package/packages/sprint-planner/package.json +1 -1
  81. package/packages/subscription-engine/package.json +1 -1
  82. package/packages/task-compiler/package.json +1 -1
  83. package/packages/tencentdb-memory/package.json +1 -1
  84. package/packages/tencentdb-sync/package.json +1 -1
  85. package/packages/test-data-generator/package.json +1 -1
  86. package/packages/test-generator/package.json +1 -1
  87. package/packages/todo-bd-sync/package.json +1 -1
  88. package/packages/token-estimation/package.json +1 -1
  89. package/packages/token-optimizer/package.json +1 -1
  90. package/packages/tui/package.json +1 -1
  91. package/packages/types/package.json +1 -1
  92. package/packages/workflow-events/package.json +1 -1
  93. package/packages/workspace-scanner/package.json +1 -1
  94. package/packages/worktree/package.json +1 -1
  95. package/packages/write-review/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.1.16](https://github.com/ManotLuijiu/pi-harness-runtime/compare/v1.1.13...v1.1.16) (2026-08-24)
6
+
7
+
8
+ ### Features
9
+
10
+ * **glm-quota:** add robust GLM quota countdown with auto-resume ([cb78a2b](https://github.com/ManotLuijiu/pi-harness-runtime/commit/cb78a2bdf5ecf79fc028030d43e3ce40767253cb))
11
+ * **glm:** add structured logging for GLM quota events ([09e692e](https://github.com/ManotLuijiu/pi-harness-runtime/commit/09e692ec17b9c21a448c72f081d18fb35b8636ae))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **glm:** improve footer status display with specific 5h quota and reset time ([ab991c3](https://github.com/ManotLuijiu/pi-harness-runtime/commit/ab991c329bdb4097e77503d3d7f574edc6cdc1c4))
17
+
5
18
  ### [1.1.15](https://github.com/ManotLuijiu/pi-harness-runtime/compare/v1.1.13...v1.1.15) (2026-08-24)
6
19
 
7
20
 
package/footer-status.ts CHANGED
@@ -235,7 +235,10 @@ export function buildFooterStatusValue(
235
235
  view.resets_at !== undefined ||
236
236
  view.h5_resets_at !== undefined)
237
237
  ) {
238
- const limitTypeLabel = getLimitTypeLabel(provider, view.limitType ?? undefined);
238
+ const limitTypeLabel = getLimitTypeLabel(
239
+ provider,
240
+ view.limitType ?? undefined,
241
+ );
239
242
  const resetFormatted = formatResetTime(view.resets_at ?? view.h5_resets_at);
240
243
  return `${label}: ${limitTypeLabel} hit, resets ${resetFormatted}`;
241
244
  }
@@ -143,7 +143,8 @@ export class GLMQuotaScraper {
143
143
 
144
144
  constructor(config: GLMScraperConfig = {}) {
145
145
  // Resolve API key: direct value > file > null
146
- const apiKey = config.apiKey ?? loadApiKey(config.apiKeyFile ?? DEFAULT_API_KEY_FILE);
146
+ const apiKey =
147
+ config.apiKey ?? loadApiKey(config.apiKeyFile ?? DEFAULT_API_KEY_FILE);
147
148
 
148
149
  this.config = {
149
150
  apiKeyFile: config.apiKeyFile ?? DEFAULT_API_KEY_FILE,
@@ -191,13 +192,16 @@ export class GLMQuotaScraper {
191
192
  /**
192
193
  * Fetch usage data from z.ai API
193
194
  */
194
- async fetchUsage(startDate?: Date, endDate?: Date): Promise<GLMQuotaData | null> {
195
+ async fetchUsage(
196
+ startDate?: Date,
197
+ endDate?: Date,
198
+ ): Promise<GLMQuotaData | null> {
195
199
  const apiKey = this.getApiKey();
196
200
  if (!apiKey) {
197
201
  if (!this.config.quiet) {
198
202
  console.error(
199
203
  `[DEBUG GLMQuotaScraper] No API key found. ` +
200
- `Set ZAI_API_KEY env var or drop key into ${DEFAULT_API_KEY_FILE}`,
204
+ `Set ZAI_API_KEY env var or drop key into ${DEFAULT_API_KEY_FILE}`,
201
205
  );
202
206
  }
203
207
  return null;
@@ -214,7 +218,9 @@ export class GLMQuotaScraper {
214
218
 
215
219
  try {
216
220
  if (!this.config.quiet) {
217
- console.log(`[DEBUG GLMQuotaScraper] Fetching usage from ${startStr} to ${endStr}`);
221
+ console.log(
222
+ `[DEBUG GLMQuotaScraper] Fetching usage from ${startStr} to ${endStr}`,
223
+ );
218
224
  }
219
225
 
220
226
  const response = await fetch(url, {
@@ -234,7 +240,7 @@ export class GLMQuotaScraper {
234
240
  return null;
235
241
  }
236
242
 
237
- const data = await response.json() as {
243
+ const data = (await response.json()) as {
238
244
  code?: number;
239
245
  success?: boolean;
240
246
  data?: {
@@ -255,7 +261,9 @@ export class GLMQuotaScraper {
255
261
 
256
262
  if (!data.success || !data.data) {
257
263
  if (!this.config.quiet) {
258
- console.error(`[DEBUG GLMQuotaScraper] API error: ${data.msg ?? "Unknown error"}`);
264
+ console.error(
265
+ `[DEBUG GLMQuotaScraper] API error: ${data.msg ?? "Unknown error"}`,
266
+ );
259
267
  }
260
268
  return null;
261
269
  }
@@ -279,8 +287,8 @@ export class GLMQuotaScraper {
279
287
  if (!this.config.quiet) {
280
288
  console.log(
281
289
  `[DEBUG GLMQuotaScraper] Total calls: ${result.totalCalls}, ` +
282
- `Total tokens: ${result.totalTokens.toLocaleString()}, ` +
283
- `Model: ${result.modelName}`,
290
+ `Total tokens: ${result.totalTokens.toLocaleString()}, ` +
291
+ `Model: ${result.modelName}`,
284
292
  );
285
293
  }
286
294
 
@@ -320,7 +328,7 @@ export class GLMQuotaScraper {
320
328
  return null;
321
329
  }
322
330
 
323
- const data = await response.json() as {
331
+ const data = (await response.json()) as {
324
332
  code?: number;
325
333
  success?: boolean;
326
334
  data?: Array<{
@@ -479,7 +487,7 @@ export class GLMQuotaManager {
479
487
  return this.lastQuota;
480
488
  }
481
489
 
482
- this.lastQuota = await this.scraper.fetchUsage() ?? undefined;
490
+ this.lastQuota = (await this.scraper.fetchUsage()) ?? undefined;
483
491
  this.lastFetchTime = now;
484
492
  return this.lastQuota ?? null;
485
493
  }
@@ -21,6 +21,24 @@ import type { JobStateMachine } from "./job-state-machine.js";
21
21
  import type { MirrorStore } from "../mirror.js";
22
22
  import type { NotificationCenter } from "../packages/notification/dist/notification-center.js";
23
23
 
24
+ import {
25
+ logInfo,
26
+ logWarn,
27
+ logError,
28
+ logCountdownStarted,
29
+ logCountdownTick,
30
+ logCountdownComplete,
31
+ logAutoResumeSuccess,
32
+ logAutoResumeFailed,
33
+ logNotificationSent,
34
+ logNotificationFailed,
35
+ logMirrorUpdate,
36
+ logQuotaExhausted,
37
+ logCountdownCancelled,
38
+ logResetTimeParseError,
39
+ getLogFilePath,
40
+ } from "./glm-quota-logger.js";
41
+
24
42
  /** Notification intervals before reset (in seconds) */
25
43
  const NOTIFICATION_INTERVALS = [
26
44
  15 * 60, // 15 minutes
@@ -245,9 +263,7 @@ export class GLMQuotaCountdown {
245
263
  isResetTime: totalSeconds <= 0,
246
264
  });
247
265
 
248
- console.log(
249
- `[GLMQuotaCountdown] Started countdown for job ${jobId}: ${formatCountdown(totalSeconds)} until reset at ${resetAt}`,
250
- );
266
+ logCountdownStarted(jobId, resetAt, totalSeconds);
251
267
 
252
268
  return state;
253
269
  }
@@ -263,9 +279,7 @@ export class GLMQuotaCountdown {
263
279
  ): Promise<GLMQuotaCountdownState | null> {
264
280
  const resetAt = parseGLMResetTime(errorMessage);
265
281
  if (!resetAt) {
266
- console.warn(
267
- `[GLMQuotaCountdown] Could not parse reset time from error for job ${jobId}`,
268
- );
282
+ logResetTimeParseError(jobId);
269
283
  return null;
270
284
  }
271
285
 
@@ -282,7 +296,7 @@ export class GLMQuotaCountdown {
282
296
  this.timers.delete(jobId);
283
297
  }
284
298
  this.activeCountdowns.delete(jobId);
285
- console.log(`[GLMQuotaCountdown] Cancelled countdown for job ${jobId}`);
299
+ logCountdownCancelled(jobId);
286
300
  }
287
301
 
288
302
  /**
@@ -322,11 +336,10 @@ export class GLMQuotaCountdown {
322
336
  };
323
337
 
324
338
  mirrorStore.writeProvider("glm", updated);
325
- console.log(
326
- `[GLMQuotaCountdown] Updated mirror with reset time: ${resetAt}`,
327
- );
339
+ logMirrorUpdate(jobId, true);
328
340
  } catch (error) {
329
- console.error(`[GLMQuotaCountdown] Failed to update mirror: ${error}`);
341
+ logMirrorUpdate(jobId, false);
342
+ logError(jobId, "Failed to update mirror", error);
330
343
  }
331
344
  }
332
345
 
@@ -476,7 +489,7 @@ export class GLMQuotaCountdown {
476
489
  * Get seconds until next notification
477
490
  */
478
491
  private getNextNotificationIn(
479
- state: GLMQuotaCountdownState,
492
+ _state: GLMQuotaCountdownState,
480
493
  remainingSeconds: number,
481
494
  ): number | undefined {
482
495
  for (const interval of NOTIFICATION_INTERVALS) {
@@ -496,13 +509,13 @@ export class GLMQuotaCountdown {
496
509
  interval: number,
497
510
  ): Promise<void> {
498
511
  if (!this.notificationCenter) {
499
- console.log(
500
- `[GLMQuotaCountdown] Notification: ${formatCountdown(remainingSeconds)} until GLM quota reset`,
512
+ logInfo(
513
+ jobId,
514
+ `Notification: ${formatCountdown(remainingSeconds)} until GLM quota reset`,
501
515
  );
502
516
  return;
503
517
  }
504
518
 
505
- const minutes = Math.floor(remainingSeconds / 60);
506
519
  const label =
507
520
  interval === 15 * 60
508
521
  ? "15 minutes"
@@ -516,11 +529,9 @@ export class GLMQuotaCountdown {
516
529
  requirement: this.jobContext?.requirement ?? "GLM Quota",
517
530
  error: `GLM quota reset in ${label} (${formatCountdown(remainingSeconds)}). Auto-resume pending.`,
518
531
  });
519
- console.log(
520
- `[GLMQuotaCountdown] Sent ${label} notification for job ${jobId}`,
521
- );
532
+ logNotificationSent(jobId, remainingSeconds);
522
533
  } catch (error) {
523
- console.error(`[GLMQuotaCountdown] Failed to send notification: ${error}`);
534
+ logNotificationFailed(jobId, String(error));
524
535
  }
525
536
  }
526
537
 
@@ -529,11 +540,11 @@ export class GLMQuotaCountdown {
529
540
  */
530
541
  private async triggerAutoResume(
531
542
  jobId: string,
532
- state: GLMQuotaCountdownState,
543
+ _state: GLMQuotaCountdownState,
533
544
  machine: JobStateMachine,
534
545
  mirrorStore: MirrorStore,
535
546
  ): Promise<void> {
536
- console.log(`[GLMQuotaCountdown] Triggering auto-resume for job ${jobId}`);
547
+ logCountdownComplete(jobId);
537
548
 
538
549
  // Clear timers
539
550
  this.cancelCountdown(jobId);
@@ -547,7 +558,7 @@ export class GLMQuotaCountdown {
547
558
  if (checkpoint && checkpoint.status === "paused_quota") {
548
559
  const result = await machine.transition("running");
549
560
  if (result.success) {
550
- console.log(`[GLMQuotaCountdown] Job ${jobId} auto-resumed successfully`);
561
+ logAutoResumeSuccess(jobId);
551
562
 
552
563
  // Update mirror to clear exhaustion
553
564
  const record = mirrorStore.readProvider("glm");
@@ -569,11 +580,11 @@ export class GLMQuotaCountdown {
569
580
  isResetTime: true,
570
581
  });
571
582
  } else {
572
- console.error(`[GLMQuotaCountdown] Auto-resume failed: ${result.error}`);
583
+ logAutoResumeFailed(jobId, result.error ?? "Unknown error");
573
584
  }
574
585
  }
575
586
  } catch (error) {
576
- console.error(`[GLMQuotaCountdown] Auto-resume error: ${error}`);
587
+ logError(jobId, "Auto-resume error", error);
577
588
  }
578
589
  }
579
590
 
@@ -585,7 +596,7 @@ export class GLMQuotaCountdown {
585
596
  try {
586
597
  callback(event);
587
598
  } catch (error) {
588
- console.error(`[GLMQuotaCountdown] Tick callback error: ${error}`);
599
+ logError(event.jobId, "Tick callback error", error);
589
600
  }
590
601
  }
591
602
  }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * GLM Quota Logger — Structured logging for GLM quota events
3
+ *
4
+ * Logs are written to:
5
+ * ~/.pi/harness-logs/glm-quota.log
6
+ *
7
+ * Log levels:
8
+ * INFO - Normal events (countdown started, resume triggered)
9
+ * WARN - Warnings (quota still exhausted, notification failed)
10
+ * ERROR - Errors (auto-resume failed, mirror update failed)
11
+ *
12
+ * Format: [ISO_TIMESTAMP] [LEVEL] [jobId] message
13
+ */
14
+
15
+ import { appendFileSync, existsSync, mkdirSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { homedir } from "node:os";
18
+
19
+ export type LogLevel = "INFO" | "WARN" | "ERROR";
20
+
21
+ const LOG_DIR = join(homedir(), ".pi", "harness-logs");
22
+ const LOG_FILE = join(LOG_DIR, "glm-quota.log");
23
+
24
+ /** Ensure log directory exists */
25
+ function ensureLogDir(): void {
26
+ if (!existsSync(LOG_DIR)) {
27
+ mkdirSync(LOG_DIR, { recursive: true });
28
+ }
29
+ }
30
+
31
+ /** Format log entry */
32
+ function formatLog(level: LogLevel, jobId: string | null, message: string): string {
33
+ const timestamp = new Date().toISOString();
34
+ const job = jobId ? `[${jobId}]` : "[system]";
35
+ return `[${timestamp}] [${level}] ${job} ${message}`;
36
+ }
37
+
38
+ /**
39
+ * Write a log entry to file
40
+ */
41
+ function writeLog(level: LogLevel, jobId: string | null, message: string): void {
42
+ try {
43
+ ensureLogDir();
44
+ const entry = formatLog(level, jobId, message) + "\n";
45
+ appendFileSync(LOG_FILE, entry);
46
+ } catch {
47
+ // Non-fatal - just log to console
48
+ console.error(`[GLMQuotaLogger] Failed to write log: ${message}`);
49
+ }
50
+ }
51
+
52
+ // --- Public API ---
53
+
54
+ /**
55
+ * Log info level event
56
+ */
57
+ export function logInfo(jobId: string | null, message: string): void {
58
+ console.log(`[GLMQuota] ${jobId ? `[${jobId}] ` : ""}${message}`);
59
+ writeLog("INFO", jobId, message);
60
+ }
61
+
62
+ /**
63
+ * Log warning level event
64
+ */
65
+ export function logWarn(jobId: string | null, message: string): void {
66
+ console.warn(`[GLMQuota] ${jobId ? `[${jobId}] ` : ""}${message}`);
67
+ writeLog("WARN", jobId, message);
68
+ }
69
+
70
+ /**
71
+ * Log error level event
72
+ */
73
+ export function logError(jobId: string | null, message: string, error?: unknown): void {
74
+ const errorMsg = error instanceof Error ? error.message : String(error ?? "");
75
+ const fullMessage = errorMsg ? `${message}: ${errorMsg}` : message;
76
+ console.error(`[GLMQuota] ${jobId ? `[${jobId}] ` : ""}${fullMessage}`);
77
+ writeLog("ERROR", jobId, fullMessage);
78
+ }
79
+
80
+ // --- Event-specific log helpers ---
81
+
82
+ /** Log countdown started */
83
+ export function logCountdownStarted(
84
+ jobId: string,
85
+ resetAt: string,
86
+ totalSeconds: number,
87
+ ): void {
88
+ const hours = Math.floor(totalSeconds / 3600);
89
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
90
+ logInfo(
91
+ jobId,
92
+ `Countdown started: ${hours}h ${minutes}m until ${resetAt}`,
93
+ );
94
+ }
95
+
96
+ /** Log countdown tick */
97
+ export function logCountdownTick(
98
+ jobId: string,
99
+ remainingSeconds: number,
100
+ ): void {
101
+ const hours = Math.floor(remainingSeconds / 3600);
102
+ const minutes = Math.floor((remainingSeconds % 3600) / 60);
103
+ const secs = remainingSeconds % 60;
104
+ logInfo(
105
+ jobId,
106
+ `Countdown tick: ${hours}h ${minutes}m ${secs}s remaining`,
107
+ );
108
+ }
109
+
110
+ /** Log countdown completed */
111
+ export function logCountdownComplete(jobId: string): void {
112
+ logInfo(jobId, "Countdown complete, triggering auto-resume");
113
+ }
114
+
115
+ /** Log auto-resume success */
116
+ export function logAutoResumeSuccess(jobId: string): void {
117
+ logInfo(jobId, "Auto-resume succeeded, job resumed");
118
+ }
119
+
120
+ /** Log auto-resume failed */
121
+ export function logAutoResumeFailed(jobId: string, error: string): void {
122
+ logError(jobId, "Auto-resume failed", error);
123
+ }
124
+
125
+ /** Log notification sent */
126
+ export function logNotificationSent(
127
+ jobId: string,
128
+ beforeReset: number,
129
+ ): void {
130
+ const minutes = Math.floor(beforeReset / 60);
131
+ logInfo(jobId, `Notification sent: ${minutes} minutes before reset`);
132
+ }
133
+
134
+ /** Log notification failed */
135
+ export function logNotificationFailed(
136
+ jobId: string,
137
+ error: string,
138
+ ): void {
139
+ logWarn(jobId, `Notification failed: ${error}`);
140
+ }
141
+
142
+ /** Log mirror update */
143
+ export function logMirrorUpdate(jobId: string, success: boolean): void {
144
+ if (success) {
145
+ logInfo(jobId, "Mirror store updated with reset time");
146
+ } else {
147
+ logWarn(jobId, "Failed to update mirror store");
148
+ }
149
+ }
150
+
151
+ /** Log quota exhaustion detected */
152
+ export function logQuotaExhausted(
153
+ jobId: string,
154
+ resetAt: string,
155
+ ): void {
156
+ logInfo(jobId, `GLM 5h quota exhausted, reset at ${resetAt}`);
157
+ }
158
+
159
+ /** Log countdown cancelled */
160
+ export function logCountdownCancelled(jobId: string): void {
161
+ logInfo(jobId, "Countdown cancelled");
162
+ }
163
+
164
+ /** Log error parsing reset time */
165
+ export function logResetTimeParseError(jobId: string): void {
166
+ logWarn(jobId, "Could not parse reset time from error message");
167
+ }
168
+
169
+ /** Get the log file path */
170
+ export function getLogFilePath(): string {
171
+ return LOG_FILE;
172
+ }
package/harness/index.ts CHANGED
@@ -222,6 +222,25 @@ export type {
222
222
  CountdownTickEvent,
223
223
  } from "./glm-quota-countdown.js";
224
224
 
225
+ // --- GLM Quota Logger ---------------------------------------------
226
+ export {
227
+ logInfo,
228
+ logWarn,
229
+ logError,
230
+ logCountdownStarted,
231
+ logCountdownTick,
232
+ logCountdownComplete,
233
+ logAutoResumeSuccess,
234
+ logAutoResumeFailed,
235
+ logNotificationSent,
236
+ logNotificationFailed,
237
+ logMirrorUpdate,
238
+ logQuotaExhausted,
239
+ logCountdownCancelled,
240
+ logResetTimeParseError,
241
+ getLogFilePath,
242
+ } from "./glm-quota-logger.js";
243
+
225
244
  // --- RFC-0059: Experience Replay ------------------------------------------
226
245
  export {
227
246
  ExperienceReplay,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-harness-runtime",
3
- "version": "1.1.15",
3
+ "version": "1.1.16",
4
4
  "description": "[BETA] Codex-style /usage status + autonomous coding harness for pi. Not production ready — expect breaking changes.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/a2a-adapter",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "description": "Google Agent-to-Agent (A2A) protocol adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/architecture-generator",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Generate ADR and Mermaid diagrams from project analysis",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/auth",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "pi-harness-runtime — auth",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-refactor",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "description": "Autonomous refactoring engine",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/autonomous-runtime",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Autonomous Operations Runtime — task inbox, lease management, and worker lifecycle (RFC-0101)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cache-strategy",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "description": "Smart caching with TTL and invalidation strategies (RFC-0022)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/capability-registry",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/checkpoint",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Enhanced checkpoint system with incremental snapshots, diff-based storage, and recovery strategies",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/cli-plugin-sdk",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "description": "CLI Plugin SDK for pi-harness — install, list, remove, update, invoke plugins",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/clipboard-plugin",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-generation",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Code generation pipeline for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/code-review",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Automated code review engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/codex-adapter",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "description": "OpenAI Codex provider adapter for pi-harness",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moocoding/config-capture",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Auto-capture API-fetched configuration values to AGENTS.md",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-compiler",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Bounded context selection engine for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/context-discovery",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/context-manager",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Context Window Manager — prevents model context overflow via compaction and resume prompts (RFC-0010)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cookie-sanitizer",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "pi-harness-runtime — cookie sanitizer (provider-quota cookie file normaliser)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/cost-optimizer",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Cost Optimizer for pi-harness-runtime — budget tracking, forecasting, and model selection optimization",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/dependency-analyzer",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {