@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,64 @@
1
+ /** Service platform identifier — combines OS + service manager.
2
+ * - "linux-systemd-user": Linux with `systemctl --user` reachable.
3
+ * - "darwin-launchd-user": macOS with `launchctl` reachable.
4
+ * - "unsupported": Windows native, Linux without systemd `--user`,
5
+ * macOS without launchctl, or any other POSIX. */
6
+ export type ServicePlatform = "linux-systemd-user" | "darwin-launchd-user" | "unsupported";
7
+ /** install() options. Passed from `runServiceInstall` handler to the
8
+ * selected `ServiceTarget` (systemd or launchd).
9
+ *
10
+ * rev4 contract:
11
+ * - `autoStart=false` (--no-start) on linux: skip `systemctl start` after enable.
12
+ * - `autoStart=false` (--no-start) on launchd: plist writes RunAtLoad=false,
13
+ * still runs `launchctl bootstrap` (registers LaunchAgent) but skips kickstart.
14
+ * - `printOnly=true` (--print): generator emits unit/plist text to stdout,
15
+ * writes nothing, runs no systemctl/launchctl. exit 0.
16
+ * - `envFile` is systemd-only; darwin handlers exit 2 with
17
+ * `client_env_file_unsupported_on_darwin` BEFORE createLaunchdTarget. */
18
+ export interface ServiceInstallOptions {
19
+ readonly autoStart: boolean;
20
+ readonly printOnly: boolean;
21
+ readonly envFile?: string;
22
+ }
23
+ /** uninstall() options. */
24
+ export interface ServiceUninstallOptions {
25
+ /** When true, also `rm -rf $AIFIGHT_RUNTIME_HOME` after stop+disable+removing
26
+ * unit/plist (拍板点 #8). Plain `--purge` flag is the user's destructive
27
+ * opt-in; handler prints a warning line in human mode but does NOT prompt. */
28
+ readonly purge: boolean;
29
+ }
30
+ /** status() result — three-state contract (拍板点 #6). */
31
+ export type ServiceStatus = {
32
+ kind: "not_installed";
33
+ } | {
34
+ kind: "stopped";
35
+ /** Optional sub-status from the underlying service manager:
36
+ * - systemd: `is-active` raw output (`inactive` / `failed` / `activating` / ...)
37
+ * - launchd: parsed state (`waiting` / `unknown` / ...) */
38
+ substatus?: string;
39
+ } | {
40
+ kind: "running";
41
+ /** systemd: parsed `MainPID`; launchd: parsed `pid`.
42
+ * Best-effort; absent when parser fails (Open Question #6). */
43
+ pid?: number;
44
+ /** systemd: parsed `ActiveEnterTimestamp`; launchd: not always available.
45
+ * ISO 8601 string when present. */
46
+ since?: string;
47
+ };
48
+ /** Common shape for systemd + launchd targets. The handlers in
49
+ * `service-install.ts` consume this interface; both target factories
50
+ * (`createSystemdTarget` + `createLaunchdTarget`) return implementations. */
51
+ export interface ServiceTarget {
52
+ /** Absolute path of the generated unit/plist:
53
+ * - systemd: `~/.config/systemd/user/aifight.service`
54
+ * - launchd: `~/Library/LaunchAgents/ai.aifight.runtime.plist` */
55
+ readonly unitPath: string;
56
+ /** Pure — produces the unit/plist text. Used for `--print` dry-run +
57
+ * snapshot tests + diff detection on existing files. */
58
+ generate(): string;
59
+ install(opts: ServiceInstallOptions): Promise<void>;
60
+ uninstall(opts: ServiceUninstallOptions): Promise<void>;
61
+ start(): Promise<void>;
62
+ stop(): Promise<void>;
63
+ status(): Promise<ServiceStatus>;
64
+ }
@@ -0,0 +1,29 @@
1
+ import type { HandlerArgs, HandlerEnv } from "../shared";
2
+ import { type OsPlatform, type ServiceExecFile } from "./service/platform";
3
+ export type ServiceErrorCode = "client_unsupported_flag" | "client_platform_unsupported" | "client_service_manager_missing" | "client_env_file_missing" | "client_env_file_unsupported_on_darwin" | "client_already_installed_diff" | "client_not_installed" | "client_aifight_exec_unresolved" | "client_install_failed" | "client_uninstall_failed" | "client_start_failed" | "client_stop_failed";
4
+ export declare function emitServiceError(env: HandlerEnv, jsonMode: boolean, exitCode: number, code: ServiceErrorCode, humanMessage: string, hint?: string): number;
5
+ export declare function resolveAifightExec(candidate: string | undefined, execFile: ServiceExecFile): Promise<string>;
6
+ export interface ServiceDeps {
7
+ /** ExecFile injection for tests. Defaults to `defaultExecFile`. */
8
+ readonly execFile?: ServiceExecFile;
9
+ /** Pre-resolved aifight binary path. When provided, the install
10
+ * handler skips `resolveAifightExec(process.argv[1], ...)` —
11
+ * necessary in tests because `process.argv[1]` typically points at
12
+ * the vitest worker, not a real aifight binary. */
13
+ readonly aifightExec?: string;
14
+ /** OS platform override for tests. Defaults to `detectOsPlatform()`. */
15
+ readonly osPlatform?: OsPlatform;
16
+ /** Effective UID for `gui/$UID` selector on darwin. Defaults to
17
+ * `process.getuid?.() ?? 0`. */
18
+ readonly uid?: number;
19
+ /** Path overrides — production picks under `~`. Tests inject tmp dirs. */
20
+ readonly systemdUnitPath?: string;
21
+ readonly launchdPlistPath?: string;
22
+ readonly launchdLogDir?: string;
23
+ readonly runtimeHome?: string;
24
+ }
25
+ export declare function runServiceInstall(args: HandlerArgs, env: HandlerEnv, deps?: ServiceDeps): Promise<number>;
26
+ export declare function runServiceUninstall(args: HandlerArgs, env: HandlerEnv, deps?: ServiceDeps): Promise<number>;
27
+ export declare function runServiceStart(args: HandlerArgs, env: HandlerEnv, deps?: ServiceDeps): Promise<number>;
28
+ export declare function runServiceStop(args: HandlerArgs, env: HandlerEnv, deps?: ServiceDeps): Promise<number>;
29
+ export declare function runServiceStatus(args: HandlerArgs, env: HandlerEnv, deps?: ServiceDeps): Promise<number>;
@@ -0,0 +1,2 @@
1
+ import type { HandlerArgs, HandlerEnv } from "../shared";
2
+ export declare function runSetup(args: HandlerArgs, env: HandlerEnv): Promise<number>;
@@ -0,0 +1,2 @@
1
+ import type { HandlerArgs, HandlerEnv } from "../shared";
2
+ export declare function runShutdown(args: HandlerArgs, env: HandlerEnv): Promise<number>;
@@ -0,0 +1,24 @@
1
+ import type { HandlerArgs, HandlerEnv } from "../shared";
2
+ interface PureStubOptions {
3
+ /** User-visible canonical name, e.g. "setup" / "service install" / "results". */
4
+ readonly command: string;
5
+ readonly arityMin: number;
6
+ readonly arityMax: number;
7
+ readonly usage: string;
8
+ /** Tier B carries milestone (e.g. "M1-18 daemon lifecycle"); Tier C omits. */
9
+ readonly milestone?: string;
10
+ }
11
+ /** Factory that returns a Tier B / Tier C stub handler. */
12
+ export declare function pureStub(opts: PureStubOptions): (args: HandlerArgs, env: HandlerEnv) => Promise<number>;
13
+ export declare function tierBStub(command: string, milestone: string, arity?: {
14
+ readonly min: number;
15
+ readonly max: number;
16
+ }, usage?: string): (args: HandlerArgs, env: HandlerEnv) => Promise<number>;
17
+ export declare function tierCStub(command: string, arity?: {
18
+ readonly min: number;
19
+ readonly max: number;
20
+ }, usage?: string): (args: HandlerArgs, env: HandlerEnv) => Promise<number>;
21
+ export declare function runAgentAdd(args: HandlerArgs, env: HandlerEnv): Promise<number>;
22
+ export declare function runAgentRemove(args: HandlerArgs, env: HandlerEnv): Promise<number>;
23
+ export declare function doctorFixSkillOverrideStub(): (args: HandlerArgs, env: HandlerEnv) => Promise<number>;
24
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { HandlerArgs, HandlerEnv } from "../shared";
2
+ export declare function runVersion(args: HandlerArgs, env: HandlerEnv): Promise<number>;
@@ -0,0 +1,59 @@
1
+ export type ControlErrorCodeLocal = "unauthorized" | "not_found" | "method_not_allowed" | "bad_request" | "unsupported_media_type" | "payload_too_large" | "not_implemented" | "service_unavailable" | "internal_error";
2
+ export declare function isControlErrorCode(x: unknown): x is ControlErrorCodeLocal;
3
+ export interface ControlErrorBodyLocal {
4
+ readonly error: {
5
+ readonly code: ControlErrorCodeLocal;
6
+ readonly message: string;
7
+ readonly details?: Readonly<Record<string, unknown>>;
8
+ };
9
+ }
10
+ export declare function isControlErrorBody(x: unknown): x is ControlErrorBodyLocal;
11
+ export type ControlClientErrorKind = "daemon_unreachable" | "runtime_files_corrupt" | "auth_failed" | "request_timeout" | "server_error" | "transport_unparseable";
12
+ export interface ControlClientErrorInit {
13
+ readonly serverCode?: ControlErrorCodeLocal;
14
+ readonly status?: number;
15
+ readonly body?: unknown;
16
+ readonly cause?: unknown;
17
+ }
18
+ export declare class ControlClientError extends Error {
19
+ readonly name = "ControlClientError";
20
+ readonly kind: ControlClientErrorKind;
21
+ readonly serverCode?: ControlErrorCodeLocal;
22
+ readonly status: number;
23
+ readonly body?: unknown;
24
+ readonly cause?: unknown;
25
+ constructor(kind: ControlClientErrorKind, message: string, init?: ControlClientErrorInit);
26
+ }
27
+ export interface ControlClient {
28
+ /** GET <path>. Returns parsed JSON body. 4xx/5xx → throw ControlClientError. */
29
+ get<T = unknown>(path: string): Promise<T>;
30
+ /** POST <path> with body.
31
+ * - body === undefined → no Content-Type / no payload (use this for
32
+ * /shutdown, /pause, /resume, /leave).
33
+ * - body === null → Content-Type: application/json + literal "null".
34
+ * - object → Content-Type: application/json + JSON.stringify. */
35
+ post<T = unknown>(path: string, body?: unknown): Promise<T>;
36
+ /** DELETE <path>. */
37
+ delete<T = unknown>(path: string): Promise<T>;
38
+ }
39
+ export interface CreateControlClientOptions {
40
+ /** Sync, lazy — invoked at the moment of each request, NOT at client
41
+ * construction. Construction MUST succeed even if the source would
42
+ * throw, so bridge-independent commands (version / --help / doctor)
43
+ * can construct a client without a running Bridge. */
44
+ readonly tokenSource: () => string;
45
+ /** Same lazy semantics + same wrap-at-boundary contract as tokenSource. */
46
+ readonly portSource: () => number;
47
+ /** Default "127.0.0.1". */
48
+ readonly host?: string;
49
+ /** Per-request timeout. Default 10000 ms. */
50
+ readonly baseTimeoutMs?: number;
51
+ /** Injectable for tests. Default globalThis.fetch. */
52
+ readonly fetchImpl?: typeof fetch;
53
+ /** Optional log hook (rebootstrap reason etc.). MUST NOT receive token. */
54
+ readonly onLog?: (event: {
55
+ code: string;
56
+ message: string;
57
+ }) => void;
58
+ }
59
+ export declare function createControlClient(opts: CreateControlClientOptions): ControlClient;
@@ -0,0 +1,52 @@
1
+ /** Minimal duck-type of M1-16 SanitizedAgentSnapshot we render. */
2
+ interface AgentSnapshotLike {
3
+ readonly name: string;
4
+ readonly started: boolean;
5
+ readonly stopped: boolean;
6
+ readonly transport?: string;
7
+ readonly state: AgentStateLike | null;
8
+ }
9
+ interface AgentStateLike {
10
+ readonly phase?: string;
11
+ readonly agentId?: string;
12
+ readonly agentName?: string;
13
+ readonly availableGames?: readonly string[];
14
+ readonly autoConfirmMatches?: boolean;
15
+ readonly queue?: {
16
+ readonly game: string;
17
+ readonly mode: string;
18
+ };
19
+ readonly activeMatch?: {
20
+ readonly sessionId: string;
21
+ readonly game: string;
22
+ readonly startedAt: number;
23
+ };
24
+ }
25
+ interface DailyScheduleConfigLike {
26
+ readonly enabled: boolean;
27
+ readonly timezone: string;
28
+ readonly minIntervalSec?: number;
29
+ readonly days: Readonly<Record<string, {
30
+ readonly count: number;
31
+ }>>;
32
+ }
33
+ export declare function formatAgentTable(agents: readonly AgentSnapshotLike[]): string;
34
+ export declare function formatAgentStatus(agent: AgentSnapshotLike): string;
35
+ interface ScheduleSnapshotLike {
36
+ readonly running: boolean;
37
+ /** YYYY-MM-DD local date (M1-15 DailySchedulerSnapshot.today) or null
38
+ * when scheduler has not yet computed the boundary. */
39
+ readonly today?: string | null;
40
+ readonly remaining?: Readonly<Record<string, number>>;
41
+ readonly nextFireInMs?: number | null;
42
+ readonly lastAttempt?: {
43
+ readonly outcome?: string;
44
+ readonly game?: string | null;
45
+ readonly atMs?: number;
46
+ } | null;
47
+ }
48
+ export declare function formatScheduleShow(cfg: DailyScheduleConfigLike | null, snap: ScheduleSnapshotLike): string;
49
+ /** Compose a JSON-mode error envelope. Used by main.ts error funnel and
50
+ * by handlers that surface a usage error in JSON mode. */
51
+ export declare function jsonErrorEnvelope(code: string, message: string, details?: Readonly<Record<string, unknown>>): string;
52
+ export {};
@@ -0,0 +1,18 @@
1
+ import type { HelloResult } from "../index";
2
+ import type { BridgeServiceDeps } from "../bridge/service";
3
+ export interface RunOptions {
4
+ readonly stdout?: (s: string) => void;
5
+ readonly stderr?: (s: string) => void;
6
+ /** Override for M1-01 hello() (used by doctor schemas check). */
7
+ readonly hello?: () => HelloResult;
8
+ /** Override fetch (used by tests). */
9
+ readonly fetchImpl?: typeof fetch;
10
+ /** Reserved for injected command handlers that need a shorter network timeout. */
11
+ readonly baseTimeoutMs?: number;
12
+ readonly onLog?: (event: {
13
+ code: string;
14
+ message: string;
15
+ }) => void;
16
+ readonly bridgeService?: BridgeServiceDeps;
17
+ }
18
+ export declare function run(argv: readonly string[], opts?: RunOptions): Promise<number>;
@@ -0,0 +1,11 @@
1
+ export type RuntimeFilesErrorKind = "token_missing" | "port_missing" | "token_corrupt" | "port_corrupt";
2
+ export declare class RuntimeFilesError extends Error {
3
+ readonly name = "RuntimeFilesError";
4
+ readonly kind: RuntimeFilesErrorKind;
5
+ readonly filePath: string;
6
+ constructor(kind: RuntimeFilesErrorKind, filePath: string, message: string);
7
+ }
8
+ export declare function tokenFilePath(): string;
9
+ export declare function portFilePath(): string;
10
+ export declare function readToken(): string;
11
+ export declare function readPort(): number;
@@ -0,0 +1,74 @@
1
+ import type { ControlClient, CreateControlClientOptions } from "./control-client";
2
+ import type { HelloResult } from "../index";
3
+ import type { BridgeServiceDeps } from "../bridge/service";
4
+ /** Per-handler injectable environment. Defaults wired to process I/O +
5
+ * real fs + native fetch. Tests pass overrides for stdout/stderr capture
6
+ * + hello stub + fetchImpl pointing at a temporary M1-16 server. */
7
+ export interface HandlerEnv {
8
+ readonly stdout: (s: string) => void;
9
+ readonly stderr: (s: string) => void;
10
+ /** Override for the M1-01 schemas/types self-test used by `doctor`.
11
+ * Default: real `hello` from runtime/src/index.ts (lazy-imported by
12
+ * the doctor handler so other commands do not pull in the
13
+ * schemas-loading cost). */
14
+ readonly hello?: () => HelloResult;
15
+ /** Override fetch implementation for tests. Default globalThis.fetch. */
16
+ readonly fetchImpl?: typeof fetch;
17
+ /** Optional rebootstrap log hook (forwarded to control-client). */
18
+ readonly onLog?: (event: {
19
+ code: string;
20
+ message: string;
21
+ }) => void;
22
+ /** Default 10000 ms per Step 2b directive (must not drop below ~3000
23
+ * for normal commands). doctor uses its own 3000 ms one-shot fetch. */
24
+ readonly baseTimeoutMs?: number;
25
+ /** Optional bridge service manager overrides for tests and controlled installs. */
26
+ readonly bridgeService?: BridgeServiceDeps;
27
+ }
28
+ export interface HandlerArgs {
29
+ /** Positional argv with the command (and subcommand for `agent`/`daily`)
30
+ * already stripped by the dispatcher in main.ts. */
31
+ readonly positional: readonly string[];
32
+ /** All globally-known flags merged from the single argv pass. */
33
+ readonly flags: Readonly<Record<string, string | number | boolean>>;
34
+ /** True when `--json` was set (any position — floating flag, rev2 fix #1). */
35
+ readonly jsonMode: boolean;
36
+ }
37
+ /** Build a controlClient that lazily reads token+port from the daemon
38
+ * files. version / doctor / Tier B/C stubs do NOT call this. */
39
+ export declare function makeClient(env: HandlerEnv, extra?: Partial<CreateControlClientOptions>): ControlClient;
40
+ /** Centralised game enum for client-side validation (Risks #11 — CLI
41
+ * hard-codes the supported list rather than fetching from server, so a
42
+ * contract drift surfaces as a usage error rather than a daemon round
43
+ * trip). */
44
+ export declare const SUPPORTED_GAMES: ReadonlyArray<string>;
45
+ export declare function isSupportedGame(g: string): boolean;
46
+ /** Class for argv-parser-style usage errors that should map to exit 2.
47
+ * Distinct from AgentResolverError (which uses its own kind discriminator). */
48
+ export declare class UsageError extends Error {
49
+ readonly name = "UsageError";
50
+ readonly hint?: string;
51
+ constructor(message: string, hint?: string);
52
+ }
53
+ /** Expected runtime/API failures that should be shown as ordinary command
54
+ * errors (exit 1), not catchall programmer failures (exit 99). */
55
+ export declare class CommandError extends Error {
56
+ readonly name = "CommandError";
57
+ readonly code: string;
58
+ readonly exitCode: number;
59
+ readonly hint?: string;
60
+ constructor(code: string, message: string, opts?: {
61
+ readonly exitCode?: number;
62
+ readonly hint?: string;
63
+ });
64
+ }
65
+ /** Step 3b — assert positional arity at the top of every handler BEFORE
66
+ * any side-effect (controlClient / network / fs). Extra positionals
67
+ * must NOT silently fall through to a successful POST (e.g.
68
+ * `aifight shutdown anything` previously still POSTed /v1/shutdown).
69
+ *
70
+ * Throws UsageError → main.ts funnel maps to exit 2 + usage hint.
71
+ * No-args handlers call `expectArity(args, 0, 0, "...")`;
72
+ * optional-arg handlers (e.g. agent status [<name>]) use min=0 max=1;
73
+ * fixed-arity handlers (e.g. daily set <game> <count>) use min=max=N. */
74
+ export declare function expectArity(args: HandlerArgs, min: number, max: number, usage: string): void;
@@ -0,0 +1,49 @@
1
+ export interface ProfileRouteDeps {
2
+ /**
3
+ * Resolve the on-disk directory for an agent slug.
4
+ * Defaults to resolveAgentDir from profile-loader.
5
+ */
6
+ resolveAgentDir?: (slug: string) => string;
7
+ /**
8
+ * List session IDs for an agent from the daemon's active state.
9
+ * Returns [] when the daemon has no state for this slug or the function
10
+ * is not wired (stubs for CLI-only deployments).
11
+ */
12
+ listSessions?: (agentSlug: string) => SessionSummary[];
13
+ /**
14
+ * Fetch a single session summary by sessionId.
15
+ * Returns null when the session is not found.
16
+ */
17
+ getSessionSummary?: (sessionId: string) => SessionSummary | null;
18
+ }
19
+ export interface SessionSummary {
20
+ readonly sessionId: string;
21
+ readonly agentSlug: string;
22
+ readonly game: string;
23
+ readonly startedAt: number;
24
+ readonly endedAt?: number;
25
+ readonly outcome?: "win" | "loss" | "draw" | "forfeit" | string;
26
+ readonly ratingDelta?: number;
27
+ }
28
+ export interface ProfileHandlerContext {
29
+ readonly params: Readonly<Record<string, string>>;
30
+ readonly body: unknown;
31
+ }
32
+ export interface ProfileRouteResult {
33
+ readonly status: number;
34
+ readonly body: unknown;
35
+ }
36
+ declare class ProfileRouteError extends Error {
37
+ readonly name = "ProfileRouteError";
38
+ readonly status: number;
39
+ readonly code: string;
40
+ readonly details?: Record<string, unknown>;
41
+ constructor(status: number, code: string, message: string, details?: Record<string, unknown>);
42
+ }
43
+ export interface ProfileRoute {
44
+ readonly method: "GET" | "POST";
45
+ readonly path: string;
46
+ readonly handle: (ctx: ProfileHandlerContext) => Promise<ProfileRouteResult>;
47
+ }
48
+ export declare function createProfileRoutes(deps?: ProfileRouteDeps): ProfileRoute[];
49
+ export { ProfileRouteError };
@@ -0,0 +1,3 @@
1
+ import type { ControlAgentHandle, ControlRouterTarget, ControlServer, ControlServerOptions } from "./types";
2
+ export declare function createControlServer(opts: ControlServerOptions): ControlServer;
3
+ export type { ControlAgentHandle, ControlRouterTarget };
@@ -0,0 +1,136 @@
1
+ import type { AgentInstanceSnapshot } from "../agents/agent";
2
+ import type { DailyScheduler } from "../scheduler/daily";
3
+ import type { DailyScheduleConfig } from "../scheduler/types";
4
+ export interface ControlAgentHandle {
5
+ snapshot(): AgentInstanceSnapshot;
6
+ }
7
+ export interface ControlJoinQueueOptions {
8
+ readonly oneShot?: boolean;
9
+ readonly count?: number;
10
+ }
11
+ export interface ControlRouterTarget {
12
+ listAgents(): readonly AgentInstanceSnapshot[];
13
+ /** Throws RouterAgentNotFoundError when no agent matches. Handler
14
+ * catches by `error.kind === "router_agent_not_found"` (duck-typed,
15
+ * no instanceof) and maps to HTTP 404. Other RouterError kinds map
16
+ * to 500 internal_error. */
17
+ getAgent(selector: {
18
+ readonly name: string;
19
+ }): ControlAgentHandle;
20
+ joinQueue(selector: {
21
+ readonly name: string;
22
+ }, game: string, mode?: string, opts?: ControlJoinQueueOptions): void;
23
+ leaveQueue(selector: {
24
+ readonly name: string;
25
+ }): void;
26
+ }
27
+ export type ControlLogLevel = "info" | "warn" | "error";
28
+ export type ControlLogCode = "server_listening" | "server_closed" | "request_received" | "request_completed" | "auth_failed" | "handler_threw" | "shutdown_requested";
29
+ export interface ControlLogEvent {
30
+ readonly level: ControlLogLevel;
31
+ readonly code: ControlLogCode;
32
+ readonly message: string;
33
+ readonly method?: string;
34
+ readonly path?: string;
35
+ readonly status?: number;
36
+ readonly durationMs?: number;
37
+ readonly host?: string;
38
+ readonly port?: number;
39
+ /** auth_failed: missing_header | invalid_format | token_mismatch | token_unset */
40
+ readonly reason?: string;
41
+ readonly cause?: unknown;
42
+ }
43
+ export interface ControlServerOptions {
44
+ /** Default "127.0.0.1". server binds 127.0.0.1 only — no remote
45
+ * exposure path in M1; TLS / remote access is M5+ scope. */
46
+ readonly host?: string;
47
+ /** Default 0 → OS picks an unused port; resolve via address(). */
48
+ readonly port?: number;
49
+ /** Sync, called per request to fetch the currently-valid Bearer
50
+ * token. Returning null → 401 token_unset (daemon has not generated
51
+ * the token file yet, or rotated it). M1-18 daemon lifecycle wires
52
+ * this to a cached token-file reader. */
53
+ readonly tokenSource: () => string | null;
54
+ readonly router: ControlRouterTarget;
55
+ /** agent name → that agent's DailyScheduler. Returning null →
56
+ * schedule endpoint returns 404 not_found (rev3 fix #2 —
57
+ * resolveScheduler helper enforces). */
58
+ readonly schedulerLookup?: (agentName: string) => DailyScheduler | null;
59
+ /** rev2 fix #4 — daemon source-of-truth current cfg reader. Used by
60
+ * GET /schedule + POST /pause + POST /resume when the server's
61
+ * internal lastSetSchedules cache misses (e.g. first POST /pause
62
+ * after daemon startup with strategy.json initial schedule). May
63
+ * return null when the agent has no configured schedule yet. */
64
+ readonly scheduleConfigLookup?: (agentName: string) => DailyScheduleConfig | null;
65
+ /** rev4 fix — daemon graceful stop callback. May return void or
66
+ * Promise<void>. The server calls it via:
67
+ * setImmediate(() => {
68
+ * Promise.resolve()
69
+ * .then(() => opts.onShutdown?.())
70
+ * .catch((cause) => safeLog({code:"handler_threw", level:"error", cause, ...}));
71
+ * });
72
+ * so neither a synchronous throw NOR a rejected Promise can escape
73
+ * as an unhandled rejection — both are funnelled through .catch
74
+ * into safeLog. The client has already received the 200 response by
75
+ * then, and the failure is logged via onLog without crashing the
76
+ * server.
77
+ *
78
+ * rev3 wrote this as `Promise.resolve(opts.onShutdown?.()).catch(...)`
79
+ * which only caught async rejections — a synchronous throw escaped
80
+ * the setImmediate callback because `opts.onShutdown?.()` is
81
+ * evaluated BEFORE `Promise.resolve(...)` runs, so the throw never
82
+ * reaches Promise.resolve at all. The corrected `.then(() => ...)`
83
+ * shape relies on the standard Promise behavior that any throw
84
+ * inside a `.then` callback is automatically converted to a
85
+ * rejected Promise (and any returned rejected Promise is propagated),
86
+ * so `.catch` reliably covers both shapes with one path. */
87
+ readonly onShutdown?: () => Promise<void> | void;
88
+ /** Called on lifecycle / request / auth events. Wrapped via safeLog
89
+ * internally; throws are swallowed so a faulty logger cannot crash
90
+ * the server (matches M1-15 onNotify pattern). */
91
+ readonly onLog?: (event: ControlLogEvent) => void;
92
+ /** Default 1_048_576 (1 MiB). parseJsonBody aborts and returns 413
93
+ * payload_too_large past this; rev3 fix #4 requires the 413
94
+ * response to be flushed BEFORE any best-effort req.destroy(),
95
+ * so the client receives an HTTP 413 rather than ECONNRESET. */
96
+ readonly bodyLimitBytes?: number;
97
+ /** Defaults to a Date.now-backed clock; injectable for tests
98
+ * (matches M1-15 SchedulerClock pattern). */
99
+ readonly clock?: {
100
+ readonly now: () => number;
101
+ };
102
+ }
103
+ export interface ControlServerAddress {
104
+ readonly host: string;
105
+ readonly port: number;
106
+ }
107
+ export interface ControlServer {
108
+ /** Bind host:port and resolve with the actual bound port. Throws
109
+ * ControlServerError("invalid_state") when called twice or after
110
+ * close(); rejects with ControlServerError("bind_failed") when
111
+ * the OS rejects the bind (EADDRINUSE / EACCES / ...). */
112
+ listen(): Promise<number>;
113
+ /** Sync; returns null when the server has not yet listened. */
114
+ address(): ControlServerAddress | null;
115
+ /** Drain in-flight requests then close. Idempotent: pre-listen and
116
+ * post-close calls resolve as no-ops. 5-second grace before forcing
117
+ * remaining sockets shut via http.Server.closeAllConnections (Node
118
+ * 18.2+). */
119
+ close(): Promise<void>;
120
+ }
121
+ export type ControlServerErrorKind = "invalid_state" | "bind_failed";
122
+ export declare class ControlServerError extends Error {
123
+ readonly name = "ControlServerError";
124
+ readonly kind: ControlServerErrorKind;
125
+ readonly cause: unknown;
126
+ constructor(kind: ControlServerErrorKind, message: string, cause?: unknown);
127
+ }
128
+ export type ControlErrorCode = "unauthorized" | "not_found" | "method_not_allowed" | "bad_request" | "unsupported_media_type" | "payload_too_large" | "not_implemented" | "service_unavailable" | "internal_error";
129
+ export interface ControlErrorBody {
130
+ readonly error: {
131
+ readonly code: ControlErrorCode;
132
+ readonly message: string;
133
+ readonly details?: Readonly<Record<string, unknown>>;
134
+ };
135
+ }
136
+ export type { DailyScheduler, DailyScheduleConfig };
@@ -0,0 +1,40 @@
1
+ import type { AgentDecisionProvider } from "../agents/agent";
2
+ import type { ReconnectingWSClient, ReconnectingWSClientOptions } from "../wsclient/reconnect";
3
+ import type { DecisionProvider } from "../decision/provider";
4
+ import type { GameType, StrategyProfile } from "../decision/types";
5
+ export interface GameStartCacheEntry {
6
+ readonly game: GameType;
7
+ readonly playerId: string;
8
+ readonly rules: unknown;
9
+ }
10
+ export type GameStartCache = Map<string, GameStartCacheEntry>;
11
+ export declare function createGameStartCache(): GameStartCache;
12
+ export type ReconnectFactory = (opts: ReconnectingWSClientOptions) => Promise<ReconnectingWSClient>;
13
+ /**
14
+ * Builds a `connect` factory for `AgentInstanceOptions.connect`. It
15
+ * delegates to `createReconnectingWSClient(opts)` (or a caller-supplied
16
+ * factory for tests), then attaches a sidecar `client.onMessage` handler
17
+ * that snoops `game_start` envelopes and caches the immutable
18
+ * per-match metadata adapter.decide() needs later.
19
+ *
20
+ * The sidecar does NOT consume the message — wsclient still delivers it
21
+ * to the AgentInstance's own onMessage handler in parallel (M1-06
22
+ * sealed multi-handler API).
23
+ */
24
+ export declare function buildConnectWithGameStartCache(cache: GameStartCache, factory?: ReconnectFactory): (opts: ReconnectingWSClientOptions) => Promise<ReconnectingWSClient>;
25
+ export declare class AgentDecisionBridgeError extends Error {
26
+ readonly name = "AgentDecisionBridgeError";
27
+ readonly code: "missing_game_start_metadata";
28
+ readonly matchId: string;
29
+ constructor(matchId: string, message: string);
30
+ }
31
+ export interface BuildAgentDecisionAdapterOptions {
32
+ readonly provider: DecisionProvider;
33
+ readonly strategyProfile: StrategyProfile;
34
+ readonly cache: GameStartCache;
35
+ /** Subtracted from action_request.timeout_ms to derive the
36
+ * decisionBudgetMs passed to M1-14 provider. Default 5000 ms. */
37
+ readonly decisionBudgetSafetyMs?: number;
38
+ }
39
+ export declare function buildAgentDecisionAdapter(opts: BuildAgentDecisionAdapterOptions): AgentDecisionProvider;
40
+ export declare function buildLlmApiKeyResolver(agentName: string): (provider: string, model: string) => string;