pi-harness-runtime 1.1.392 → 1.1.394

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 (116) hide show
  1. package/harness/console-guard.ts +73 -0
  2. package/index.ts +103 -1
  3. package/package.json +1 -1
  4. package/packages/a2a-adapter/package.json +1 -1
  5. package/packages/agent-policy/package.json +1 -1
  6. package/packages/architecture-generator/package.json +1 -1
  7. package/packages/auth/package.json +1 -1
  8. package/packages/autonomous-refactor/package.json +1 -1
  9. package/packages/autonomous-runtime/package.json +1 -1
  10. package/packages/cache-strategy/package.json +1 -1
  11. package/packages/capability-registry/package.json +1 -1
  12. package/packages/checkpoint/package.json +1 -1
  13. package/packages/cli-plugin-sdk/package.json +1 -1
  14. package/packages/clipboard/package.json +1 -1
  15. package/packages/clipboard-plugin/package.json +1 -1
  16. package/packages/code-generation/package.json +1 -1
  17. package/packages/code-review/package.json +1 -1
  18. package/packages/codex-adapter/package.json +1 -1
  19. package/packages/codex-watcher/package.json +1 -1
  20. package/packages/config-capture/package.json +1 -1
  21. package/packages/connection-runtime/package.json +1 -1
  22. package/packages/context-compiler/package.json +1 -1
  23. package/packages/context-discovery/package.json +1 -1
  24. package/packages/context-manager/package.json +1 -1
  25. package/packages/contracts/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/durable-review/package.json +1 -1
  32. package/packages/e2e-tester/package.json +1 -1
  33. package/packages/evaluation-engine/package.json +1 -1
  34. package/packages/evaluation-runner/package.json +1 -1
  35. package/packages/event-bus/package.json +1 -1
  36. package/packages/event-sink/package.json +1 -1
  37. package/packages/event-store/package.json +1 -1
  38. package/packages/experience-replay/package.json +1 -1
  39. package/packages/feedback-collector/package.json +1 -1
  40. package/packages/file-copy-helper/package.json +1 -1
  41. package/packages/framework-detector/package.json +1 -1
  42. package/packages/framework-plugin-sdk/package.json +1 -1
  43. package/packages/frappe-plugin/package.json +1 -1
  44. package/packages/generic-web-plugin/package.json +1 -1
  45. package/packages/health-monitor/package.json +1 -1
  46. package/packages/intent-analyzer/package.json +1 -1
  47. package/packages/jev-judge/package.json +1 -1
  48. package/packages/knowledge-graph/package.json +1 -1
  49. package/packages/knowledge-retrieval/package.json +1 -1
  50. package/packages/laravel-plugin/package.json +1 -1
  51. package/packages/learning-engine/package.json +1 -1
  52. package/packages/mcp-adapter/package.json +1 -1
  53. package/packages/memory-engine/package.json +1 -1
  54. package/packages/milestone-manager/package.json +1 -1
  55. package/packages/model-registry/package.json +1 -1
  56. package/packages/nextjs-plugin/package.json +1 -1
  57. package/packages/notification/package.json +1 -1
  58. package/packages/observability/package.json +1 -1
  59. package/packages/okf-indexer/package.json +1 -1
  60. package/packages/paperclip-integration/package.json +1 -1
  61. package/packages/performance-optimizer/package.json +1 -1
  62. package/packages/permission-mode/package.json +1 -1
  63. package/packages/privilege-broker/package.json +1 -1
  64. package/packages/project-analyzer/package.json +1 -1
  65. package/packages/project-bootstrap/package.json +1 -1
  66. package/packages/projection-engine/package.json +1 -1
  67. package/packages/prompt-compiler/package.json +1 -1
  68. package/packages/prompt-versioning/package.json +1 -1
  69. package/packages/provider-adapter-sdk/package.json +1 -1
  70. package/packages/provider-router/package.json +1 -1
  71. package/packages/provider-selector/package.json +1 -1
  72. package/packages/providers/package.json +1 -1
  73. package/packages/qdrant-skills/package.json +1 -1
  74. package/packages/quota-manager/package.json +1 -1
  75. package/packages/rate-limiter/package.json +1 -1
  76. package/packages/react-vite-plugin/package.json +1 -1
  77. package/packages/relay/dist/client.d.ts +25 -1
  78. package/packages/relay/dist/client.js +71 -23
  79. package/packages/relay/dist/index.d.ts +1 -1
  80. package/packages/relay/package.json +1 -1
  81. package/packages/relay/src/client.ts +87 -23
  82. package/packages/relay/src/index.ts +1 -1
  83. package/packages/relay/test/client.test.ts +134 -0
  84. package/packages/release-manager/package.json +1 -1
  85. package/packages/requirement-compiler/package.json +1 -1
  86. package/packages/runtime/package.json +1 -1
  87. package/packages/scheduler/package.json +1 -1
  88. package/packages/scheduler-adapter/package.json +1 -1
  89. package/packages/session/package.json +1 -1
  90. package/packages/session-api/package.json +1 -1
  91. package/packages/session-export/package.json +1 -1
  92. package/packages/shared-context/package.json +1 -1
  93. package/packages/skill-mcp-client/package.json +1 -1
  94. package/packages/skill-registry/package.json +1 -1
  95. package/packages/skills/package.json +1 -1
  96. package/packages/sprint-planner/package.json +1 -1
  97. package/packages/subscription-engine/package.json +1 -1
  98. package/packages/task-compiler/package.json +1 -1
  99. package/packages/telegram/package.json +1 -1
  100. package/packages/tencentdb-memory/package.json +1 -1
  101. package/packages/tencentdb-sync/package.json +1 -1
  102. package/packages/test-data-generator/package.json +1 -1
  103. package/packages/test-generator/package.json +1 -1
  104. package/packages/todo-bd-sync/package.json +1 -1
  105. package/packages/token-estimation/package.json +1 -1
  106. package/packages/token-optimizer/package.json +1 -1
  107. package/packages/trajectory/package.json +1 -1
  108. package/packages/tui/package.json +1 -1
  109. package/packages/types/package.json +1 -1
  110. package/packages/voice-api/package.json +1 -1
  111. package/packages/webmcp-tester/package.json +1 -1
  112. package/packages/wiki/package.json +1 -1
  113. package/packages/workflow-events/package.json +1 -1
  114. package/packages/workspace-scanner/package.json +1 -1
  115. package/packages/worktree/package.json +1 -1
  116. package/packages/write-review/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/jev-judge",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Jev Judge - Structured decision model for agent routing, E2E testing, and automated decisions",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/knowledge-graph",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Knowledge Graph extraction and provenance linking for SKILL.md files",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/knowledge-retrieval",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Knowledge retrieval via TencentDB-Agent-Memory MCP (RFC-0105)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/laravel-plugin",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Laravel framework analysis — artisan commands, Eloquent models, Blade",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/learning-engine",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Learning engine for extracting lessons from runtime execution (RFC-0058)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/mcp-adapter",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "type": "module",
