pi-harness-runtime 1.1.375 → 1.1.377
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/README.md +68 -39
- package/package.json +2 -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 +56 -35
- package/packages/relay/dist/client.js +278 -71
- package/packages/relay/dist/index.d.ts +12 -5
- package/packages/relay/dist/index.js +12 -4
- package/packages/relay/dist/server.d.ts +58 -20
- package/packages/relay/dist/server.js +344 -49
- package/packages/relay/dist/types.d.ts +137 -1
- package/packages/relay/dist/types.js +21 -2
- package/packages/relay/dist/ws-server.d.ts +48 -0
- package/packages/relay/dist/ws-server.js +130 -0
- package/packages/relay/package.json +1 -1
- package/packages/relay/src/client.ts +375 -81
- package/packages/relay/src/index.ts +42 -5
- package/packages/relay/src/server.ts +452 -54
- package/packages/relay/src/types.ts +174 -1
- package/packages/relay/src/ws-server.ts +165 -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
- package/scripts/relay-client.ts +184 -0
- package/scripts/sync-callback-queue.ts +57 -0
- package/scripts/telegram-callback-processor.ts +16 -0
- package/scripts/unified-webhook-server.ts +160 -145
- package/scripts/ws-server.ts +81 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Relay Types
|
|
2
|
+
* Relay Types - Two-way Streaming Communication
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Connection Types
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
5
11
|
export interface RelayConfig {
|
|
6
12
|
/** Relay server URL */
|
|
7
13
|
serverUrl: string;
|
|
@@ -30,6 +36,173 @@ export interface RelayTunnel {
|
|
|
30
36
|
error?: string;
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// WebSocket Connection State Machine
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
export type ConnectionState =
|
|
44
|
+
| { state: 'disconnected' }
|
|
45
|
+
| { state: 'connecting' }
|
|
46
|
+
| { state: 'authenticating' }
|
|
47
|
+
| { state: 'connected'; sessionId: string }
|
|
48
|
+
| { state: 'reconnecting'; attempt: number }
|
|
49
|
+
| { state: 'error'; error: string };
|
|
50
|
+
|
|
51
|
+
export interface ConnectionStateChange {
|
|
52
|
+
previous: ConnectionState;
|
|
53
|
+
current: ConnectionState;
|
|
54
|
+
timestamp: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Typed Streaming Protocol
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Protocol version for typed streaming
|
|
63
|
+
*/
|
|
64
|
+
export const PROTOCOL_VERSION = 1;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generate a unique message ID
|
|
68
|
+
*/
|
|
69
|
+
export function generateMessageId(): string {
|
|
70
|
+
return randomUUID();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create a timestamp
|
|
75
|
+
*/
|
|
76
|
+
export function createTimestamp(): string {
|
|
77
|
+
return new Date().toISOString();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Base message interface
|
|
82
|
+
*/
|
|
83
|
+
export interface BaseMessage<T extends string, P = unknown> {
|
|
84
|
+
version: typeof PROTOCOL_VERSION;
|
|
85
|
+
type: T;
|
|
86
|
+
payload: P;
|
|
87
|
+
timestamp: string;
|
|
88
|
+
messageId?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Server -> Client: Initial state snapshot sent on connect
|
|
93
|
+
*/
|
|
94
|
+
export interface SnapshotMessage extends BaseMessage<'snapshot'> {
|
|
95
|
+
payload: {
|
|
96
|
+
sessionId: string;
|
|
97
|
+
serverVersion: string;
|
|
98
|
+
connectedClients: number;
|
|
99
|
+
recentCallbacks: CallbackPayload[];
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Server -> Client: Synchronization marker (indicates all initial state sent)
|
|
105
|
+
*/
|
|
106
|
+
export interface SynchronizedMessage extends BaseMessage<'synchronized'> {}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Callback types from Telegram/LINE
|
|
110
|
+
*/
|
|
111
|
+
export interface CallbackPayload {
|
|
112
|
+
id: string;
|
|
113
|
+
type: 'telegram_callback' | 'line_callback';
|
|
114
|
+
action: string;
|
|
115
|
+
targetId: string;
|
|
116
|
+
userId: number;
|
|
117
|
+
username?: string;
|
|
118
|
+
messageId?: number;
|
|
119
|
+
timestamp: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Server -> Client: Live callback event (after synchronized)
|
|
124
|
+
*/
|
|
125
|
+
export interface CallbackMessage extends BaseMessage<'callback'> {
|
|
126
|
+
payload: CallbackPayload;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Server -> Client: Status update
|
|
131
|
+
*/
|
|
132
|
+
export type StatusKind = 'info' | 'warning' | 'error';
|
|
133
|
+
|
|
134
|
+
export interface StatusMessage extends BaseMessage<'status'> {
|
|
135
|
+
payload: {
|
|
136
|
+
kind: StatusKind;
|
|
137
|
+
code: string;
|
|
138
|
+
message: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Heartbeat messages
|
|
144
|
+
*/
|
|
145
|
+
export interface PingMessage extends BaseMessage<'ping'> {}
|
|
146
|
+
|
|
147
|
+
export interface PongMessage extends BaseMessage<'pong'> {}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Authentication messages
|
|
151
|
+
*/
|
|
152
|
+
export interface AuthRequestMessage extends BaseMessage<'auth'> {
|
|
153
|
+
payload: {
|
|
154
|
+
token: string;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface AuthResponseMessage extends BaseMessage<'auth'> {
|
|
159
|
+
payload: {
|
|
160
|
+
success: boolean;
|
|
161
|
+
sessionId?: string;
|
|
162
|
+
error?: string;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Client -> Server: Subscribe to specific event types
|
|
168
|
+
*/
|
|
169
|
+
export interface SubscribeMessage extends BaseMessage<'subscribe'> {
|
|
170
|
+
payload: {
|
|
171
|
+
events: ('callback' | 'status' | 'sync')[];
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Connection acknowledged by server
|
|
177
|
+
*/
|
|
178
|
+
export interface ConnectedMessage extends BaseMessage<'connected'> {
|
|
179
|
+
payload: {
|
|
180
|
+
clientId: string;
|
|
181
|
+
serverTime: string;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Union type of all server -> client messages
|
|
187
|
+
*/
|
|
188
|
+
export type ServerMessage =
|
|
189
|
+
| SnapshotMessage
|
|
190
|
+
| SynchronizedMessage
|
|
191
|
+
| CallbackMessage
|
|
192
|
+
| StatusMessage
|
|
193
|
+
| PongMessage
|
|
194
|
+
| ConnectedMessage
|
|
195
|
+
| AuthResponseMessage;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Union type of all client -> server messages
|
|
199
|
+
*/
|
|
200
|
+
export type ClientMessage =
|
|
201
|
+
| AuthRequestMessage
|
|
202
|
+
| PingMessage
|
|
203
|
+
| SubscribeMessage;
|
|
204
|
+
|
|
205
|
+
// Legacy compatibility
|
|
33
206
|
export interface RelayMessage {
|
|
34
207
|
type: 'connect' | 'disconnect' | 'data' | 'ping' | 'pong' | 'error';
|
|
35
208
|
tunnelId?: string;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Relay Server - Pushes callbacks to connected clients in real-time
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* Telegram/LINE → Webhook → This Server → WebSocket → Local Client
|
|
6
|
+
*
|
|
7
|
+
* No file queue needed - real-time streaming!
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createServer, IncomingMessage, ServerResponse, Server } from "node:http";
|
|
11
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
13
|
+
|
|
14
|
+
export interface RelayMessage {
|
|
15
|
+
type: "callback" | "ping" | "pong" | "auth";
|
|
16
|
+
payload: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface CallbackPayload {
|
|
20
|
+
type: "telegram_callback" | "line_callback";
|
|
21
|
+
action: string;
|
|
22
|
+
targetId: string;
|
|
23
|
+
userId: number;
|
|
24
|
+
username?: string;
|
|
25
|
+
messageId?: number;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const AUTH_TOKEN = process.env.RELAY_AUTH_TOKEN || "change-me-in-production";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* WebSocket Relay Server
|
|
33
|
+
*/
|
|
34
|
+
export class WsRelayServer {
|
|
35
|
+
private server: Server | null = null;
|
|
36
|
+
private wss: WebSocketServer | null = null;
|
|
37
|
+
private clients = new Map<string, WebSocket>();
|
|
38
|
+
private port: number;
|
|
39
|
+
private running = false;
|
|
40
|
+
|
|
41
|
+
constructor(port = 8444) {
|
|
42
|
+
this.port = port;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Start the WebSocket server
|
|
47
|
+
*/
|
|
48
|
+
async start(): Promise<void> {
|
|
49
|
+
if (this.running) return;
|
|
50
|
+
|
|
51
|
+
this.server = createServer();
|
|
52
|
+
this.wss = new WebSocketServer({ server: this.server });
|
|
53
|
+
|
|
54
|
+
this.wss.on("connection", (ws: WebSocket, req: IncomingMessage) => {
|
|
55
|
+
const clientId = randomUUID();
|
|
56
|
+
console.log(`[WsRelay] Client connected: ${clientId} from ${req.socket.remoteAddress}`);
|
|
57
|
+
|
|
58
|
+
// Don't auth yet - just accept connection
|
|
59
|
+
// Client will send auth message
|
|
60
|
+
ws.on("message", (data: Buffer) => {
|
|
61
|
+
try {
|
|
62
|
+
const msg = JSON.parse(data.toString()) as RelayMessage;
|
|
63
|
+
this.handleMessage(ws, clientId, msg);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.error("[WsRelay] Invalid message:", err);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
ws.on("close", () => {
|
|
70
|
+
this.clients.delete(clientId);
|
|
71
|
+
console.log(`[WsRelay] Client disconnected: ${clientId}`);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
ws.on("error", (err) => {
|
|
75
|
+
console.error(`[WsRelay] Client error: ${clientId}`, err);
|
|
76
|
+
this.clients.delete(clientId);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Send welcome
|
|
80
|
+
ws.send(JSON.stringify({ type: "connected", payload: { clientId } }));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
this.server!.listen(this.port, () => {
|
|
85
|
+
this.running = true;
|
|
86
|
+
console.log(`[WsRelay] Server started on port ${this.port}`);
|
|
87
|
+
resolve();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private handleMessage(ws: WebSocket, clientId: string, msg: RelayMessage): void {
|
|
93
|
+
switch (msg.type) {
|
|
94
|
+
case "auth":
|
|
95
|
+
if (msg.payload === AUTH_TOKEN) {
|
|
96
|
+
this.clients.set(clientId, ws);
|
|
97
|
+
ws.send(JSON.stringify({ type: "auth", payload: { success: true } }));
|
|
98
|
+
console.log(`[WsRelay] Client authenticated: ${clientId}`);
|
|
99
|
+
} else {
|
|
100
|
+
ws.send(JSON.stringify({ type: "auth", payload: { success: false, error: "Invalid token" } }));
|
|
101
|
+
ws.close();
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
|
|
105
|
+
case "ping":
|
|
106
|
+
ws.send(JSON.stringify({ type: "pong", payload: {} }));
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Broadcast callback to all connected clients
|
|
113
|
+
*/
|
|
114
|
+
broadcastCallback(callback: CallbackPayload): void {
|
|
115
|
+
const msg = JSON.stringify({ type: "callback", payload: callback });
|
|
116
|
+
let count = 0;
|
|
117
|
+
|
|
118
|
+
for (const [clientId, ws] of this.clients) {
|
|
119
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
120
|
+
ws.send(msg);
|
|
121
|
+
count++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log(`[WsRelay] Broadcast callback to ${count} client(s): ${callback.action} ${callback.targetId}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Stop the server
|
|
130
|
+
*/
|
|
131
|
+
async stop(): Promise<void> {
|
|
132
|
+
if (!this.running) return;
|
|
133
|
+
|
|
134
|
+
for (const ws of this.clients.values()) {
|
|
135
|
+
ws.close();
|
|
136
|
+
}
|
|
137
|
+
this.clients.clear();
|
|
138
|
+
|
|
139
|
+
return new Promise((resolve) => {
|
|
140
|
+
this.server!.close(() => {
|
|
141
|
+
this.running = false;
|
|
142
|
+
console.log("[WsRelay] Server stopped");
|
|
143
|
+
resolve();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
isRunning(): boolean {
|
|
149
|
+
return this.running;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
getClientCount(): number {
|
|
153
|
+
return this.clients.size;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Export singleton for use in unified webhook server
|
|
158
|
+
let singleton: WsRelayServer | null = null;
|
|
159
|
+
|
|
160
|
+
export function getRelayServer(): WsRelayServer {
|
|
161
|
+
if (!singleton) {
|
|
162
|
+
singleton = new WsRelayServer();
|
|
163
|
+
}
|
|
164
|
+
return singleton;
|
|
165
|
+
}
|