@sensigo/realm-cli 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 (190) hide show
  1. package/README.md +109 -0
  2. package/dist/agent/agent-utils.d.ts +27 -0
  3. package/dist/agent/agent-utils.d.ts.map +1 -0
  4. package/dist/agent/agent-utils.js +79 -0
  5. package/dist/agent/agent-utils.js.map +1 -0
  6. package/dist/agent/anthropic-provider.d.ts +23 -0
  7. package/dist/agent/anthropic-provider.d.ts.map +1 -0
  8. package/dist/agent/anthropic-provider.js +245 -0
  9. package/dist/agent/anthropic-provider.js.map +1 -0
  10. package/dist/agent/gate/slack-gate-notifier.d.ts +80 -0
  11. package/dist/agent/gate/slack-gate-notifier.d.ts.map +1 -0
  12. package/dist/agent/gate/slack-gate-notifier.js +315 -0
  13. package/dist/agent/gate/slack-gate-notifier.js.map +1 -0
  14. package/dist/agent/gate/slack-gate-server.d.ts +30 -0
  15. package/dist/agent/gate/slack-gate-server.d.ts.map +1 -0
  16. package/dist/agent/gate/slack-gate-server.js +99 -0
  17. package/dist/agent/gate/slack-gate-server.js.map +1 -0
  18. package/dist/agent/gate/slack-socket-client.d.ts +20 -0
  19. package/dist/agent/gate/slack-socket-client.d.ts.map +1 -0
  20. package/dist/agent/gate/slack-socket-client.js +141 -0
  21. package/dist/agent/gate/slack-socket-client.js.map +1 -0
  22. package/dist/agent/gate-intent-interpreter.d.ts +29 -0
  23. package/dist/agent/gate-intent-interpreter.d.ts.map +1 -0
  24. package/dist/agent/gate-intent-interpreter.js +33 -0
  25. package/dist/agent/gate-intent-interpreter.js.map +1 -0
  26. package/dist/agent/index.d.ts +4 -0
  27. package/dist/agent/index.d.ts.map +1 -0
  28. package/dist/agent/index.js +4 -0
  29. package/dist/agent/index.js.map +1 -0
  30. package/dist/agent/llm-provider.d.ts +46 -0
  31. package/dist/agent/llm-provider.d.ts.map +1 -0
  32. package/dist/agent/llm-provider.js +55 -0
  33. package/dist/agent/llm-provider.js.map +1 -0
  34. package/dist/agent/mcp/mcp-client.d.ts +18 -0
  35. package/dist/agent/mcp/mcp-client.d.ts.map +1 -0
  36. package/dist/agent/mcp/mcp-client.js +108 -0
  37. package/dist/agent/mcp/mcp-client.js.map +1 -0
  38. package/dist/agent/mcp/mcp-extensions.d.ts +40 -0
  39. package/dist/agent/mcp/mcp-extensions.d.ts.map +1 -0
  40. package/dist/agent/mcp/mcp-extensions.js +2 -0
  41. package/dist/agent/mcp/mcp-extensions.js.map +1 -0
  42. package/dist/agent/mcp-client.d.ts +18 -0
  43. package/dist/agent/mcp-client.d.ts.map +1 -0
  44. package/dist/agent/mcp-client.js +108 -0
  45. package/dist/agent/mcp-client.js.map +1 -0
  46. package/dist/agent/mcp-types.d.ts +40 -0
  47. package/dist/agent/mcp-types.d.ts.map +1 -0
  48. package/dist/agent/mcp-types.js +2 -0
  49. package/dist/agent/mcp-types.js.map +1 -0
  50. package/dist/agent/openai-provider.d.ts +30 -0
  51. package/dist/agent/openai-provider.d.ts.map +1 -0
  52. package/dist/agent/openai-provider.js +253 -0
  53. package/dist/agent/openai-provider.js.map +1 -0
  54. package/dist/agent/openai-reasoning-provider.d.ts +18 -0
  55. package/dist/agent/openai-reasoning-provider.d.ts.map +1 -0
  56. package/dist/agent/openai-reasoning-provider.js +76 -0
  57. package/dist/agent/openai-reasoning-provider.js.map +1 -0
  58. package/dist/agent/preflight.d.ts +36 -0
  59. package/dist/agent/preflight.d.ts.map +1 -0
  60. package/dist/agent/preflight.js +81 -0
  61. package/dist/agent/preflight.js.map +1 -0
  62. package/dist/agent/providers/agent-utils.d.ts +27 -0
  63. package/dist/agent/providers/agent-utils.d.ts.map +1 -0
  64. package/dist/agent/providers/agent-utils.js +79 -0
  65. package/dist/agent/providers/agent-utils.js.map +1 -0
  66. package/dist/agent/providers/anthropic-provider.d.ts +23 -0
  67. package/dist/agent/providers/anthropic-provider.d.ts.map +1 -0
  68. package/dist/agent/providers/anthropic-provider.js +257 -0
  69. package/dist/agent/providers/anthropic-provider.js.map +1 -0
  70. package/dist/agent/providers/llm-provider.d.ts +46 -0
  71. package/dist/agent/providers/llm-provider.d.ts.map +1 -0
  72. package/dist/agent/providers/llm-provider.js +56 -0
  73. package/dist/agent/providers/llm-provider.js.map +1 -0
  74. package/dist/agent/providers/openai-provider.d.ts +30 -0
  75. package/dist/agent/providers/openai-provider.d.ts.map +1 -0
  76. package/dist/agent/providers/openai-provider.js +253 -0
  77. package/dist/agent/providers/openai-provider.js.map +1 -0
  78. package/dist/agent/providers/openai-reasoning-provider.d.ts +19 -0
  79. package/dist/agent/providers/openai-reasoning-provider.d.ts.map +1 -0
  80. package/dist/agent/providers/openai-reasoning-provider.js +89 -0
  81. package/dist/agent/providers/openai-reasoning-provider.js.map +1 -0
  82. package/dist/agent/run-agent.d.ts +50 -0
  83. package/dist/agent/run-agent.d.ts.map +1 -0
  84. package/dist/agent/run-agent.js +327 -0
  85. package/dist/agent/run-agent.js.map +1 -0
  86. package/dist/agent/slack-gate-notifier.d.ts +80 -0
  87. package/dist/agent/slack-gate-notifier.d.ts.map +1 -0
  88. package/dist/agent/slack-gate-notifier.js +315 -0
  89. package/dist/agent/slack-gate-notifier.js.map +1 -0
  90. package/dist/agent/slack-gate-poller.d.ts +28 -0
  91. package/dist/agent/slack-gate-poller.d.ts.map +1 -0
  92. package/dist/agent/slack-gate-poller.js +66 -0
  93. package/dist/agent/slack-gate-poller.js.map +1 -0
  94. package/dist/agent/slack-gate-server.d.ts +30 -0
  95. package/dist/agent/slack-gate-server.d.ts.map +1 -0
  96. package/dist/agent/slack-gate-server.js +99 -0
  97. package/dist/agent/slack-gate-server.js.map +1 -0
  98. package/dist/agent/slack-socket-client.d.ts +20 -0
  99. package/dist/agent/slack-socket-client.d.ts.map +1 -0
  100. package/dist/agent/slack-socket-client.js +141 -0
  101. package/dist/agent/slack-socket-client.js.map +1 -0
  102. package/dist/commands/agent.d.ts +3 -0
  103. package/dist/commands/agent.d.ts.map +1 -0
  104. package/dist/commands/agent.js +183 -0
  105. package/dist/commands/agent.js.map +1 -0
  106. package/dist/commands/cleanup.d.ts +16 -0
  107. package/dist/commands/cleanup.d.ts.map +1 -0
  108. package/dist/commands/cleanup.js +79 -0
  109. package/dist/commands/cleanup.js.map +1 -0
  110. package/dist/commands/diff.d.ts +41 -0
  111. package/dist/commands/diff.d.ts.map +1 -0
  112. package/dist/commands/diff.js +203 -0
  113. package/dist/commands/diff.js.map +1 -0
  114. package/dist/commands/init.d.ts +10 -0
  115. package/dist/commands/init.d.ts.map +1 -0
  116. package/dist/commands/init.js +97 -0
  117. package/dist/commands/init.js.map +1 -0
  118. package/dist/commands/inspect.d.ts +14 -0
  119. package/dist/commands/inspect.d.ts.map +1 -0
  120. package/dist/commands/inspect.js +224 -0
  121. package/dist/commands/inspect.js.map +1 -0
  122. package/dist/commands/list.d.ts +18 -0
  123. package/dist/commands/list.d.ts.map +1 -0
  124. package/dist/commands/list.js +88 -0
  125. package/dist/commands/list.js.map +1 -0
  126. package/dist/commands/mcp.d.ts +8 -0
  127. package/dist/commands/mcp.d.ts.map +1 -0
  128. package/dist/commands/mcp.js +22 -0
  129. package/dist/commands/mcp.js.map +1 -0
  130. package/dist/commands/migrate.d.ts +3 -0
  131. package/dist/commands/migrate.d.ts.map +1 -0
  132. package/dist/commands/migrate.js +42 -0
  133. package/dist/commands/migrate.js.map +1 -0
  134. package/dist/commands/register.d.ts +6 -0
  135. package/dist/commands/register.d.ts.map +1 -0
  136. package/dist/commands/register.js +51 -0
  137. package/dist/commands/register.js.map +1 -0
  138. package/dist/commands/replay-format.d.ts +3 -0
  139. package/dist/commands/replay-format.d.ts.map +1 -0
  140. package/dist/commands/replay-format.js +10 -0
  141. package/dist/commands/replay-format.js.map +1 -0
  142. package/dist/commands/replay.d.ts +38 -0
  143. package/dist/commands/replay.d.ts.map +1 -0
  144. package/dist/commands/replay.js +173 -0
  145. package/dist/commands/replay.js.map +1 -0
  146. package/dist/commands/respond.d.ts +20 -0
  147. package/dist/commands/respond.d.ts.map +1 -0
  148. package/dist/commands/respond.js +49 -0
  149. package/dist/commands/respond.js.map +1 -0
  150. package/dist/commands/resume.d.ts +15 -0
  151. package/dist/commands/resume.d.ts.map +1 -0
  152. package/dist/commands/resume.js +63 -0
  153. package/dist/commands/resume.js.map +1 -0
  154. package/dist/commands/run.d.ts +3 -0
  155. package/dist/commands/run.d.ts.map +1 -0
  156. package/dist/commands/run.js +127 -0
  157. package/dist/commands/run.js.map +1 -0
  158. package/dist/commands/serve.d.ts +33 -0
  159. package/dist/commands/serve.d.ts.map +1 -0
  160. package/dist/commands/serve.js +144 -0
  161. package/dist/commands/serve.js.map +1 -0
  162. package/dist/commands/test.d.ts +12 -0
  163. package/dist/commands/test.d.ts.map +1 -0
  164. package/dist/commands/test.js +58 -0
  165. package/dist/commands/test.js.map +1 -0
  166. package/dist/commands/validate.d.ts +3 -0
  167. package/dist/commands/validate.d.ts.map +1 -0
  168. package/dist/commands/validate.js +35 -0
  169. package/dist/commands/validate.js.map +1 -0
  170. package/dist/commands/watch.d.ts +18 -0
  171. package/dist/commands/watch.d.ts.map +1 -0
  172. package/dist/commands/watch.js +112 -0
  173. package/dist/commands/watch.js.map +1 -0
  174. package/dist/commands/webhook.d.ts +51 -0
  175. package/dist/commands/webhook.d.ts.map +1 -0
  176. package/dist/commands/webhook.js +227 -0
  177. package/dist/commands/webhook.js.map +1 -0
  178. package/dist/commands-registry.d.ts +7 -0
  179. package/dist/commands-registry.d.ts.map +1 -0
  180. package/dist/commands-registry.js +44 -0
  181. package/dist/commands-registry.js.map +1 -0
  182. package/dist/index.d.ts +3 -0
  183. package/dist/index.d.ts.map +1 -0
  184. package/dist/index.js +21 -0
  185. package/dist/index.js.map +1 -0
  186. package/dist/store/replay-store.d.ts +29 -0
  187. package/dist/store/replay-store.d.ts.map +1 -0
  188. package/dist/store/replay-store.js +31 -0
  189. package/dist/store/replay-store.js.map +1 -0
  190. package/package.json +83 -0