5
5
  "description": "MCP server adapter for pi-harness — exposes harness capabilities as MCP tools/resources/prompts (RFC-0068)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/memory-engine",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Memory engine with OKF integration for durable knowledge management (RFC-0060)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/milestone-manager",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Track milestones and alerts when items are at risk",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/model-registry",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Model Registry for pi-harness-runtime — centralized model metadata with pricing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/nextjs-plugin",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Next.js framework detection and analysis for pi-harness-runtime (RFC-0062)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/notification",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "pi-harness-runtime — notification",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/observability",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Comprehensive observability system with structured logging, tracing, metrics, and alerting",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/okf-indexer",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "OKF document indexer for SKILL.md files (RFC-0106)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/paperclip-integration",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Paperclip API integration: poll agent inbox, route tasks to pi.dev, Telegram alerts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/performance-optimizer",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Performance optimization analyzer for pi-harness runtime (RFC-0056)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/permission-mode",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "type": "module",
5
5
  "description": "Runtime permission modes for pi-harness - Supervised/Auto/Full-access",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/privilege-broker",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Privilege Broker — capability registry and command executor for autonomous runtime (RFC-0101 §7)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/project-analyzer",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Project analysis system for pi-harness-runtime - detects frameworks, rules, and project structure",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/project-bootstrap",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Project scaffolding from typed ProjectSpec",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/projection-engine",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/prompt-compiler",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Deterministic prompt compiler for pi-harness-runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/prompt-versioning",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "type": "module",
