@aifight/aifight 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +160 -0
  2. package/dist/bin.mjs +291 -0
  3. package/dist/index.mjs +107 -0
  4. package/dist/schemas/README.md +57 -0
  5. package/dist/schemas/common/README.md +40 -0
  6. package/dist/schemas/common/action.schema.json +19 -0
  7. package/dist/schemas/common/error.schema.json +23 -0
  8. package/dist/schemas/common/event.schema.json +33 -0
  9. package/dist/schemas/common/game_result.schema.json +31 -0
  10. package/dist/schemas/common/player_identity.schema.json +29 -0
  11. package/dist/schemas/common/player_info.schema.json +27 -0
  12. package/dist/schemas/common/rules.schema.json +34 -0
  13. package/dist/schemas/games/README.md +43 -0
  14. package/dist/schemas/games/coup/README.md +104 -0
  15. package/dist/schemas/games/coup/action.schema.json +198 -0
  16. package/dist/schemas/games/coup/event.schema.json +249 -0
  17. package/dist/schemas/games/coup/rules.schema.json +46 -0
  18. package/dist/schemas/games/coup/state.schema.json +123 -0
  19. package/dist/schemas/games/liars_dice/README.md +59 -0
  20. package/dist/schemas/games/liars_dice/action.schema.json +45 -0
  21. package/dist/schemas/games/liars_dice/event.schema.json +120 -0
  22. package/dist/schemas/games/liars_dice/rules.schema.json +36 -0
  23. package/dist/schemas/games/liars_dice/state.schema.json +72 -0
  24. package/dist/schemas/games/texas_holdem/README.md +58 -0
  25. package/dist/schemas/games/texas_holdem/action.schema.json +88 -0
  26. package/dist/schemas/games/texas_holdem/config.schema.json +30 -0
  27. package/dist/schemas/games/texas_holdem/event.schema.json +135 -0
  28. package/dist/schemas/games/texas_holdem/rules.schema.json +39 -0
  29. package/dist/schemas/games/texas_holdem/state.schema.json +98 -0
  30. package/dist/schemas/messages/README.md +98 -0
  31. package/dist/schemas/messages/client_action.schema.json +20 -0
  32. package/dist/schemas/messages/client_join_queue.schema.json +39 -0
  33. package/dist/schemas/messages/client_leave_queue.schema.json +18 -0
  34. package/dist/schemas/messages/client_match_confirm.schema.json +25 -0
  35. package/dist/schemas/messages/client_runtime_status.schema.json +46 -0
  36. package/dist/schemas/messages/server_action_request.schema.json +71 -0
  37. package/dist/schemas/messages/server_error.schema.json +16 -0
  38. package/dist/schemas/messages/server_event.schema.json +30 -0
  39. package/dist/schemas/messages/server_game_over.schema.json +49 -0
  40. package/dist/schemas/messages/server_game_start.schema.json +99 -0
  41. package/dist/schemas/messages/server_game_state.schema.json +33 -0
  42. package/dist/schemas/messages/server_match_cancelled.schema.json +51 -0
  43. package/dist/schemas/messages/server_match_confirm_request.schema.json +37 -0
  44. package/dist/schemas/messages/server_queue_joined.schema.json +26 -0
  45. package/dist/schemas/messages/server_queue_left.schema.json +24 -0
  46. package/dist/schemas/messages/server_readiness_check.schema.json +42 -0
  47. package/dist/schemas/messages/server_welcome.schema.json +49 -0
  48. package/dist/schemas/rest/README.md +85 -0
  49. package/dist/schemas/rest/agent_status_response.schema.json +34 -0
  50. package/dist/schemas/rest/claim_request.schema.json +20 -0
  51. package/dist/schemas/rest/claim_response.schema.json +24 -0
  52. package/dist/schemas/rest/error_response.schema.json +15 -0
  53. package/dist/schemas/rest/register_request.schema.json +35 -0
  54. package/dist/schemas/rest/register_response.schema.json +54 -0
  55. package/dist/types/account/credentials.d.ts +29 -0
  56. package/dist/types/account/errors.d.ts +61 -0
  57. package/dist/types/account/registration.d.ts +26 -0
  58. package/dist/types/agents/agent.d.ts +82 -0
  59. package/dist/types/agents/state-machine.d.ts +96 -0
  60. package/dist/types/bridge/config.d.ts +35 -0
  61. package/dist/types/bridge/hermes-provider.d.ts +9 -0
  62. package/dist/types/bridge/openclaw-provider.d.ts +9 -0
  63. package/dist/types/bridge/pairing.d.ts +18 -0
  64. package/dist/types/bridge/provider.d.ts +18 -0
  65. package/dist/types/bridge/runner.d.ts +30 -0
  66. package/dist/types/bridge/service.d.ts +55 -0
  67. package/dist/types/bridge/update-check.d.ts +23 -0
  68. package/dist/types/cli/agent-resolver.d.ts +25 -0
  69. package/dist/types/cli/argv.d.ts +13 -0
  70. package/dist/types/cli/commands/agent-list.d.ts +2 -0
  71. package/dist/types/cli/commands/agent-status.d.ts +2 -0
  72. package/dist/types/cli/commands/bridge-accept.d.ts +2 -0
  73. package/dist/types/cli/commands/bridge-challenge.d.ts +2 -0
  74. package/dist/types/cli/commands/bridge-connect.d.ts +2 -0
  75. package/dist/types/cli/commands/bridge-register.d.ts +2 -0
  76. package/dist/types/cli/commands/bridge-run.d.ts +7 -0
  77. package/dist/types/cli/commands/bridge-service.d.ts +3 -0
  78. package/dist/types/cli/commands/bridge-set.d.ts +2 -0
  79. package/dist/types/cli/commands/bridge-start.d.ts +2 -0
  80. package/dist/types/cli/commands/bridge-status.d.ts +2 -0
  81. package/dist/types/cli/commands/bridge-uninstall.d.ts +4 -0
  82. package/dist/types/cli/commands/config-init.d.ts +2 -0
  83. package/dist/types/cli/commands/config-probe.d.ts +2 -0
  84. package/dist/types/cli/commands/config-validate.d.ts +2 -0
  85. package/dist/types/cli/commands/daily-off.d.ts +2 -0
  86. package/dist/types/cli/commands/daily-on.d.ts +2 -0
  87. package/dist/types/cli/commands/daily-set.d.ts +2 -0
  88. package/dist/types/cli/commands/daily-show.d.ts +2 -0
  89. package/dist/types/cli/commands/doctor.d.ts +2 -0
  90. package/dist/types/cli/commands/init.d.ts +2 -0
  91. package/dist/types/cli/commands/join.d.ts +2 -0
  92. package/dist/types/cli/commands/leave.d.ts +2 -0
  93. package/dist/types/cli/commands/mcp.d.ts +2 -0
  94. package/dist/types/cli/commands/runtime-management.d.ts +16 -0
  95. package/dist/types/cli/commands/runtime-setup-state.d.ts +21 -0
  96. package/dist/types/cli/commands/runtime-setup.d.ts +23 -0
  97. package/dist/types/cli/commands/serve.d.ts +2 -0
  98. package/dist/types/cli/commands/service/launchd.d.ts +71 -0
  99. package/dist/types/cli/commands/service/platform.d.ts +69 -0
  100. package/dist/types/cli/commands/service/systemd.d.ts +55 -0
  101. package/dist/types/cli/commands/service/types.d.ts +64 -0
  102. package/dist/types/cli/commands/service-install.d.ts +29 -0
  103. package/dist/types/cli/commands/setup.d.ts +2 -0
  104. package/dist/types/cli/commands/shutdown.d.ts +2 -0
  105. package/dist/types/cli/commands/stubs.d.ts +24 -0
  106. package/dist/types/cli/commands/version.d.ts +2 -0
  107. package/dist/types/cli/control-client.d.ts +59 -0
  108. package/dist/types/cli/format.d.ts +52 -0
  109. package/dist/types/cli/main.d.ts +18 -0
  110. package/dist/types/cli/runtime-files.d.ts +11 -0
  111. package/dist/types/cli/shared.d.ts +74 -0
  112. package/dist/types/controlapi/profile-routes.d.ts +49 -0
  113. package/dist/types/controlapi/server.d.ts +3 -0
  114. package/dist/types/controlapi/types.d.ts +136 -0
  115. package/dist/types/daemon/agent-decision-adapter.d.ts +40 -0
  116. package/dist/types/daemon/lifecycle.d.ts +85 -0
  117. package/dist/types/daemon/router.d.ts +97 -0
  118. package/dist/types/daemon/runtime-files-write.d.ts +76 -0
  119. package/dist/types/decision/direct-model/anthropic.d.ts +12 -0
  120. package/dist/types/decision/direct-model/errors.d.ts +59 -0
  121. package/dist/types/decision/direct-model/openai.d.ts +12 -0
  122. package/dist/types/decision/direct-model/types.d.ts +20 -0
  123. package/dist/types/decision/parser-types.d.ts +31 -0
  124. package/dist/types/decision/prompt-builder.d.ts +10 -0
  125. package/dist/types/decision/provider.d.ts +50 -0
  126. package/dist/types/decision/types.d.ts +87 -0
  127. package/dist/types/games/_shared/player-info.d.ts +14 -0
  128. package/dist/types/games/coup/action-parser.d.ts +3 -0
  129. package/dist/types/games/coup/fallback.d.ts +8 -0
  130. package/dist/types/games/coup/state-formatter.d.ts +14 -0
  131. package/dist/types/games/liars_dice/action-parser.d.ts +3 -0
  132. package/dist/types/games/liars_dice/fallback.d.ts +8 -0
  133. package/dist/types/games/liars_dice/state-formatter.d.ts +14 -0
  134. package/dist/types/games/texas_holdem/action-parser.d.ts +3 -0
  135. package/dist/types/games/texas_holdem/fallback.d.ts +8 -0
  136. package/dist/types/games/texas_holdem/state-formatter.d.ts +14 -0
  137. package/dist/types/identity/identity-manager.d.ts +59 -0
  138. package/dist/types/index.d.ts +30 -0
  139. package/dist/types/llm/adapter-registry.d.ts +27 -0
  140. package/dist/types/llm/adapters/anthropic-messages.d.ts +2 -0
  141. package/dist/types/llm/adapters/deepseek-chat-completions.d.ts +2 -0
  142. package/dist/types/llm/adapters/openai-chat-compat.d.ts +2 -0
  143. package/dist/types/llm/adapters/openai-chat-completions.d.ts +2 -0
  144. package/dist/types/llm/adapters/openai-responses.d.ts +2 -0
  145. package/dist/types/llm/adapters/types.d.ts +128 -0
  146. package/dist/types/llm/capabilities/validate-capabilities.d.ts +68 -0
  147. package/dist/types/mcp/control-client.d.ts +54 -0
  148. package/dist/types/mcp/profile-tools.d.ts +10 -0
  149. package/dist/types/mcp/server.d.ts +10 -0
  150. package/dist/types/mcp/tools.d.ts +31 -0
  151. package/dist/types/mcp/types.d.ts +27 -0
  152. package/dist/types/profile/config-schema.d.ts +199 -0
  153. package/dist/types/profile/identity-schema.d.ts +75 -0
  154. package/dist/types/profile/index.d.ts +7 -0
  155. package/dist/types/profile/migrate.d.ts +16 -0
  156. package/dist/types/profile/profile-loader.d.ts +64 -0
  157. package/dist/types/profile/secret-ref.d.ts +82 -0
  158. package/dist/types/profile/soul.d.ts +46 -0
  159. package/dist/types/profile/strategy-schema.d.ts +70 -0
  160. package/dist/types/protocol/schemas.d.ts +11 -0
  161. package/dist/types/protocol/types.d.ts +1333 -0
  162. package/dist/types/reflection/proposal-store.d.ts +50 -0
  163. package/dist/types/reflection/reflection-engine.d.ts +81 -0
  164. package/dist/types/scheduler/daily.d.ts +47 -0
  165. package/dist/types/scheduler/types.d.ts +42 -0
  166. package/dist/types/session/match-session-manager.d.ts +113 -0
  167. package/dist/types/session/session-context-builder.d.ts +68 -0
  168. package/dist/types/store/errors.d.ts +23 -0
  169. package/dist/types/store/paths.d.ts +3 -0
  170. package/dist/types/store/schema.generated.d.ts +1 -0
  171. package/dist/types/store/sqlite.d.ts +36 -0
  172. package/dist/types/wsclient/client.d.ts +220 -0
  173. package/dist/types/wsclient/errors.d.ts +106 -0
  174. package/dist/types/wsclient/frame-handler.d.ts +20 -0
  175. package/dist/types/wsclient/reconnect.d.ts +84 -0
  176. package/package.json +53 -0