@@ -0,0 +1,112 @@
1
+ // realm workflow watch <path> — watches a workflow YAML and re-registers on change.
2
+ import { watch, existsSync } from 'node:fs';
3
+ import { join, dirname, resolve } from 'node:path';
4
+ import { Command } from 'commander';
5
+ import { loadWorkflowFromFile, WorkflowError } from '@sensigo/realm';
6
+ /**
7
+ * Attempts to load and register a workflow YAML file.
8
+ * Logs the result (success or validation error) to stdout/stderr.
9
+ * @param filePath Path to the workflow YAML file.
10
+ * @param store The registrar to register into.
11
+ */
12
+ async function registerFile(filePath, store) {
13
+ const timestamp = new Date().toISOString();
14
+ try {
15
+ const definition = loadWorkflowFromFile(filePath);
16
+ await store.register(definition);
17
+ console.log(`[${timestamp}] Registered: ${definition.id} v${definition.version} (${Object.keys(definition.steps).length} steps)`);
18
+ }
19
+ catch (err) {
20
+ if (err instanceof WorkflowError) {
21
+ console.error(`[${timestamp}] Invalid: ${err.message}`);
22
+ }
23
+ else {
24
+ const message = err instanceof Error ? err.message : String(err);
25
+ console.error(`[${timestamp}] Error: ${message}`);
26
+ }
27
+ }
28
+ }
29
+ /**
30
+ * Watches a workflow YAML file and re-registers it into the given store on every change.
31
+ * Also watches the profiles directory alongside the YAML — any file change there triggers
32
+ * re-registration. If the profiles directory does not exist, only the YAML is watched.
33
+ * Performs an initial registration before entering the watch loop.
34
+ * Resolves when the watcher is closed (e.g. when the AbortSignal fires).
35
+ *
36
+ * @param filePath Path to the workflow YAML file.
37
+ * @param store The workflow registrar to register into — injected, never instantiated here.
38
+ * @param signal Optional AbortSignal; when aborted the watcher stops and the promise resolves.
39
+ * @param profilesDir Optional override for the profiles directory path. Defaults to
40
+ * `<workflow-dir>/profiles` (or `profiles_dir` declared in the YAML).
41
+ */
42
+ export async function watchWorkflow(filePath, store, signal, profilesDir) {
43
+ await registerFile(filePath, store);
44
+ // Derive the profiles directory: caller override → YAML profiles_dir → default.
45
+ let resolvedProfilesDir = profilesDir;
46
+ if (resolvedProfilesDir === undefined) {
47
+ const workflowDir = dirname(resolve(filePath));
48
+ try {
49
+ const definition = loadWorkflowFromFile(filePath);
50
+ resolvedProfilesDir =
51
+ definition.profiles_dir !== undefined
52
+ ? resolve(workflowDir, definition.profiles_dir)
53
+ : join(workflowDir, 'profiles');
54
+ }
55
+ catch {
56
+ // If the YAML is invalid on startup we still run the YAML watcher.
57
+ resolvedProfilesDir = join(workflowDir, 'profiles');
58
+ }
59
+ }
60
+ const watchYaml = new Promise((resolve, reject) => {
61
+ const watcher = watch(filePath, { persistent: false, signal });
62
+ watcher.on('change', (eventType) => {
63
+ if (eventType === 'change') {
64
+ void registerFile(filePath, store);
65
+ }
66
+ });
67
+ watcher.on('error', (err) => {
68
+ reject(err);
69
+ });
70
+ watcher.on('close', () => {
71
+ resolve();
72
+ });
73
+ });
74
+ // Only watch the profiles directory if it exists.
75
+ if (!existsSync(resolvedProfilesDir)) {
76
+ return watchYaml;
77
+ }
78
+ const profilesDirPath = resolvedProfilesDir;
79
+ const watchProfiles = new Promise((resolve, reject) => {
80
+ const watcher = watch(profilesDirPath, { persistent: false, signal });
81
+ watcher.on('change', () => {
82
+ void registerFile(filePath, store);
83
+ });
84
+ watcher.on('error', (err) => {
85
+ reject(err);
86
+ });
87
+ watcher.on('close', () => {
88
+ resolve();
89
+ });
90
+ });
91
+ await Promise.all([watchYaml, watchProfiles]);
92
+ }
93
+ export const watchCommand = new Command('watch')
94
+ .argument('<path>', 'Path to workflow directory or workflow.yaml file')
95
+ .description('Watch a workflow YAML file and re-register it on every change')
96
+ .action(async (inputPath) => {
97
+ const filePath = inputPath.endsWith('.yaml') || inputPath.endsWith('.yml')
98
+ ? inputPath
99
+ : join(inputPath, 'workflow.yaml');
100
+ const { JsonWorkflowStore } = await import('@sensigo/realm');
101
+ const store = new JsonWorkflowStore();
102
+ console.log(`Watching ${filePath} — press Ctrl+C to stop`);
103
+ try {
104
+ await watchWorkflow(filePath, store);
105
+ }
106
+ catch (err) {
107
+ const message = err instanceof Error ? err.message : String(err);
108
+ console.error(`Error: ${message}`);
109
+ process.exit(1);
110
+ }
111
+ });
112
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { type Server } from 'node:http';
2
+ import { spawn as nodeSpawn } from 'node:child_process';
3
+ import { Command } from 'commander';
4
+ import type { WorkflowDefinition, WorkflowRegistrar, RunStore } from '@sensigo/realm';
5
+ /**
6
+ * Checks a GitHub webhook HMAC-SHA256 signature using timing-safe comparison.
7
+ * Returns true only if the header is present, uses the sha256= prefix, and
8
+ * the HMAC matches byte-for-byte. Pads both buffers to equal length before
9
+ * comparison to avoid length-based timing leaks.
10
+ */
11
+ export declare function checkWebhookSignature(rawBody: Buffer, signatureHeader: string | undefined, secret: string): boolean;
12
+ /**
13
+ * Checks whether a delivery ID is a duplicate within the TTL window.
14
+ * Evicts stale entries and enforces a capacity cap on each call.
15
+ * Returns true if the delivery was already seen; records it and returns false otherwise.
16
+ */
17
+ export declare function isDuplicate(deliveryCache: Map<string, number>, deliveryId: string): boolean;
18
+ /** An event:action pair used to filter incoming webhook deliveries. */
19
+ export interface EventFilter {
20
+ event: string;
21
+ action: string;
22
+ }
23
+ /** Options for startWebhookServer — all I/O dependencies are injectable for testing. */
24
+ export interface StartWebhookServerOptions {
25
+ port: number;
26
+ secret: string;
27
+ definition: WorkflowDefinition;
28
+ events: EventFilter[];
29
+ provider?: string;
30
+ model?: string;
31
+ /** Custom run store — avoids writing to disk in tests. */
32
+ runStore?: RunStore;
33
+ /** Custom workflow registrar — avoids writing to disk in tests. */
34
+ workflowStore?: WorkflowRegistrar;
35
+ /** Override spawn — injectable for test isolation. */
36
+ spawnFn?: typeof nodeSpawn;
37
+ }
38
+ /**
39
+ * Creates and starts the webhook HTTP server. Resolves once the server is listening.
40
+ * The caller is responsible for calling server.close() when done.
41
+ *
42
+ * Security-first request handling order:
43
+ * 1. Buffer body 2. Verify HMAC 3. Filter event/action 4. Dedup 5. Create run 6. Spawn agent
44
+ */
45
+ export declare function startWebhookServer(options: StartWebhookServerOptions): Promise<Server>;
46
+ /**
47
+ * `realm webhook` — starts an HTTP server that creates runs from GitHub webhook deliveries.
48
+ * Verifies HMAC-SHA256 signatures, deduplicates deliveries, and spawns realm agent children.
49
+ */
50
+ export declare const webhookCommand: Command;
51
+ //# sourceMappingURL=webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAKtF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,MAAM,EAAE,MAAM,GACb,OAAO,CAcT;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAgB3F;AAED,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wFAAwF;AACxF,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,mEAAmE;IACnE,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,SAAS,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4H5F;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,SAqExB,CAAC"}
@@ -0,0 +1,227 @@
1
+ // webhook.ts — realm webhook command
2
+ // Receives GitHub webhook POST requests, verifies HMAC-SHA256 signatures,
3
+ // deduplicates deliveries by X-Github-Delivery ID, creates runs, and spawns
4
+ // realm agent as a detached child process for each new delivery.
5
+ import { createServer } from 'node:http';
6
+ import { createHmac, timingSafeEqual } from 'node:crypto';
7
+ import { spawn as nodeSpawn } from 'node:child_process';
8
+ import { join } from 'node:path';
9
+ import { Command } from 'commander';
10
+ import { loadWorkflowFromFile, JsonFileStore, JsonWorkflowStore } from '@sensigo/realm';
11
+ const DEDUP_TTL_MS = 10 * 60 * 1000; // 10 minutes
12
+ const CACHE_MAX_SIZE = 1000;
13
+ /**
14
+ * Checks a GitHub webhook HMAC-SHA256 signature using timing-safe comparison.
15
+ * Returns true only if the header is present, uses the sha256= prefix, and
16
+ * the HMAC matches byte-for-byte. Pads both buffers to equal length before
17
+ * comparison to avoid length-based timing leaks.
18
+ */
19
+ export function checkWebhookSignature(rawBody, signatureHeader, secret) {
20
+ if (!signatureHeader?.startsWith('sha256='))
21
+ return false;
22
+ const provided = signatureHeader.slice(7);
23
+ const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
24
+ const a = Buffer.from(provided, 'utf8');
25
+ const b = Buffer.from(expected, 'utf8');
26
+ const maxLen = Math.max(a.length, b.length);
27
+ const aa = Buffer.alloc(maxLen);
28
+ const bb = Buffer.alloc(maxLen);
29
+ a.copy(aa);
30
+ b.copy(bb);
31
+ // Compare in constant time AND require equal length — pads prevent length-leak
32
+ // from short-circuiting timingSafeEqual, but lengths must still match for validity.
33
+ return timingSafeEqual(aa, bb) && a.length === b.length;
34
+ }
35
+ /**
36
+ * Checks whether a delivery ID is a duplicate within the TTL window.
37
+ * Evicts stale entries and enforces a capacity cap on each call.
38
+ * Returns true if the delivery was already seen; records it and returns false otherwise.
39
+ */
40
+ export function isDuplicate(deliveryCache, deliveryId) {
41
+ const now = Date.now();
42
+ // Evict stale entries on every request
43
+ for (const [id, ts] of deliveryCache) {
44
+ if (now - ts > DEDUP_TTL_MS)
45
+ deliveryCache.delete(id);
46
+ }
47
+ // Enforce capacity cap — evict oldest entry when at limit
48
+ if (deliveryCache.size >= CACHE_MAX_SIZE) {
49
+ const oldest = [...deliveryCache.entries()].sort((a, b) => a[1] - b[1])[0];
50
+ deliveryCache.delete(oldest[0]);
51
+ }
52
+ if (deliveryCache.has(deliveryId) && now - deliveryCache.get(deliveryId) < DEDUP_TTL_MS) {
53
+ return true;
54
+ }
55
+ deliveryCache.set(deliveryId, now);
56
+ return false;
57
+ }
58
+ /**
59
+ * Creates and starts the webhook HTTP server. Resolves once the server is listening.
60
+ * The caller is responsible for calling server.close() when done.
61
+ *
62
+ * Security-first request handling order:
63
+ * 1. Buffer body 2. Verify HMAC 3. Filter event/action 4. Dedup 5. Create run 6. Spawn agent
64
+ */
65
+ export async function startWebhookServer(options) {
66
+ const runStore = options.runStore ?? new JsonFileStore();
67
+ const workflowStore = options.workflowStore ?? new JsonWorkflowStore();
68
+ const spawnFn = options.spawnFn ?? nodeSpawn;
69
+ const deliveryCache = new Map();
70
+ const server = createServer(async (req, res) => {
71
+ // 1. Buffer raw body before any other logic
72
+ const chunks = [];
73
+ for await (const chunk of req)
74
+ chunks.push(chunk);
75
+ const rawBody = Buffer.concat(chunks);
76
+ // 2. HMAC signature check — mandatory before any event filtering (oracle-attack prevention)
77
+ const sigHeader = req.headers['x-hub-signature-256'];
78
+ if (!checkWebhookSignature(rawBody, sigHeader, options.secret)) {
79
+ res.writeHead(403, { 'Content-Type': 'application/json' });
80
+ res.end(JSON.stringify({ error: 'Invalid signature' }));
81
+ return;
82
+ }
83
+ // 3. Parse JSON body
84
+ let payload;
85
+ try {
86
+ payload = JSON.parse(rawBody.toString('utf-8'));
87
+ }
88
+ catch {
89
+ res.writeHead(400, { 'Content-Type': 'application/json' });
90
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
91
+ return;
92
+ }
93
+ // 4. Check X-Github-Event header against configured event types
94
+ const githubEvent = req.headers['x-github-event'];
95
+ const matchingEvents = options.events.filter((e) => e.event === githubEvent);
96
+ if (matchingEvents.length === 0) {
97
+ res.writeHead(200, { 'Content-Type': 'application/json' });
98
+ res.end(JSON.stringify({ ok: true, skipped: 'event' }));
99
+ return;
100
+ }
101
+ // 5. Check payload.action against configured action types
102
+ const payloadAction = payload.action;
103
+ const matchingActions = matchingEvents.filter((e) => e.action === payloadAction);
104
+ if (matchingActions.length === 0) {
105
+ res.writeHead(200, { 'Content-Type': 'application/json' });
106
+ res.end(JSON.stringify({ ok: true, skipped: 'action' }));
107
+ return;
108
+ }
109
+ // 6. Deduplication check — returns 200 to prevent GitHub retries on ignores
110
+ const deliveryId = req.headers['x-github-delivery'];
111
+ if (deliveryId !== undefined && isDuplicate(deliveryCache, deliveryId)) {
112
+ res.writeHead(200, { 'Content-Type': 'application/json' });
113
+ res.end(JSON.stringify({ ok: true, skipped: 'duplicate' }));
114
+ return;
115
+ }
116
+ // 7. Extract params from payload using the standard PR event field mapping
117
+ const pr = payload.pull_request ?? {};
118
+ const repo = payload.repository ?? {};
119
+ const sender = payload.sender ?? {};
120
+ const prBase = pr.base ?? {};
121
+ const prHead = pr.head ?? {};
122
+ const repoOwner = repo.owner ?? {};
123
+ const params = {
124
+ pr_number: pr.number,
125
+ pr_url: pr.html_url,
126
+ repo: repo.full_name,
127
+ repo_owner: repoOwner.login,
128
+ repo_name: repo.name,
129
+ pr_title: pr.title,
130
+ base_sha: prBase.sha,
131
+ head_sha: prHead.sha,
132
+ author: sender.login,
133
+ pr_action: payload['action'],
134
+ github_delivery_id: deliveryId,
135
+ };
136
+ // 8. Register workflow definition with the store
137
+ await workflowStore.register(options.definition);
138
+ // 9. Create run record
139
+ const run = await runStore.create({
140
+ workflowId: options.definition.id,
141
+ workflowVersion: options.definition.version,
142
+ params,
143
+ });
144
+ // 10. Spawn realm agent as detached child — inherits full env (API keys, tokens, etc.)
145
+ const realmBin = process.argv[1];
146
+ const providerArgs = [];
147
+ if (options.provider !== undefined)
148
+ providerArgs.push('--provider', options.provider);
149
+ if (options.model !== undefined)
150
+ providerArgs.push('--model', options.model);
151
+ const child = spawnFn(process.execPath, [realmBin, 'agent', '--run-id', run.id, ...providerArgs], { detached: true, stdio: 'inherit' });
152
+ child.unref();
153
+ // 11. Log spawn event for visibility in server logs
154
+ console.log(`realm agent spawned for run ${run.id} (pid: ${child.pid ?? 'unknown'})`);
155
+ // 12. Respond 202 Accepted — run is created, agent is running in background
156
+ res.writeHead(202, { 'Content-Type': 'application/json' });
157
+ res.end(JSON.stringify({ ok: true, run_id: run.id }));
158
+ });
159
+ return new Promise((resolve, reject) => {
160
+ let isListening = false;
161
+ server.on('error', (err) => {
162
+ if (!isListening) {
163
+ reject(err);
164
+ }
165
+ else {
166
+ console.error('Realm webhook server error:', err);
167
+ }
168
+ });
169
+ server.listen(options.port, () => {
170
+ isListening = true;
171
+ resolve(server);
172
+ });
173
+ });
174
+ }
175
+ /**
176
+ * `realm webhook` — starts an HTTP server that creates runs from GitHub webhook deliveries.
177
+ * Verifies HMAC-SHA256 signatures, deduplicates deliveries, and spawns realm agent children.
178
+ */
179
+ export const webhookCommand = new Command('webhook')
180
+ .description('Start a webhook server that creates runs from GitHub events')
181
+ .requiredOption('--workflow <path>', 'Path to workflow directory or workflow.yaml file')
182
+ .requiredOption('--port <port>', 'Port to listen on')
183
+ .option('--secret <secret>', 'GitHub webhook secret (overrides GITHUB_WEBHOOK_SECRET env var)')
184
+ .option('--event <filters>', 'Comma-separated event:action pairs to handle', 'pull_request:opened')
185
+ .option('--provider <provider>', 'LLM provider forwarded to spawned realm agent')
186
+ .option('--model <model>', 'Model name forwarded to spawned realm agent')
187
+ .action(async (opts) => {
188
+ // 1. Resolve secret — CLI flag overrides env var; refuse to start if neither set
189
+ const secret = opts.secret ?? process.env['GITHUB_WEBHOOK_SECRET'];
190
+ if (!secret) {
191
+ console.error('Error: webhook secret is required. Pass --secret or set GITHUB_WEBHOOK_SECRET.');
192
+ process.exit(1);
193
+ return;
194
+ }
195
+ // 2. Load and validate workflow before binding the port
196
+ const inputPath = opts.workflow;
197
+ const filePath = inputPath.endsWith('.yaml') || inputPath.endsWith('.yml')
198
+ ? inputPath
199
+ : join(inputPath, 'workflow.yaml');
200
+ let definition;
201
+ try {
202
+ definition = loadWorkflowFromFile(filePath);
203
+ }
204
+ catch (err) {
205
+ console.error(`Error: failed to load workflow: ${err instanceof Error ? err.message : String(err)}`);
206
+ process.exit(1);
207
+ return;
208
+ }
209
+ // 3. Parse event filters from comma-separated event:action string
210
+ const events = opts.event.split(',').map((token) => {
211
+ const [event, action] = token.trim().split(':');
212
+ return { event: event ?? '', action: action ?? '' };
213
+ });
214
+ // 4. Start server — only reached after secret and workflow are validated
215
+ const port = parseInt(opts.port, 10);
216
+ const server = await startWebhookServer({
217
+ port,
218
+ secret,
219
+ definition,
220
+ events,
221
+ ...(opts.provider !== undefined ? { provider: opts.provider } : {}),
222
+ ...(opts.model !== undefined ? { model: opts.model } : {}),
223
+ });
224
+ const addr = server.address();
225
+ console.log(`Realm webhook server listening on port ${addr.port}`);
226
+ });
227
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/commands/webhook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Commands that operate on workflow definitions (realm workflow <cmd>). */
2
+ export declare const workflowCommands: import("commander").Command[];
3
+ /** Commands that operate on run instances (realm run <cmd>). */
4
+ export declare const runCommands: import("commander").Command[];
5
+ /** Top-level commands not nested under a subgroup. */
6
+ export declare const topLevelCommands: import("commander").Command[];
7
+ //# sourceMappingURL=commands-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-registry.d.ts","sourceRoot":"","sources":["../src/commands-registry.ts"],"names":[],"mappings":"AAsBA,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB,+BAQ5B,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,WAAW,+BAQvB,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,+BAA2D,CAAC"}
@@ -0,0 +1,44 @@
1
+ // commands-registry.ts — exports all CLI commands grouped by category.
2
+ // Consumed by @sensigo/realm-cli itself and by realm-cloud/packages/cli-cloud,
3
+ // which adds cloud-specific commands on top.
4
+ import { validateCommand } from './commands/validate.js';
5
+ import { registerCommand } from './commands/register.js';
6
+ import { runCommand } from './commands/run.js';
7
+ import { resumeCommand } from './commands/resume.js';
8
+ import { cleanupCommand } from './commands/cleanup.js';
9
+ import { respondCommand } from './commands/respond.js';
10
+ import { inspectCommand } from './commands/inspect.js';
11
+ import { replayCommand } from './commands/replay.js';
12
+ import { diffCommand } from './commands/diff.js';
13
+ import { initCommand } from './commands/init.js';
14
+ import { testCommand } from './commands/test.js';
15
+ import { watchCommand } from './commands/watch.js';
16
+ import { listCommand } from './commands/list.js';
17
+ import { mcpCommand } from './commands/mcp.js';
18
+ import { serveCommand } from './commands/serve.js';
19
+ import { migrateCommand } from './commands/migrate.js';
20
+ import { agentCommand } from './commands/agent.js';
21
+ import { webhookCommand } from './commands/webhook.js';
22
+ /** Commands that operate on workflow definitions (realm workflow <cmd>). */
23
+ export const workflowCommands = [
24
+ initCommand,
25
+ validateCommand,
26
+ registerCommand,
27
+ watchCommand,
28
+ runCommand,
29
+ testCommand,
30
+ migrateCommand,
31
+ ];
32
+ /** Commands that operate on run instances (realm run <cmd>). */
33
+ export const runCommands = [
34
+ listCommand,
35
+ inspectCommand,
36
+ replayCommand,
37
+ diffCommand,
38
+ resumeCommand,
39
+ respondCommand,
40
+ cleanupCommand,
41
+ ];
42
+ /** Top-level commands not nested under a subgroup. */
43
+ export const topLevelCommands = [mcpCommand, serveCommand, agentCommand, webhookCommand];
44
+ //# sourceMappingURL=commands-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-registry.js","sourceRoot":"","sources":["../src/commands-registry.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,+EAA+E;AAC/E,6CAA6C;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,4EAA4E;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW;IACX,eAAe;IACf,eAAe;IACf,YAAY;IACZ,UAAU;IACV,WAAW;IACX,cAAc;CACf,CAAC;AAEF,gEAAgE;AAChE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,WAAW;IACX,cAAc;IACd,aAAa;IACb,WAAW;IACX,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC;AAEF,sDAAsD;AACtD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import 'dotenv/config';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ // @sensigo/realm-cli — command-line interface for Realm
3
+ import 'dotenv/config';
4
+ import { Command } from 'commander';
5
+ import { workflowCommands, runCommands, topLevelCommands } from './commands-registry.js';
6
+ const program = new Command();
7
+ program.name('realm').description('Realm workflow engine CLI').version('0.1.0');
8
+ // realm workflow — operations on workflow definitions
9
+ const workflowCmd = new Command('workflow').description('Manage workflow definitions');
10
+ for (const cmd of workflowCommands)
11
+ workflowCmd.addCommand(cmd);
12
+ // realm run — operations on run instances
13
+ const runCmd = new Command('run').description('Manage workflow run instances');
14
+ for (const cmd of runCommands)
15
+ runCmd.addCommand(cmd);
16
+ program.addCommand(workflowCmd);
17
+ program.addCommand(runCmd);
18
+ for (const cmd of topLevelCommands)
19
+ program.addCommand(cmd);
20
+ program.parse();
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,wDAAwD;AACxD,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEzF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhF,sDAAsD;AACtD,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,6BAA6B,CAAC,CAAC;AACvF,KAAK,MAAM,GAAG,IAAI,gBAAgB;IAAE,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAEhE,0CAA0C;AAC1C,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC;AAC/E,KAAK,MAAM,GAAG,IAAI,WAAW;IAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAEtD,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAC3B,KAAK,MAAM,GAAG,IAAI,gBAAgB;IAAE,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAE5D,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ReplayStepResult } from '../commands/replay.js';
2
+ /** A persisted replay snapshot: the result of replayRun() + the metadata that produced it. */
3
+ export interface ReplayRecord {
4
+ /** Unique ID, always starts with "rpl_". */
5
+ id: string;
6
+ /** The run ID that was replayed. */
7
+ origin_run_id: string;
8
+ /** The workflow ID of the origin run. */
9
+ workflow_id: string;
10
+ /** The overrides that were applied: ["step.field=value", ...] — raw string form. */
11
+ overrides: string[];
12
+ /** The step-level results from replayRun(). */
13
+ results: ReplayStepResult[];
14
+ /** ISO 8601 creation timestamp. */
15
+ created_at: string;
16
+ }
17
+ export interface ReplayStore {
18
+ /** Persist a replay record. Returns the stored record with its assigned ID. */
19
+ save(record: Omit<ReplayRecord, 'id' | 'created_at'>): Promise<ReplayRecord>;
20
+ /** Get a replay record by ID. Throws a plain Error if not found (not a WorkflowError). */
21
+ get(replayId: string): Promise<ReplayRecord>;
22
+ }
23
+ export declare class JsonFileReplayStore implements ReplayStore {
24
+ private readonly replaysDir;
25
+ constructor(replaysDir?: string);
26
+ save(record: Omit<ReplayRecord, 'id' | 'created_at'>): Promise<ReplayRecord>;
27
+ get(replayId: string): Promise<ReplayRecord>;
28
+ }
29
+ //# sourceMappingURL=replay-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-store.d.ts","sourceRoot":"","sources":["../../src/store/replay-store.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,8FAA8F;AAC9F,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,oCAAoC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,oFAAoF;IACpF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,+CAA+C;IAC/C,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7E,0FAA0F;IAC1F,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC9C;AAID,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,UAAU,CAAC,EAAE,MAAM;IAIzB,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAS5E,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CASnD"}
@@ -0,0 +1,31 @@
1
+ // ReplayStore — interface and JsonFileReplayStore for persisting replay results locally.
2
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { randomUUID } from 'node:crypto';
6
+ const DEFAULT_REPLAYS_DIR = join(homedir(), '.realm', 'replays');
7
+ export class JsonFileReplayStore {
8
+ replaysDir;
9
+ constructor(replaysDir) {
10
+ this.replaysDir = replaysDir ?? DEFAULT_REPLAYS_DIR;
11
+ }
12
+ async save(record) {
13
+ await mkdir(this.replaysDir, { recursive: true });
14
+ const id = `rpl_${randomUUID()}`;
15
+ const created_at = new Date().toISOString();
16
+ const full = { ...record, id, created_at };
17
+ await writeFile(join(this.replaysDir, `${id}.json`), JSON.stringify(full, null, 2), 'utf8');
18
+ return full;
19
+ }
20
+ async get(replayId) {
21
+ const filePath = join(this.replaysDir, `${replayId}.json`);
22
+ try {
23
+ const content = await readFile(filePath, 'utf8');
24
+ return JSON.parse(content);
25
+ }
26
+ catch {
27
+ throw new Error(`Replay not found: ${replayId}`);
28
+ }
29
+ }
30
+ }
31
+ //# sourceMappingURL=replay-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-store.js","sourceRoot":"","sources":["../../src/store/replay-store.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0BzC,MAAM,mBAAmB,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEjE,MAAM,OAAO,mBAAmB;IACb,UAAU,CAAS;IAEpC,YAAY,UAAmB;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,mBAAmB,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAA+C;QACxD,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,EAAE,GAAG,OAAO,UAAU,EAAE,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAiB,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;QACzD,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAgB;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;QAC3D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACjD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAiB,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;CACF"}