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.
- package/harness/console-guard.ts +73 -0
- package/index.ts +103 -1
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/dist/client.d.ts +25 -1
- package/packages/relay/dist/client.js +71 -23
- package/packages/relay/dist/index.d.ts +1 -1
- package/packages/relay/package.json +1 -1
- package/packages/relay/src/client.ts +87 -23
- package/packages/relay/src/index.ts +1 -1
- package/packages/relay/test/client.test.ts +134 -0
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/provider-router",
|
|
3
|
-
"version": "1.1.
|
|
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",
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
322
|
+
this.logWarn(`[RelayClient] Unknown message type: ${unknownMsg.type}`);
|
|
277
323
|
}
|
|
278
324
|
}
|
|
279
325
|
}
|
|
280
326
|
catch (err) {
|
|
281
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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';
|