heyhank 0.1.0

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 (199) hide show
  1. package/README.md +40 -0
  2. package/bin/cli.ts +168 -0
  3. package/bin/ctl.ts +528 -0
  4. package/bin/generate-token.ts +28 -0
  5. package/dist/apple-touch-icon.png +0 -0
  6. package/dist/assets/AgentsPage-BPhirnCe.js +7 -0
  7. package/dist/assets/AssistantPage-DJ-cMQfb.js +1 -0
  8. package/dist/assets/CronManager-DDbz-yiT.js +1 -0
  9. package/dist/assets/HelpPage-DMfkzERp.js +1 -0
  10. package/dist/assets/IntegrationsPage-CrOitCmJ.js +1 -0
  11. package/dist/assets/MediaPage-CE5rdvkC.js +1 -0
  12. package/dist/assets/PlatformDashboard-Do6F0O2p.js +1 -0
  13. package/dist/assets/Playground-Fc5cdc5p.js +109 -0
  14. package/dist/assets/ProcessPanel-CslEiZkI.js +2 -0
  15. package/dist/assets/PromptsPage-D2EhsdNO.js +4 -0
  16. package/dist/assets/RunsPage-C5BZF5Rx.js +1 -0
  17. package/dist/assets/SandboxManager-a1AVI5q2.js +8 -0
  18. package/dist/assets/SettingsPage-DirhjQrJ.js +51 -0
  19. package/dist/assets/SocialMediaPage-DBuM28vD.js +1 -0
  20. package/dist/assets/TailscalePage-CHiFhZXF.js +1 -0
  21. package/dist/assets/TelephonyPage-x0VV0fOo.js +1 -0
  22. package/dist/assets/TerminalPage-Drwyrnfd.js +1 -0
  23. package/dist/assets/gemini-audio-t-TSU-To.js +17 -0
  24. package/dist/assets/gemini-live-client-C7rqAW7G.js +166 -0
  25. package/dist/assets/index-C8M_PUmX.css +32 -0
  26. package/dist/assets/index-CEqZnThB.js +204 -0
  27. package/dist/assets/sw-register-LSSpj6RU.js +1 -0
  28. package/dist/assets/time-ago-B6r_l9u1.js +1 -0
  29. package/dist/assets/workbox-window.prod.es5-BIl4cyR9.js +2 -0
  30. package/dist/favicon-32-original.png +0 -0
  31. package/dist/favicon-32.png +0 -0
  32. package/dist/favicon.ico +0 -0
  33. package/dist/favicon.svg +8 -0
  34. package/dist/fonts/MesloLGSNerdFontMono-Bold.woff2 +0 -0
  35. package/dist/fonts/MesloLGSNerdFontMono-Regular.woff2 +0 -0
  36. package/dist/heyhank-mascot-poster.png +0 -0
  37. package/dist/heyhank-mascot.mp4 +0 -0
  38. package/dist/heyhank-mascot.webm +0 -0
  39. package/dist/icon-192-original.png +0 -0
  40. package/dist/icon-192.png +0 -0
  41. package/dist/icon-512-original.png +0 -0
  42. package/dist/icon-512.png +0 -0
  43. package/dist/index.html +21 -0
  44. package/dist/logo-192.png +0 -0
  45. package/dist/logo-512.png +0 -0
  46. package/dist/logo-codex.svg +14 -0
  47. package/dist/logo-docker.svg +4 -0
  48. package/dist/logo-original.png +0 -0
  49. package/dist/logo.png +0 -0
  50. package/dist/logo.svg +14 -0
  51. package/dist/manifest.json +24 -0
  52. package/dist/push-sw.js +34 -0
  53. package/dist/sw.js +1 -0
  54. package/dist/workbox-d2a0910a.js +1 -0
  55. package/package.json +109 -0
  56. package/server/agent-cron-migrator.ts +85 -0
  57. package/server/agent-executor.ts +357 -0
  58. package/server/agent-store.ts +185 -0
  59. package/server/agent-timeout.ts +107 -0
  60. package/server/agent-types.ts +122 -0
  61. package/server/ai-validation-settings.ts +37 -0
  62. package/server/ai-validator.ts +181 -0
  63. package/server/anthropic-provider-migration.ts +48 -0
  64. package/server/assistant-store.ts +272 -0
  65. package/server/auth-manager.ts +150 -0
  66. package/server/auto-approve.ts +153 -0
  67. package/server/auto-namer.ts +36 -0
  68. package/server/backend-adapter.ts +54 -0
  69. package/server/cache-headers.ts +61 -0
  70. package/server/calendar-service.ts +434 -0
  71. package/server/claude-adapter.ts +889 -0
  72. package/server/claude-container-auth.ts +30 -0
  73. package/server/claude-session-discovery.ts +157 -0
  74. package/server/claude-session-history.ts +410 -0
  75. package/server/cli-launcher.ts +1303 -0
  76. package/server/codex-adapter.ts +3027 -0
  77. package/server/codex-container-auth.ts +24 -0
  78. package/server/codex-home.ts +27 -0
  79. package/server/codex-ws-proxy.cjs +226 -0
  80. package/server/commands-discovery.ts +81 -0
  81. package/server/constants.ts +7 -0
  82. package/server/container-manager.ts +1053 -0
  83. package/server/cost-tracker.ts +222 -0
  84. package/server/cron-scheduler.ts +243 -0
  85. package/server/cron-store.ts +148 -0
  86. package/server/cron-types.ts +63 -0
  87. package/server/email-service.ts +354 -0
  88. package/server/env-manager.ts +161 -0
  89. package/server/event-bus-types.ts +75 -0
  90. package/server/event-bus.ts +124 -0
  91. package/server/execution-store.ts +170 -0
  92. package/server/federation/node-connection.ts +190 -0
  93. package/server/federation/node-manager.ts +366 -0
  94. package/server/federation/node-store.ts +86 -0
  95. package/server/federation/node-types.ts +121 -0
  96. package/server/fs-utils.ts +15 -0
  97. package/server/git-utils.ts +421 -0
  98. package/server/github-pr.ts +379 -0
  99. package/server/google-media.ts +342 -0
  100. package/server/image-pull-manager.ts +279 -0
  101. package/server/index.ts +491 -0
  102. package/server/internal-ai.ts +237 -0
  103. package/server/kill-switch.ts +99 -0
  104. package/server/llm-providers.ts +342 -0
  105. package/server/logger.ts +259 -0
  106. package/server/mcp-registry.ts +401 -0
  107. package/server/message-bus.ts +271 -0
  108. package/server/message-delivery.ts +128 -0
  109. package/server/metrics-collector.ts +350 -0
  110. package/server/metrics-types.ts +108 -0
  111. package/server/middleware/managed-auth.ts +195 -0
  112. package/server/novnc-proxy.ts +99 -0
  113. package/server/path-resolver.ts +186 -0
  114. package/server/paths.ts +13 -0
  115. package/server/pr-poller.ts +162 -0
  116. package/server/prompt-manager.ts +211 -0
  117. package/server/protocol/claude-upstream/README.md +19 -0
  118. package/server/protocol/claude-upstream/sdk.d.ts.txt +1943 -0
  119. package/server/protocol/codex-upstream/ClientNotification.ts.txt +5 -0
  120. package/server/protocol/codex-upstream/ClientRequest.ts.txt +60 -0
  121. package/server/protocol/codex-upstream/README.md +18 -0
  122. package/server/protocol/codex-upstream/ServerNotification.ts.txt +41 -0
  123. package/server/protocol/codex-upstream/ServerRequest.ts.txt +16 -0
  124. package/server/protocol/codex-upstream/v2/DynamicToolCallParams.ts.txt +6 -0
  125. package/server/protocol/codex-upstream/v2/DynamicToolCallResponse.ts.txt +6 -0
  126. package/server/protocol-monitor.ts +50 -0
  127. package/server/provider-manager.ts +111 -0
  128. package/server/provider-registry.ts +393 -0
  129. package/server/push-notifications.ts +221 -0
  130. package/server/recorder.ts +374 -0
  131. package/server/recording-hub/compat-validator.ts +284 -0
  132. package/server/recording-hub/diagnostics.ts +299 -0
  133. package/server/recording-hub/hub-config.ts +19 -0
  134. package/server/recording-hub/hub-routes.ts +236 -0
  135. package/server/recording-hub/hub-store.ts +265 -0
  136. package/server/recording-hub/replay-adapter.ts +207 -0
  137. package/server/relay-client.ts +320 -0
  138. package/server/reminder-scheduler.ts +38 -0
  139. package/server/replay.ts +78 -0
  140. package/server/routes/agent-routes.ts +264 -0
  141. package/server/routes/assistant-routes.ts +90 -0
  142. package/server/routes/cron-routes.ts +103 -0
  143. package/server/routes/env-routes.ts +95 -0
  144. package/server/routes/federation-routes.ts +76 -0
  145. package/server/routes/fs-routes.ts +622 -0
  146. package/server/routes/git-routes.ts +97 -0
  147. package/server/routes/llm-routes.ts +166 -0
  148. package/server/routes/media-routes.ts +135 -0
  149. package/server/routes/metrics-routes.ts +13 -0
  150. package/server/routes/platform-routes.ts +1379 -0
  151. package/server/routes/prompt-routes.ts +67 -0
  152. package/server/routes/provider-routes.ts +109 -0
  153. package/server/routes/sandbox-routes.ts +127 -0
  154. package/server/routes/settings-routes.ts +285 -0
  155. package/server/routes/skills-routes.ts +100 -0
  156. package/server/routes/socialmedia-routes.ts +208 -0
  157. package/server/routes/system-routes.ts +228 -0
  158. package/server/routes/tailscale-routes.ts +22 -0
  159. package/server/routes/telephony-routes.ts +259 -0
  160. package/server/routes.ts +1379 -0
  161. package/server/sandbox-manager.ts +168 -0
  162. package/server/service.ts +718 -0
  163. package/server/session-creation-service.ts +457 -0
  164. package/server/session-git-info.ts +104 -0
  165. package/server/session-names.ts +67 -0
  166. package/server/session-orchestrator.ts +824 -0
  167. package/server/session-state-machine.ts +207 -0
  168. package/server/session-store.ts +146 -0
  169. package/server/session-types.ts +511 -0
  170. package/server/settings-manager.ts +149 -0
  171. package/server/shared-context.ts +157 -0
  172. package/server/socialmedia/adapter.ts +15 -0
  173. package/server/socialmedia/adapters/ayrshare-adapter.ts +169 -0
  174. package/server/socialmedia/adapters/buffer-adapter.ts +299 -0
  175. package/server/socialmedia/adapters/postiz-adapter.ts +298 -0
  176. package/server/socialmedia/manager.ts +227 -0
  177. package/server/socialmedia/store.ts +98 -0
  178. package/server/socialmedia/types.ts +89 -0
  179. package/server/tailscale-manager.ts +451 -0
  180. package/server/telephony/audio-bridge.ts +331 -0
  181. package/server/telephony/call-manager.ts +457 -0
  182. package/server/telephony/call-types.ts +108 -0
  183. package/server/telephony/telephony-store.ts +119 -0
  184. package/server/terminal-manager.ts +240 -0
  185. package/server/update-checker.ts +192 -0
  186. package/server/usage-limits.ts +225 -0
  187. package/server/web-push.d.ts +51 -0
  188. package/server/worktree-tracker.ts +84 -0
  189. package/server/ws-auth.ts +41 -0
  190. package/server/ws-bridge-browser-ingest.ts +72 -0
  191. package/server/ws-bridge-browser.ts +112 -0
  192. package/server/ws-bridge-cli-ingest.ts +81 -0
  193. package/server/ws-bridge-codex.ts +266 -0
  194. package/server/ws-bridge-controls.ts +20 -0
  195. package/server/ws-bridge-persist.ts +66 -0
  196. package/server/ws-bridge-publish.ts +79 -0
  197. package/server/ws-bridge-replay.ts +61 -0
  198. package/server/ws-bridge-types.ts +121 -0
  199. package/server/ws-bridge.ts +1240 -0