@@ -0,0 +1,220 @@
1
+ import { type WSClientError } from "./errors";
2
+ import { type ServerMessageEnvelope } from "./frame-handler";
3
+ export interface WSWelcome {
4
+ readonly type: "welcome";
5
+ readonly data: {
6
+ readonly server_protocol_version: string;
7
+ readonly agent_id: string;
8
+ readonly agent_name: string;
9
+ readonly server_time: string;
10
+ readonly games: readonly string[];
11
+ };
12
+ readonly match_id?: string;
13
+ }
14
+ /**
15
+ * Discriminated union of valid outbound messages the client may
16
+ * `send()` to the server. Mirrors the four `client_*.schema.json`
17
+ * files at the TypeScript layer (rev 3 P2 #4 — TS first line of
18
+ * defence; ajv via `serializeClientMessage` is the authoritative
19
+ * runtime check).
20
+ *
21
+ * Required-vs-optional contracts here track schema `required` arrays:
22
+ * - join_queue: `data` required (game name lives here)
23
+ * - leave_queue: `data` optional (no fields needed)
24
+ * - match_confirm: `data` required (carries confirm_id)
25
+ * - action: `match_id` required (server uses it for the
26
+ * per-player session_id) AND `data` required
27
+ * (the chosen action object)
28
+ *
29
+ * `match_id` on the three non-`action` types is envelope-level
30
+ * scaffolding — the schemas accept it but no current message uses it.
31
+ * Keep optional so callers don't have to thread an empty string.
32
+ *
33
+ * The `unknown` typing on `data` is deliberate: per-message strict
34
+ * payload typing is M1-22 codegen territory. ajv enforces the inner
35
+ * shape at runtime; surfacing it through TS now would duplicate
36
+ * conformance work.
37
+ */
38
+ export type WSClientMessage = {
39
+ type: "join_queue";
40
+ data: unknown;
41
+ match_id?: string;
42
+ } | {
43
+ type: "leave_queue";
44
+ data?: unknown;
45
+ match_id?: string;
46
+ } | {
47
+ type: "match_confirm";
48
+ data: unknown;
49
+ match_id?: string;
50
+ } | {
51
+ type: "action";
52
+ match_id: string;
53
+ data: unknown;
54
+ } | {
55
+ type: "runtime_status";
56
+ data: unknown;
57
+ match_id?: string;
58
+ };
59
+ export interface WSClientOptions {
60
+ /** WebSocket URL — e.g. "wss://aifight.ai/api/ws" or
61
+ * "ws://127.0.0.1:<port>/api/ws" in tests. */
62
+ url: string;
63
+ /** In-memory plaintext API key. Caller resolves from credentials.ts
64
+ * (M1-05) before this call; transport never touches keychain. */
65
+ apiKey: string;
66
+ /** Runtime's compiled-in protocol version, SemVer (e.g. "1.0.0"
67
+ * or "v1.0.0"). The optional "v" prefix is stripped before
68
+ * comparison. Major component must match server's
69
+ * server_protocol_version per plan §5.8 / ADR-016. */
70
+ expectedProtocolVersion: string;
71
+ /** Time after WS open() to receive the welcome frame. Default
72
+ * 10_000 ms. Tests can lower for fast-fail coverage. */
73
+ welcomeTimeoutMs?: number;
74
+ /** Client-initiated WS ping frame (opcode 0x9) interval in ms.
75
+ * Default 25_000 (per plan §5.8 / ADR-015 — keeps server's
76
+ * 60s ReadDeadline safely fed). Set to 0 to DISABLE the
77
+ * client-initiated ping entirely (the server's own ping +
78
+ * the `ws` library's automatic pong reply still keep the
79
+ * link alive in that case, but the structural Batch D fix
80
+ * — independent client ping timer — is not active). */
81
+ pingIntervalMs?: number;
82
+ /** Optional caller-controlled AbortSignal. If pre-aborted
83
+ * (signal.aborted=true at the moment createWSClient is called),
84
+ * rejects synchronously with WSAbortedError. If aborted
85
+ * mid-handshake, terminates the socket and rejects with
86
+ * WSAbortedError. If aborted AFTER createWSClient resolves,
87
+ * the WSClient transitions to "closed" (timers cleared,
88
+ * socket terminated) — equivalent to calling close(); no
89
+ * error is thrown since the signal owner is the actor. */
90
+ signal?: AbortSignal;
91
+ }
92
+ export type WSMessageHandler = (msg: ServerMessageEnvelope) => void | Promise<void>;
93
+ /** Frame-level errors surfaced AFTER createWSClient resolves —
94
+ * malformed inbound JSON, schema violations, unknown server
95
+ * message types. Connect / handshake / welcome errors are
96
+ * rejected by createWSClient itself and never reach onError. */
97
+ export type WSErrorHandler = (err: WSClientError) => void | Promise<void>;
98
+ /** Information passed to onClose handlers. The connection is
99
+ * fully torn down by the time this fires; no further onMessage
100
+ * / onError handlers will run. */
101
+ export interface WSCloseInfo {
102
+ /** WS close code from the close frame, or 0 for synthetic
103
+ * closes (abort, transport error before close frame). */
104
+ readonly code: number;
105
+ /** Human-readable reason. For client-initiated close, the
106
+ * string passed to close(); for server-initiated, what the
107
+ * server sent; for abort, the constant "aborted". */
108
+ readonly reason: string;
109
+ /** Who initiated the close: client (close() call), server
110
+ * (server-side close), or abort (AbortSignal fired
111
+ * post-connect). */
112
+ readonly initiator: "client" | "server" | "abort";
113
+ }
114
+ export type WSCloseHandler = (info: WSCloseInfo) => void | Promise<void>;
115
+ /** @internal — passed from createWSClient to WSClientImpl constructor. */
116
+ interface WSClientInternalOpts {
117
+ pingIntervalMs?: number;
118
+ signal?: AbortSignal;
119
+ }
120
+ declare class WSClientImpl {
121
+ #private;
122
+ /** The authenticated welcome frame received from the server. */
123
+ readonly welcome: WSWelcome;
124
+ /**
125
+ * Constructor is REACHABLE only from this module's createWSClient
126
+ * factory. Because WSClientImpl is not exported, consumers of
127
+ * @aifight/aifight cannot `new` it (they only see the
128
+ * `export type WSClient = WSClientImpl` alias, which carries
129
+ * no constructor signature). The `socket` parameter is typed as
130
+ * `unknown` belt-and-suspenders so that even if an internal
131
+ * caller someday passes the wrong shape it fails as a cast
132
+ * mistake rather than a structural type leak.
133
+ *
134
+ * Step 5a additions:
135
+ * - Starts a client-initiated ping timer (default 25s; pass
136
+ * pingIntervalMs=0 to disable).
137
+ * - Wires opts.signal so a post-connect abort triggers a forced
138
+ * close-equivalent transition (state→closed, timer cleared,
139
+ * socket terminated) without throwing — the signal owner is
140
+ * the actor and already knows.
141
+ *
142
+ * Step 5b1 additions:
143
+ * - Re-attaches "message", "error", "close" listeners on the
144
+ * socket (createWSClient's cleanup() removed all listeners
145
+ * during the handshake settle; this is the post-handshake
146
+ * re-attachment Roy flagged in the Step 5b1 brief).
147
+ * - "message" routes through parseServerFrame and dispatches
148
+ * to onMessage / onError handlers.
149
+ * - "close" emits onClose (idempotent via #closeDispatched).
150
+ * - "error" goes to a silent sink; transport errors usually
151
+ * pair with "close" which carries the user-facing signal.
152
+ * Frame-level errors (parse / schema / unknown) come through
153
+ * the message path, not the error event.
154
+ */
155
+ constructor(socket: unknown, welcome: WSWelcome, opts: WSClientInternalOpts);
156
+ /** Current lifecycle state. Step 5b1 expanded to three values:
157
+ * "connected" after createWSClient resolves, "closing" while
158
+ * close() is awaiting the socket close handshake (briefly),
159
+ * "closed" after close completes (or abort / server close
160
+ * fires). M1-07 may add "reconnecting". */
161
+ get state(): "connected" | "closing" | "closed";
162
+ onMessage(handler: WSMessageHandler): () => void;
163
+ onError(handler: WSErrorHandler): () => void;
164
+ onClose(handler: WSCloseHandler): () => void;
165
+ /**
166
+ * Send an outbound message to the server. Synchronous.
167
+ *
168
+ * @throws {WSClosedError} when the client is not in the "connected"
169
+ * state (i.e. close()/abort/server-close has fired).
170
+ * @throws {WSOutboundSchemaError} when `msg` fails ajv validation
171
+ * against client_<type>.schema.json. The error carries the
172
+ * offending message type and the raw ajv error array.
173
+ */
174
+ send(msg: WSClientMessage): void;
175
+ /**
176
+ * Initiate a clean WS close. State transitions
177
+ * connected → closing → closed; onClose fires exactly once when
178
+ * the socket's "close" event arrives.
179
+ *
180
+ * Idempotent semantics:
181
+ * - Calling on a "closing" instance returns the in-flight
182
+ * close promise (so two awaiters share the same await).
183
+ * - Calling on a "closed" instance returns immediately.
184
+ * - Subsequent call after either resolves does nothing.
185
+ */
186
+ close(code?: number, reason?: string): Promise<void>;
187
+ }
188
+ /** The public WSClient type. This is a type alias over the internal
189
+ * WSClientImpl class — consumers can use `WSClient` as a TypeScript
190
+ * type (parameter / return / variable annotation) but cannot
191
+ * construct one directly because no class value with this name is
192
+ * exported. The only way to obtain a WSClient is via the
193
+ * createWSClient() factory. */
194
+ export type WSClient = WSClientImpl;
195
+ /**
196
+ * Open a WebSocket to `opts.url`, send `X-API-Key` in the upgrade
197
+ * request, wait for the server's welcome frame, validate it
198
+ * (ajv + protocol-version major), and return a WSClient bound to
199
+ * the open socket.
200
+ *
201
+ * Resolves on welcome accepted. Rejects with one of:
202
+ * - WSConnectError — TCP/TLS/DNS failure (no HTTP response)
203
+ * - WSHandshakeError — HTTP upgrade returned non-101 (4xx/5xx)
204
+ * - WSWelcomeTimeoutError — open succeeded but no frame within
205
+ * welcomeTimeoutMs (default 10s)
206
+ * - WSWelcomeInvalidError — first frame is not a valid welcome:
207
+ * malformed JSON, unknown type,
208
+ * wrong type, or schema-invalid welcome
209
+ * (ajv errors carried)
210
+ * - WSProtocolVersionError — welcome valid but
211
+ * server_protocol_version major
212
+ * differs from expectedProtocolVersion
213
+ *
214
+ * Step 4 caveats:
215
+ * - No AbortSignal (Step 5).
216
+ * - No reconnect (M1-07).
217
+ * - No retry on any error class — caller decides.
218
+ */
219
+ export declare function createWSClient(opts: WSClientOptions): Promise<WSClient>;
220
+ export {};
@@ -0,0 +1,106 @@
1
+ export interface AjvLikeError {
2
+ readonly instancePath: string;
3
+ readonly message?: string;
4
+ }
5
+ export type WSClientErrorKind = "connect" | "handshake" | "welcome-timeout" | "welcome-invalid" | "protocol-version" | "closed" | "schema" | "outbound-schema" | "unknown-message" | "aborted";
6
+ export declare abstract class WSClientError extends Error {
7
+ abstract readonly kind: WSClientErrorKind;
8
+ }
9
+ /** TCP / TLS / DNS layer failure: the WebSocket couldn't even
10
+ * reach the HTTP upgrade step. Wraps the underlying Node net /
11
+ * tls / dns error (or whatever the `ws` library surfaced). */
12
+ export declare class WSConnectError extends WSClientError {
13
+ readonly kind: "connect";
14
+ readonly cause?: unknown;
15
+ constructor(message: string, cause?: unknown);
16
+ }
17
+ /** HTTP upgrade was attempted and the server replied with an error
18
+ * status (typically 401 invalid api key, 404 wrong path, 5xx
19
+ * server fault). `responseBody` is the raw response payload as a
20
+ * string; callers SHOULD NOT JSON.parse it without checking
21
+ * Content-Type, since some 5xx pages are HTML. */
22
+ export declare class WSHandshakeError extends WSClientError {
23
+ readonly kind: "handshake";
24
+ readonly statusCode: number;
25
+ readonly responseBody: string;
26
+ readonly cause?: unknown;
27
+ constructor(statusCode: number, responseBody: string, message: string, cause?: unknown);
28
+ }
29
+ /** WS open succeeded but no frame arrived within
30
+ * `welcomeTimeoutMs` (default 10s). Distinguished from
31
+ * WSConnectError so callers can differentiate "couldn't reach
32
+ * server" from "reached server but it's not speaking". */
33
+ export declare class WSWelcomeTimeoutError extends WSClientError {
34
+ readonly kind: "welcome-timeout";
35
+ constructor(message: string);
36
+ }
37
+ /** First server frame arrived but is not a valid welcome — wrong
38
+ * type, malformed JSON, or fails ajv against
39
+ * server_welcome.schema.json. `ajvErrors` is the raw ajv error
40
+ * array (or empty for non-ajv failures like "wrong type"). */
41
+ export declare class WSWelcomeInvalidError extends WSClientError {
42
+ readonly kind: "welcome-invalid";
43
+ readonly ajvErrors: readonly AjvLikeError[];
44
+ constructor(ajvErrors: readonly AjvLikeError[], message: string);
45
+ }
46
+ /** server_protocol_version's major component does not match the
47
+ * runtime's compiled-in expectedProtocolVersion. Per plan §5.8 +
48
+ * server_welcome.schema.json the runtime MUST refuse such
49
+ * connections (major bumps are breaking). Minor / patch
50
+ * mismatches do NOT throw this — they are silently accepted. */
51
+ export declare class WSProtocolVersionError extends WSClientError {
52
+ readonly kind: "protocol-version";
53
+ readonly clientVersion: string;
54
+ readonly serverVersion: string;
55
+ constructor(clientVersion: string, serverVersion: string, message: string);
56
+ }
57
+ /** Operation attempted on a WSClient whose state is not
58
+ * "connected": send() during closing, send() after close,
59
+ * close() called twice (this is no-op, not an error — but
60
+ * internal use may distinguish). */
61
+ export declare class WSClosedError extends WSClientError {
62
+ readonly kind: "closed";
63
+ constructor(message: string);
64
+ }
65
+ /** Inbound frame failed ajv validation against its
66
+ * per-message schema. Indicates server bug or protocol drift —
67
+ * surfaced to onError handler; the connection stays open and
68
+ * the offending message is dropped. `messageType` is the
69
+ * envelope's `type` field if parseable, else "<unknown>". */
70
+ export declare class WSSchemaError extends WSClientError {
71
+ readonly kind: "schema";
72
+ readonly messageType: string;
73
+ readonly ajvErrors: readonly AjvLikeError[];
74
+ constructor(messageType: string, ajvErrors: readonly AjvLikeError[], message: string);
75
+ }
76
+ /** Outbound message passed to send() failed ajv validation
77
+ * against the matching client_*.schema.json. Indicates LOCAL
78
+ * code bug (we tried to send something the server would
79
+ * reject) — thrown synchronously to the calling code, message
80
+ * never reaches the wire. Kept distinct from WSSchemaError
81
+ * because callers MUST treat it as a programming error, not a
82
+ * runtime drift signal. */
83
+ export declare class WSOutboundSchemaError extends WSClientError {
84
+ readonly kind: "outbound-schema";
85
+ readonly messageType: string;
86
+ readonly ajvErrors: readonly AjvLikeError[];
87
+ constructor(messageType: string, ajvErrors: readonly AjvLikeError[], message: string);
88
+ }
89
+ /** Inbound frame's `type` field is not in the dispatch table
90
+ * (see protocol/schemas.ts MESSAGE_TYPE_TO_FILE). Server bug
91
+ * or version skew — surfaced to onError, message dropped,
92
+ * connection stays open. */
93
+ export declare class WSUnknownMessageError extends WSClientError {
94
+ readonly kind: "unknown-message";
95
+ readonly messageType: string;
96
+ constructor(messageType: string, message: string);
97
+ }
98
+ /** The caller-controlled AbortSignal fired during connect() or a
99
+ * mid-flight operation. `cause` carries the abort reason
100
+ * (AbortSignal.reason) so callers can distinguish their own
101
+ * abort categories without parsing message text. */
102
+ export declare class WSAbortedError extends WSClientError {
103
+ readonly kind: "aborted";
104
+ readonly cause?: unknown;
105
+ constructor(message: string, cause?: unknown);
106
+ }
@@ -0,0 +1,20 @@
1
+ export interface ClientMessageEnvelope {
2
+ type: string;
3
+ data?: unknown;
4
+ /** REQUIRED for type=action (per client_action.schema.json), optional otherwise. */
5
+ match_id?: string;
6
+ }
7
+ export interface ServerMessageEnvelope {
8
+ type: string;
9
+ data: unknown;
10
+ match_id?: string;
11
+ }
12
+ /** Warm the ajv cache up-front. Optional — getAjv() is lazy and
13
+ * serializeClientMessage / parseServerFrame call it on first use. */
14
+ export declare function initFrameHandler(): void;
15
+ /** Test-only: drop the ajv singleton so the next getAjv() call
16
+ * rewalks loadAllSchemas(). Pairs with __resetSchemasRootCache()
17
+ * in protocol/schemas.ts. NOT exported from src/index.ts. */
18
+ export declare function __resetFrameHandlerCache(): void;
19
+ export declare function serializeClientMessage(msg: ClientMessageEnvelope): string;
20
+ export declare function parseServerFrame(raw: string | Buffer): ServerMessageEnvelope;
@@ -0,0 +1,84 @@
1
+ import { type WSClientMessage, type WSWelcome, type WSMessageHandler, type WSErrorHandler } from "./client";
2
+ import { WSClientError } from "./errors";
3
+ /** Reasons the reconnect facade can transition to terminal "closed" state.
4
+ * ReconnectCloseInfo.kind and ReconnectStoppedError.kind share this union —
5
+ * 5 values used consistently across onClose handler, give-up event, and
6
+ * cause chain (rev 2 Codex C4). */
7
+ export type ReconnectStopReason = "caller-close" | "signal" | "fatal-close" | "fatal-error" | "max-attempts";
8
+ /** Inline error class — reconnect's own final-state error. Lives at the top
9
+ * of reconnect.ts, NOT in wsclient/errors.ts (scope fence #1).
10
+ * rev 2 Codex C4: renamed from ReconnectAbortedError to ReconnectStoppedError. */
11
+ export declare class ReconnectStoppedError extends Error {
12
+ readonly name = "ReconnectStoppedError";
13
+ readonly kind: ReconnectStopReason;
14
+ readonly cause: WSClientError | undefined;
15
+ constructor(kind: ReconnectStopReason, cause: WSClientError | undefined, message: string);
16
+ }
17
+ /** Terminal-close info passed to facade.onClose handler (rev 2 Codex C3).
18
+ * NOT a re-use of M1-06 WSCloseInfo — facade close semantics are wider than
19
+ * a single WS close frame. **No wasClean field** (M1-06 WSCloseInfo also
20
+ * doesn't have one; rev 1 wrote it incorrectly, rev 2 removed). */
21
+ export interface ReconnectCloseInfo {
22
+ readonly kind: ReconnectStopReason;
23
+ readonly code?: number;
24
+ readonly closeReason?: string;
25
+ readonly cause?: WSClientError | ReconnectStoppedError;
26
+ }
27
+ export type ReconnectCloseHandler = (info: ReconnectCloseInfo) => void;
28
+ /** Backoff jitter strategy. Default "full" (rev 2 Roy 拍板 #2). */
29
+ export type JitterStrategy = "none" | "full" | "equal";
30
+ export interface ReconnectingWSClientOptions {
31
+ url: string;
32
+ apiKey: string;
33
+ expectedProtocolVersion: string;
34
+ initialBackoffMs?: number;
35
+ backoffFactor?: number;
36
+ maxBackoffMs?: number;
37
+ jitter?: JitterStrategy;
38
+ /** Default: undefined → no cap (Roy 拍板 #3). Caller controls termination
39
+ * via signal + AbortController.abort(timeoutMs). */
40
+ maxAttempts?: number;
41
+ welcomeTimeoutMs?: number;
42
+ pingIntervalMs?: number;
43
+ signal?: AbortSignal;
44
+ }
45
+ export interface ReconnectEvent {
46
+ readonly type: "attempt-start" | "attempt-success" | "attempt-failure" | "give-up";
47
+ readonly attempt: number;
48
+ readonly nextDelayMs?: number;
49
+ readonly cause?: WSClientError | ReconnectStoppedError;
50
+ readonly elapsedMs: number;
51
+ readonly severity: "info" | "warning" | "error";
52
+ }
53
+ export type ReconnectEventHandler = (ev: ReconnectEvent) => void;
54
+ /** Stable facade — caller holds this reference indefinitely. Inner WSClient
55
+ * is mutable across reconnects; facade type is stable. */
56
+ export interface ReconnectingWSClient {
57
+ readonly state: "connecting" | "connected" | "backoff" | "closed";
58
+ readonly attempt: number;
59
+ readonly welcome: WSWelcome | null;
60
+ send(msg: WSClientMessage): void;
61
+ onMessage(handler: WSMessageHandler): () => void;
62
+ onError(handler: WSErrorHandler): () => void;
63
+ onClose(handler: ReconnectCloseHandler): () => void;
64
+ onReconnect(handler: ReconnectEventHandler): () => void;
65
+ close(code?: number, reason?: string): Promise<void>;
66
+ }
67
+ /**
68
+ * Open a reconnecting WebSocket session. Returns a Promise that:
69
+ *
70
+ * - **resolves** on the FIRST inner WSClient connect+welcome success
71
+ * - **rejects** with ReconnectStoppedError on fatal first failure (signal
72
+ * pre-aborted / WSHandshakeError 401|403|404 / WSWelcomeInvalidError /
73
+ * WSProtocolVersionError / WSAbortedError / max-attempts during the
74
+ * first-connect retry chain)
75
+ * - **stays pending** while transient first failures (WSConnectError /
76
+ * WSWelcomeTimeoutError / WSHandshakeError 408|429|5xx) drive backoff
77
+ * and re-attempt, until a success or fatal terminator
78
+ *
79
+ * After the Promise resolves, the returned facade survives across server
80
+ * disconnects: inner WSClient close → backoff → new createWSClient →
81
+ * handlers re-wired. Caller's onMessage / onError / onClose / onReconnect
82
+ * handlers persist across reconnects automatically.
83
+ */
84
+ export declare function createReconnectingWSClient(opts: ReconnectingWSClientOptions): Promise<ReconnectingWSClient>;
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@aifight/aifight",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "AIFight CLI — local outbound bridge that connects AIFight to user-selected Agent runtimes.",
5
+ "type": "module",
6
+ "main": "./dist/index.mjs",
7
+ "types": "./dist/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types/index.d.ts",
11
+ "import": "./dist/index.mjs"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "bin": {
16
+ "aifight": "dist/bin.mjs",
17
+ "aifight-bridge": "dist/bin.mjs"
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "engines": {
27
+ "node": ">=20.19"
28
+ },
29
+ "devDependencies": {
30
+ "@types/better-sqlite3": "7.6.13",
31
+ "@types/node": "^22.10.0",
32
+ "@types/ws": "8.18.1",
33
+ "ajv": "^8.17.1",
34
+ "ajv-formats": "^3.0.1",
35
+ "esbuild": "^0.24.0",
36
+ "typescript": "^5.6.0",
37
+ "vitest": "^2.1.0",
38
+ "ws": "8.20.0"
39
+ },
40
+ "scripts": {
41
+ "build": "./build.sh",
42
+ "gen:schema": "node scripts/bundle-schema.mjs",
43
+ "pack:check": "node scripts/verify-packlist.mjs",
44
+ "prepublishOnly": "npm run build && npm run pack:check",
45
+ "test": "npm run gen:schema && vitest run",
46
+ "check-types": "npm run gen:schema && tsc --noEmit -p tsconfig.json"
47
+ },
48
+ "dependencies": {
49
+ "@modelcontextprotocol/sdk": "^1.29.0",
50
+ "@napi-rs/keyring": "1.2.0",
51
+ "better-sqlite3": "12.9.0"
52
+ }
53
+ }