5
5
  "description": "Version control for prompts with rollback support (RFC-0019)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/provider-adapter-sdk",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "SDK for building, testing, and registering AI provider adapters",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/provider-router",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Enhanced Provider Router for pi-harness-runtime — intelligent routing with capabilities, costs, and quotas",
5
5
  "type": "module",
6
6
  "main": "./dist/provider-router.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/provider-selector",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Multi-Provider Selector — route requests by cost, quality, and latency (RFC-0012)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/providers",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "pi-harness-runtime — providers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/qdrant-skills",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "Qdrant vector search integration for Hermes-style skill system",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/quota-manager",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "pi-harness-runtime — quota-manager",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/rate-limiter",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "type": "module",
5
5
  "description": "Rate limiting with token bucket algorithm (RFC-0023)",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi/react-vite-plugin",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "description": "React/Vite framework analysis — components, config, TypeScript setup",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -8,6 +8,18 @@
8
8
  * - Automatic reconnection with backoff
9
9
  */
10
10
  import { type RelayConfig, type ConnectionState, type ConnectionStateChange, type CallbackPayload, type ClientMessage, type SnapshotMessage, type StatusMessage } from './types.js';
11
+ /**
12
+ * Where the client writes its diagnostics.
13
+ *
14
+ * A TUI owns the terminal: a stray console write lands in the prompt input
15
+ * field. The harness therefore injects a logger that writes to the log file
16
+ * (the console stays the default for CLI scripts).
17
+ */
18
+ export interface RelayLogger {
19
+ log?: (message: string) => void;
20
+ warn?: (message: string) => void;
21
+ error?: (message: string) => void;
22
+ }
11
23
  export interface RelayClientCallbacks {
12
24
  /** Called when connected and authenticated */
13
25
  onConnected?: (sessionId: string) => void;
@@ -30,6 +42,7 @@ export declare class RelayClient {
30
42
  private ws;
31
43
  private config;
32
44
  private callbacks;
45
+ private logger;
33
46
  private state;
34
47
  private sessionId;
35
48
  private clientId;
@@ -45,7 +58,18 @@ export declare class RelayClient {
45
58
  private heartbeatTimer;
46
59
  private snapshotReceived;
47
60
  private synchronizedReceived;
48
- constructor(config: RelayConfig, callbacks?: RelayClientCallbacks);
61
+ constructor(config: RelayConfig, callbacks?: RelayClientCallbacks, logger?: RelayLogger);
62
+ /**
63
+ * Write a diagnostic.
64
+ *
65
+ * A TUI owns the terminal: the harness injects a logger so that nothing
66
+ * reaches the console. A partial logger must not reopen that hole - a
67
+ * missing level falls back to a level the logger does provide.
68
+ */
69
+ private log;
70
+ private logWarn;
71
+ private logError;
72
+ private emit;
49
73
  private setState;
50
74
  private isConnected;
51
75
  /**
@@ -23,6 +23,7 @@ export class RelayClient {
23
23
  ws = null;
24
24
  config;
25
25
  callbacks;
26
+ logger;
26
27
  // State machine
27
28
  state = { state: 'disconnected' };
28
29
  sessionId = null;
@@ -44,9 +45,54 @@ export class RelayClient {
44
45
  // Snapshot tracking (t3code pattern)
45
46
  snapshotReceived = false;
46
47
  synchronizedReceived = false;
47
- constructor(config, callbacks = {}) {
48
+ constructor(config, callbacks = {}, logger = {}) {
48
49
  this.config = config;
49
50
  this.callbacks = callbacks;
51
+ this.logger = logger;
52
+ }
53
+ // ========================================================================
54
+ // Diagnostics
55
+ // ========================================================================
56
+ /**
57
+ * Write a diagnostic.
58
+ *
59
+ * A TUI owns the terminal: the harness injects a logger so that nothing
60
+ * reaches the console. A partial logger must not reopen that hole - a
61
+ * missing level falls back to a level the logger does provide.
62
+ */
63
+ log(message) {
64
+ this.emit("log", message);
65
+ }
66
+ logWarn(message) {
67
+ this.emit("warn", message);
68
+ }
69
+ logError(message) {
70
+ this.emit("error", message);
71
+ }
72
+ emit(level, message) {
73
+ const logger = this.logger;
74
+ // A logger was injected: route the level to one the logger provides,
75
+ // never back to the console. The order keeps the severity as close as
76
+ // possible (error -> warn -> log).
77
+ const candidates = level === "error" ? ["error", "warn", "log"] : level === "warn" ? ["warn", "error", "log"] : ["log", "warn", "error"];
78
+ for (const candidate of candidates) {
79
+ const sink = candidate === "log" ? logger.log : candidate === "warn" ? logger.warn : logger.error;
80
+ if (!sink)
81
+ continue;
82
+ try {
83
+ sink(message);
84
+ }
85
+ catch {
86
+ // A broken logger must never break the relay client.
87
+ }
88
+ return;
89
+ }
90
+ if (level === "log")
91
+ console.log(message);
92
+ else if (level === "warn")
93
+ console.warn(message);
94
+ else
95
+ console.error(message);
50
96
  }
51
97
  // ========================================================================
52
98
  // Connection State Machine
@@ -106,7 +152,7 @@ export class RelayClient {
106
152
  this.setState({ state: 'connecting' });
107
153
  const url = this.config.serverUrl;
108
154
  const timeoutMs = this.config.connectTimeout ?? CONNECT_TIMEOUT_MS;
109
- console.log(`[RelayClient] Connecting to ${url}...`);
155
+ this.log(`[RelayClient] Connecting to ${url}...`);
110
156
  return new Promise((resolve, reject) => {
111
157
  const attempt = ++this.connectAttempt;
112
158
  this.pendingConnect = { resolve, reject, attempt };
@@ -114,7 +160,7 @@ export class RelayClient {
114
160
  this.connectTimeoutTimer = setTimeout(() => {
115
161
  if (!this.pendingConnect)
116
162
  return;
117
- console.error(`[RelayClient] Connection timeout after ${timeoutMs}ms`);
163
+ this.logError(`[RelayClient] Connection timeout after ${timeoutMs}ms`);
118
164
  this.settleConnect(new Error(`Connection timeout after ${timeoutMs}ms`));
119
165
  this.closeSocket();
120
166
  this.setState({ state: 'disconnected' });
@@ -129,7 +175,7 @@ export class RelayClient {
129
175
  // pending: settle it, disarm the deadline and retry like any other
130
176
  // failed connect.
131
177
  const error = err instanceof Error ? err : new Error(String(err));
132
- console.error("[RelayClient] WebSocket construction failed:", error.message);
178
+ this.logError(`[RelayClient] WebSocket construction failed: ${error.message}`);
133
179
  this.settleConnect(error);
134
180
  this.setState({ state: 'disconnected' });
135
181
  this.scheduleReconnectAfterFailure();
@@ -139,7 +185,7 @@ export class RelayClient {
139
185
  ws.on("open", () => {
140
186
  if (this.ws !== ws)
141
187
  return;
142
- console.log("[RelayClient] WebSocket opened");
188
+ this.log("[RelayClient] WebSocket opened");
143
189
  this.setState({ state: 'authenticating' });
144
190
  // Send authentication
145
191
  this.send({
@@ -160,7 +206,7 @@ export class RelayClient {
160
206
  // schedule a spurious reconnect.
161
207
  if (this.ws !== ws)
162
208
  return;
163
- console.log("[RelayClient] WebSocket closed");
209
+ this.log("[RelayClient] WebSocket closed");
164
210
  this.ws = null;
165
211
  const wasPending = this.pendingConnect !== null;
166
212
  this.handleDisconnect();
@@ -172,7 +218,7 @@ export class RelayClient {
172
218
  ws.on("error", (err) => {
173
219
  if (this.ws !== ws)
174
220
  return;
175
- console.error("[RelayClient] WebSocket error:", err.message);
221
+ this.logError(`[RelayClient] WebSocket error: ${err.message}`);
176
222
  this.callbacks.onError?.(err);
177
223
  const wasPending = this.pendingConnect !== null;
178
224
  this.ws = null;
@@ -213,7 +259,7 @@ export class RelayClient {
213
259
  * Disconnect from relay server
214
260
  */
215
261
  disconnect() {
216
- console.log("[RelayClient] Disconnecting...");
262
+ this.log("[RelayClient] Disconnecting...");
217
263
  // Deliberate stop: do not schedule a reconnect afterwards
218
264
  this.shuttingDown = true;
219
265
  // Never leave a caller awaiting connect() hanging
@@ -240,7 +286,7 @@ export class RelayClient {
240
286
  this.ws.send(JSON.stringify(message));
241
287
  }
242
288
  else {
243
- console.warn("[RelayClient] Cannot send: WebSocket not open");
289
+ this.logWarn("[RelayClient] Cannot send: WebSocket not open");
244
290
  }
245
291
  }
246
292
  // ========================================================================
@@ -273,18 +319,20 @@ export class RelayClient {
273
319
  break;
274
320
  default: {
275
321
  const unknownMsg = msg;
276
- console.warn(`[RelayClient] Unknown message type: ${unknownMsg.type}`);
322
+ this.logWarn(`[RelayClient] Unknown message type: ${unknownMsg.type}`);
277
323
  }
278
324
  }
279
325
  }
280
326
  catch (err) {
281
- console.error("[RelayClient] Failed to parse message:", err);
327
+ const detail = err instanceof Error ? (err.stack ?? err.message) : String(err);
328
+ // One line per log record: the stack must not break the format.
329
+ this.logError(`[RelayClient] Failed to parse message: ${detail.replace(/\s*\n\s*/g, " | ")}`);
282
330
  this.callbacks.onError?.(err);
283
331
  }
284
332
  }
285
333
  handleConnected(msg) {
286
334
  this.clientId = msg.payload.clientId;
287
- console.log(`[RelayClient] Connected, clientId: ${this.clientId}`);
335
+ this.log(`[RelayClient] Connected, clientId: ${this.clientId}`);
288
336
  }
289
337
  handleAuth(msg) {
290
338
  if (msg.payload.success) {
@@ -297,13 +345,13 @@ export class RelayClient {
297
345
  this.startHeartbeat();
298
346
  // Notify callback
299
347
  this.callbacks.onConnected?.(this.sessionId || '');
300
- console.log(`[RelayClient] Authenticated, sessionId: ${this.sessionId}`);
348
+ this.log(`[RelayClient] Authenticated, sessionId: ${this.sessionId}`);
301
349
  // Readiness milestone reached - settle the connect() promise
302
350
  this.settleConnect();
303
351
  }
304
352
  else {
305
353
  const message = msg.payload.error || 'Authentication failed';
306
- console.error(`[RelayClient] Auth failed: ${message}`);
354
+ this.logError(`[RelayClient] Auth failed: ${message}`);
307
355
  const error = new Error(message);
308
356
  this.callbacks.onError?.(error);
309
357
  // Reject the caller before tearing the socket down
@@ -316,13 +364,13 @@ export class RelayClient {
316
364
  }
317
365
  }
318
366
  handleSnapshot(msg) {
319
- console.log(`[RelayClient] Snapshot received: ${msg.payload.recentCallbacks.length} recent callbacks`);
367
+ this.log(`[RelayClient] Snapshot received: ${msg.payload.recentCallbacks.length} recent callbacks`);
320
368
  this.snapshotReceived = true;
321
369
  // Notify callback
322
370
  this.callbacks.onSnapshot?.(msg.payload);
323
371
  }
324
372
  handleSynchronized(_msg) {
325
- console.log("[RelayClient] Synchronized - live events starting");
373
+ this.log("[RelayClient] Synchronized - live events starting");
326
374
  this.synchronizedReceived = true;
327
375
  // Notify callback
328
376
  this.callbacks.onSynchronized?.();
@@ -330,13 +378,13 @@ export class RelayClient {
330
378
  handleCallback(msg) {
331
379
  // Only process callbacks after synchronized
332
380
  if (!this.synchronizedReceived) {
333
- console.warn("[RelayClient] Ignoring callback before synchronized");
381
+ this.logWarn("[RelayClient] Ignoring callback before synchronized");
334
382
  return;
335
383
  }
336
384
  this.callbacks.onCallback?.(msg.payload);
337
385
  }
338
386
  handleStatus(msg) {
339
- console.log(`[RelayClient] Status [${msg.payload.kind}]: ${msg.payload.code} - ${msg.payload.message}`);
387
+ this.log(`[RelayClient] Status [${msg.payload.kind}]: ${msg.payload.code} - ${msg.payload.message}`);
340
388
  this.callbacks.onStatus?.(msg.payload);
341
389
  }
342
390
  // ========================================================================
@@ -348,7 +396,7 @@ export class RelayClient {
348
396
  this.setState({ state: 'disconnected' });
349
397
  // A deliberate stop must not trigger a reconnect
350
398
  if (this.shuttingDown) {
351
- console.log("[RelayClient] Disconnected (intentional stop, no reconnect)");
399
+ this.log("[RelayClient] Disconnected (intentional stop, no reconnect)");
352
400
  return;
353
401
  }
354
402
  if (wasConnected) {
@@ -376,11 +424,11 @@ export class RelayClient {
376
424
  return;
377
425
  this.reconnectAttempt++;
378
426
  this.setState({ state: 'reconnecting', attempt: this.reconnectAttempt });
379
- console.log(`[RelayClient] Scheduling reconnect attempt ${this.reconnectAttempt} in ${this.reconnectDelay}ms`);
427
+ this.log(`[RelayClient] Scheduling reconnect attempt ${this.reconnectAttempt} in ${this.reconnectDelay}ms`);
380
428
  this.reconnectTimer = setTimeout(() => {
381
429
  this.reconnectTimer = null;
382
430
  this.connect().catch((err) => {
383
- console.error(`[RelayClient] Reconnect failed: ${err.message}`);
431
+ this.logError(`[RelayClient] Reconnect failed: ${err.message}`);
384
432
  });
385
433
  }, this.reconnectDelay);
386
434
  // Exponential backoff
@@ -446,14 +494,14 @@ export class RelayClient {
446
494
  ws.removeAllListeners("error");
447
495
  // An 'error' without a listener throws inside the ws implementation.
448
496
  ws.on("error", (err) => {
449
- console.warn("[RelayClient] Socket error while closing:", err.message);
497
+ this.logWarn(`[RelayClient] Socket error while closing: ${err.message}`);
450
498
  });
451
499
  ws.on("close", () => { });
452
500
  try {
453
501
  ws.close();
454
502
  }
455
503
  catch (err) {
456
- console.warn("[RelayClient] Error while closing socket:", String(err));
504
+ this.logWarn(`[RelayClient] Error while closing socket: ${String(err)}`);
457
505
  }
458
506
  }
459
507
  // ========================================================================
@@ -11,7 +11,7 @@
11
11
  export { RelayServer, createRelayServer } from './server.js';
12
12
  export type { RelayServerOptions } from './server.js';
13
13
  export { RelayClient } from './client.js';
14
- export type { RelayClientCallbacks } from './client.js';
14
+ export type { RelayClientCallbacks, RelayLogger } from './client.js';
15
15
  export { resolveRelayEndpoint, deriveRelayWsUrl, isRelayWsUrl, describeRelayEndpoint, } from './relay-endpoint.js';
16
16
  export type { RelayEndpointEnv, RelayEndpointResolution, ResolveRelayEndpointOptions, } from './relay-endpoint.js';
17
17
  export { RELAY_URL_SOURCES, RELAY_TOKEN_SOURCES, } from './relay-endpoint.js';
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/relay",
3
- "version": "1.1.392",
3
+ "version": "1.1.394",
4
4
  "type": "module",
5
5
  "description": "Cloud relay for remote access - T3 Connect style for pi-harness",
6
6
  "main": "./dist/index.js",