@@ -0,0 +1,66 @@
1
+ import type { BrowserIncomingMessage } from "./session-types.js";
2
+ import type { Session } from "./ws-bridge-types.js";
3
+ import type { SessionStore, PersistedSession } from "./session-store.js";
4
+
5
+ // ─── Persistence Pipeline ───────────────────────────────────────────────────
6
+ // Extracted from WsBridge to consolidate history append + disk persistence
7
+ // into explicit, testable functions.
8
+
9
+ export const MESSAGE_HISTORY_LIMIT = 2000;
10
+
11
+ /**
12
+ * Append a message to session history with cap enforcement, then persist to disk.
13
+ * Consolidates the common appendHistory + persistSession pattern into one call,
14
+ * eliminating the risk of appending without persisting.
15
+ */
16
+ export function appendAndPersist(
17
+ session: Session,
18
+ msg: BrowserIncomingMessage,
19
+ store: SessionStore | null,
20
+ historyLimit: number = MESSAGE_HISTORY_LIMIT,
21
+ ): void {
22
+ appendHistory(session, msg, historyLimit);
23
+ persistSession(session, store);
24
+ }
25
+
26
+ /**
27
+ * Append a message to session history with cap enforcement.
28
+ * Trims oldest messages when the history exceeds the limit.
29
+ */
30
+ export function appendHistory(
31
+ session: Session,
32
+ msg: BrowserIncomingMessage,
33
+ historyLimit: number = MESSAGE_HISTORY_LIMIT,
34
+ ): void {
35
+ session.messageHistory.push(msg);
36
+ if (session.messageHistory.length > historyLimit) {
37
+ session.messageHistory.splice(0, session.messageHistory.length - historyLimit);
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Persist session state to disk (debounced via SessionStore).
43
+ * No-op if no store is attached.
44
+ */
45
+ export function persistSession(session: Session, store: SessionStore | null): void {
46
+ if (!store) return;
47
+ store.save(serializeForStore(session));
48
+ }
49
+
50
+ /**
51
+ * Serialize a Session into the shape expected by SessionStore.save().
52
+ * Converts Maps to arrays and selects the persisted fields.
53
+ */
54
+ export function serializeForStore(session: Session): PersistedSession {
55
+ return {
56
+ id: session.id,
57
+ state: session.state,
58
+ messageHistory: session.messageHistory,
59
+ pendingMessages: session.pendingMessages,
60
+ pendingPermissions: Array.from(session.pendingPermissions.entries()),
61
+ eventBuffer: session.eventBuffer,
62
+ nextEventSeq: session.nextEventSeq,
63
+ lastAckSeq: session.lastAckSeq,
64
+ processedClientMessageIds: session.processedClientMessageIds,
65
+ };
66
+ }
@@ -0,0 +1,79 @@
1
+ import type { ServerWebSocket } from "bun";
2
+ import type { BrowserIncomingMessage } from "./session-types.js";
3
+ import type { Session, SocketData } from "./ws-bridge-types.js";
4
+ import type { RecorderManager } from "./recorder.js";
5
+ import { sequenceEvent } from "./ws-bridge-replay.js";
6
+
7
+ // ─── Publish Pipeline ───────────────────────────────────────────────────────
8
+ // Transport functions for sending messages to CLI and browser sockets.
9
+ // Extracted from WsBridge to enable isolated testing of message delivery,
10
+ // sequencing, and recording behavior.
11
+
12
+ export const EVENT_BUFFER_LIMIT = 600;
13
+
14
+ /**
15
+ * Broadcast a message to all connected browsers for a session.
16
+ * Assigns a monotonic sequence number via sequenceEvent, records the
17
+ * outgoing message, and sends to every browser socket (removing broken ones).
18
+ *
19
+ * Note: sequenceEvent internally calls persistFn when buffering events.
20
+ * Callers that also call persistSession after broadcastToBrowsers will
21
+ * trigger a redundant (but harmless) debounced save. This is intentional —
22
+ * the caller-side persist covers state mutations beyond the event buffer
23
+ * (e.g. messageHistory, pendingPermissions), while the internal persist
24
+ * covers the event buffer/seq counters. SessionStore's debouncer coalesces
25
+ * them into a single write.
26
+ */
27
+ export function broadcastToBrowsers(
28
+ session: Session,
29
+ msg: BrowserIncomingMessage,
30
+ opts: {
31
+ eventBufferLimit: number;
32
+ recorder: RecorderManager | null;
33
+ persistFn: (session: Session) => void;
34
+ },
35
+ ): void {
36
+ // Warn when messages that should be visible to users are broadcast to 0 browsers
37
+ if (
38
+ session.browserSockets.size === 0
39
+ && (msg.type === "assistant" || msg.type === "stream_event" || msg.type === "result")
40
+ ) {
41
+ console.log(
42
+ `[ws-bridge] ⚠ Broadcasting ${msg.type} to 0 browsers for session ${session.id} (stored in history: ${msg.type === "assistant" || msg.type === "result"})`,
43
+ );
44
+ }
45
+
46
+ const json = JSON.stringify(
47
+ sequenceEvent(session, msg, opts.eventBufferLimit, opts.persistFn),
48
+ );
49
+
50
+ // Record raw outgoing browser message
51
+ opts.recorder?.record(
52
+ session.id, "out", json, "browser", session.backendType, session.state.cwd,
53
+ );
54
+
55
+ for (const ws of session.browserSockets) {
56
+ try {
57
+ ws.send(json);
58
+ } catch {
59
+ session.browserSockets.delete(ws);
60
+ }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Send a message to a single browser socket (no sequencing).
66
+ * Used for replay, session_init, and message_history — messages that
67
+ * should NOT go through the event buffer.
68
+ */
69
+ export function sendToBrowser(
70
+ ws: ServerWebSocket<SocketData>,
71
+ msg: BrowserIncomingMessage,
72
+ ): void {
73
+ try {
74
+ ws.send(JSON.stringify(msg));
75
+ } catch {
76
+ // Socket will be cleaned up on close
77
+ }
78
+ }
79
+
@@ -0,0 +1,61 @@
1
+ import type {
2
+ BrowserIncomingMessage,
3
+ ReplayableBrowserIncomingMessage,
4
+ } from "./session-types.js";
5
+ import type { Session } from "./ws-bridge-types.js";
6
+
7
+ export function isDuplicateClientMessage(session: Session, clientMsgId: string): boolean {
8
+ return session.processedClientMessageIdSet.has(clientMsgId);
9
+ }
10
+
11
+ export function rememberClientMessage(
12
+ session: Session,
13
+ clientMsgId: string,
14
+ processedClientMsgIdLimit: number,
15
+ persistSession: (session: Session) => void,
16
+ ): void {
17
+ session.processedClientMessageIds.push(clientMsgId);
18
+ session.processedClientMessageIdSet.add(clientMsgId);
19
+ if (session.processedClientMessageIds.length > processedClientMsgIdLimit) {
20
+ const overflow = session.processedClientMessageIds.length - processedClientMsgIdLimit;
21
+ const removed = session.processedClientMessageIds.splice(0, overflow);
22
+ for (const id of removed) {
23
+ session.processedClientMessageIdSet.delete(id);
24
+ }
25
+ }
26
+ persistSession(session);
27
+ }
28
+
29
+ export function shouldBufferForReplay(
30
+ msg: BrowserIncomingMessage,
31
+ ): msg is ReplayableBrowserIncomingMessage {
32
+ return msg.type !== "session_init"
33
+ && msg.type !== "message_history"
34
+ && msg.type !== "event_replay";
35
+ }
36
+
37
+ export function isHistoryBackedEvent(msg: ReplayableBrowserIncomingMessage): boolean {
38
+ return msg.type === "assistant"
39
+ || msg.type === "result"
40
+ || msg.type === "user_message"
41
+ || (msg.type === "system_event" && msg.event.subtype !== "hook_progress")
42
+ || msg.type === "error";
43
+ }
44
+
45
+ export function sequenceEvent(
46
+ session: Session,
47
+ msg: BrowserIncomingMessage,
48
+ eventBufferLimit: number,
49
+ persistSession: (session: Session) => void,
50
+ ): BrowserIncomingMessage {
51
+ const seq = session.nextEventSeq++;
52
+ const sequenced = { ...msg, seq };
53
+ if (shouldBufferForReplay(msg)) {
54
+ session.eventBuffer.push({ seq, message: msg });
55
+ if (session.eventBuffer.length > eventBufferLimit) {
56
+ session.eventBuffer.splice(0, session.eventBuffer.length - eventBufferLimit);
57
+ }
58
+ persistSession(session);
59
+ }
60
+ return sequenced;
61
+ }
@@ -0,0 +1,121 @@
1
+ import type { ServerWebSocket } from "bun";
2
+ import type {
3
+ BackendType,
4
+ BrowserIncomingMessage,
5
+ PermissionRequest,
6
+ SessionState,
7
+ BufferedBrowserEvent,
8
+ } from "./session-types.js";
9
+ import type { IBackendAdapter } from "./backend-adapter.js";
10
+ import type { SessionStateMachine } from "./session-state-machine.js";
11
+ import { getSettings } from "./settings-manager.js";
12
+
13
+ export interface CLISocketData {
14
+ kind: "cli";
15
+ sessionId: string;
16
+ }
17
+
18
+ export interface BrowserSocketData {
19
+ kind: "browser";
20
+ sessionId: string;
21
+ subscribed?: boolean;
22
+ lastAckSeq?: number;
23
+ }
24
+
25
+ export interface TerminalSocketData {
26
+ kind: "terminal";
27
+ terminalId: string;
28
+ }
29
+
30
+ export interface NoVncSocketData {
31
+ kind: "novnc";
32
+ sessionId: string;
33
+ }
34
+
35
+ export interface NodeSocketData {
36
+ kind: "node";
37
+ nodeId: string;
38
+ }
39
+
40
+ export interface TelephonyAudioSocketData {
41
+ kind: "telephony-audio";
42
+ callId: string;
43
+ }
44
+
45
+ export interface TelephonyTranscriptSocketData {
46
+ kind: "telephony-transcript";
47
+ callId: string;
48
+ }
49
+
50
+ export type SocketData = CLISocketData | BrowserSocketData | TerminalSocketData | NoVncSocketData | NodeSocketData | TelephonyAudioSocketData | TelephonyTranscriptSocketData;
51
+
52
+ /** Tracks a pending control_request sent to CLI that expects a control_response. */
53
+ export interface PendingControlRequest {
54
+ subtype: string;
55
+ resolve: (response: unknown) => void;
56
+ }
57
+
58
+ export interface Session {
59
+ id: string;
60
+ backendType: BackendType;
61
+ /** Unified backend adapter — replaces the former cliSocket (Claude) / codexAdapter (Codex) fields. */
62
+ backendAdapter: IBackendAdapter | null;
63
+ browserSockets: Set<ServerWebSocket<SocketData>>;
64
+ state: SessionState;
65
+ pendingPermissions: Map<string, PermissionRequest>;
66
+ messageHistory: BrowserIncomingMessage[];
67
+ pendingMessages: string[];
68
+ nextEventSeq: number;
69
+ eventBuffer: BufferedBrowserEvent[];
70
+ lastAckSeq: number;
71
+ processedClientMessageIds: string[];
72
+ processedClientMessageIdSet: Set<string>;
73
+ /** Timestamp of last non-keepalive CLI message (for idle detection) */
74
+ lastCliActivityTs: number;
75
+ /** Formal session state machine tracking phase and validating transitions. */
76
+ stateMachine: SessionStateMachine;
77
+ /** Cleanup function for state machine transition listener — call on session teardown. */
78
+ unsubscribeStateMachine?: () => void;
79
+ }
80
+
81
+ export type GitSessionKey =
82
+ | "git_branch"
83
+ | "is_worktree"
84
+ | "is_containerized"
85
+ | "repo_root"
86
+ | "git_ahead"
87
+ | "git_behind";
88
+
89
+ export function makeDefaultState(
90
+ sessionId: string,
91
+ backendType: BackendType = "claude",
92
+ ): SessionState {
93
+ return {
94
+ session_id: sessionId,
95
+ backend_type: backendType,
96
+ model: "",
97
+ cwd: "",
98
+ tools: [],
99
+ permissionMode: "default",
100
+ claude_code_version: "",
101
+ mcp_servers: [],
102
+ agents: [],
103
+ slash_commands: [],
104
+ skills: [],
105
+ total_cost_usd: 0,
106
+ num_turns: 0,
107
+ context_used_percent: 0,
108
+ is_compacting: false,
109
+ git_branch: "",
110
+ is_worktree: false,
111
+ is_containerized: false,
112
+ repo_root: "",
113
+ git_ahead: 0,
114
+ git_behind: 0,
115
+ total_lines_added: 0,
116
+ total_lines_removed: 0,
117
+ aiValidationEnabled: getSettings().aiValidationEnabled,
118
+ aiValidationAutoApprove: getSettings().aiValidationAutoApprove,
119
+ aiValidationAutoDeny: getSettings().aiValidationAutoDeny,
120
+ };
121
+ }