@codemieai/code 0.0.14 → 0.0.15

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 (173) hide show
  1. package/README.md +8 -6
  2. package/dist/agents/codemie-code/agent.d.ts.map +1 -1
  3. package/dist/agents/codemie-code/agent.js +4 -4
  4. package/dist/agents/codemie-code/agent.js.map +1 -1
  5. package/dist/agents/codemie-code/config.d.ts.map +1 -1
  6. package/dist/agents/codemie-code/config.js +2 -1
  7. package/dist/agents/codemie-code/config.js.map +1 -1
  8. package/dist/agents/codemie-code/filters.js +12 -12
  9. package/dist/agents/codemie-code/filters.js.map +1 -1
  10. package/dist/agents/codemie-code/index.d.ts.map +1 -1
  11. package/dist/agents/codemie-code/index.js +3 -1
  12. package/dist/agents/codemie-code/index.js.map +1 -1
  13. package/dist/agents/codemie-code/storage/todoStorage.js +1 -1
  14. package/dist/agents/codemie-code/storage/todoStorage.js.map +1 -1
  15. package/dist/agents/codemie-code/tools/planning.d.ts +1 -1
  16. package/dist/agents/codemie-code/ui.js +1 -1
  17. package/dist/agents/codemie-code/ui.js.map +1 -1
  18. package/dist/agents/core/AgentCLI.js +1 -1
  19. package/dist/agents/core/AgentCLI.js.map +1 -1
  20. package/dist/agents/core/types.d.ts +5 -0
  21. package/dist/agents/core/types.d.ts.map +1 -1
  22. package/dist/agents/plugins/codemie-code.plugin.js +1 -1
  23. package/dist/agents/plugins/codemie-code.plugin.js.map +1 -1
  24. package/dist/analytics/aggregation/adapters/claude.adapter.d.ts.map +1 -1
  25. package/dist/analytics/aggregation/adapters/claude.adapter.js +75 -15
  26. package/dist/analytics/aggregation/adapters/claude.adapter.js.map +1 -1
  27. package/dist/analytics/aggregation/adapters/codex.adapter.d.ts.map +1 -1
  28. package/dist/analytics/aggregation/adapters/codex.adapter.js +20 -0
  29. package/dist/analytics/aggregation/adapters/codex.adapter.js.map +1 -1
  30. package/dist/analytics/aggregation/adapters/gemini.adapter.d.ts +8 -0
  31. package/dist/analytics/aggregation/adapters/gemini.adapter.d.ts.map +1 -1
  32. package/dist/analytics/aggregation/adapters/gemini.adapter.js +46 -1
  33. package/dist/analytics/aggregation/adapters/gemini.adapter.js.map +1 -1
  34. package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.d.ts +36 -0
  35. package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.d.ts.map +1 -1
  36. package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.js +52 -0
  37. package/dist/analytics/aggregation/core/BaseAnalyticsAdapter.js.map +1 -1
  38. package/dist/analytics/aggregation/core/adapter.interface.d.ts +11 -0
  39. package/dist/analytics/aggregation/core/adapter.interface.d.ts.map +1 -1
  40. package/dist/analytics/aggregation/core/aggregation-utils.d.ts +20 -0
  41. package/dist/analytics/aggregation/core/aggregation-utils.d.ts.map +1 -1
  42. package/dist/analytics/aggregation/core/aggregation-utils.js +43 -0
  43. package/dist/analytics/aggregation/core/aggregation-utils.js.map +1 -1
  44. package/dist/analytics/aggregation/core/file-utils.d.ts +2 -1
  45. package/dist/analytics/aggregation/core/file-utils.d.ts.map +1 -1
  46. package/dist/analytics/aggregation/core/file-utils.js +20 -85
  47. package/dist/analytics/aggregation/core/file-utils.js.map +1 -1
  48. package/dist/analytics/aggregation/core/index.d.ts +3 -0
  49. package/dist/analytics/aggregation/core/index.d.ts.map +1 -1
  50. package/dist/analytics/aggregation/core/index.js +3 -0
  51. package/dist/analytics/aggregation/core/index.js.map +1 -1
  52. package/dist/analytics/aggregation/core/user-prompt-source.d.ts +81 -0
  53. package/dist/analytics/aggregation/core/user-prompt-source.d.ts.map +1 -0
  54. package/dist/analytics/aggregation/core/user-prompt-source.js +69 -0
  55. package/dist/analytics/aggregation/core/user-prompt-source.js.map +1 -0
  56. package/dist/analytics/aggregation/core/user-prompt-sources/json.d.ts +49 -0
  57. package/dist/analytics/aggregation/core/user-prompt-sources/json.d.ts.map +1 -0
  58. package/dist/analytics/aggregation/core/user-prompt-sources/json.js +66 -0
  59. package/dist/analytics/aggregation/core/user-prompt-sources/json.js.map +1 -0
  60. package/dist/analytics/aggregation/core/user-prompt-sources/jsonl.d.ts +43 -0
  61. package/dist/analytics/aggregation/core/user-prompt-sources/jsonl.d.ts.map +1 -0
  62. package/dist/analytics/aggregation/core/user-prompt-sources/jsonl.js +56 -0
  63. package/dist/analytics/aggregation/core/user-prompt-sources/jsonl.js.map +1 -0
  64. package/dist/analytics/aggregation/types.d.ts +20 -0
  65. package/dist/analytics/aggregation/types.d.ts.map +1 -1
  66. package/dist/analytics/remote-submission/cursor-manager.d.ts +71 -0
  67. package/dist/analytics/remote-submission/cursor-manager.d.ts.map +1 -0
  68. package/dist/analytics/remote-submission/cursor-manager.js +204 -0
  69. package/dist/analytics/remote-submission/cursor-manager.js.map +1 -0
  70. package/dist/analytics/remote-submission/index.d.ts +12 -0
  71. package/dist/analytics/remote-submission/index.d.ts.map +1 -0
  72. package/dist/analytics/remote-submission/index.js +11 -0
  73. package/dist/analytics/remote-submission/index.js.map +1 -0
  74. package/dist/analytics/remote-submission/lock-manager.d.ts +71 -0
  75. package/dist/analytics/remote-submission/lock-manager.d.ts.map +1 -0
  76. package/dist/analytics/remote-submission/lock-manager.js +238 -0
  77. package/dist/analytics/remote-submission/lock-manager.js.map +1 -0
  78. package/dist/analytics/remote-submission/metric-transformer.d.ts +49 -0
  79. package/dist/analytics/remote-submission/metric-transformer.d.ts.map +1 -0
  80. package/dist/analytics/remote-submission/metric-transformer.js +175 -0
  81. package/dist/analytics/remote-submission/metric-transformer.js.map +1 -0
  82. package/dist/analytics/remote-submission/submitter.d.ts +78 -0
  83. package/dist/analytics/remote-submission/submitter.d.ts.map +1 -0
  84. package/dist/analytics/remote-submission/submitter.js +381 -0
  85. package/dist/analytics/remote-submission/submitter.js.map +1 -0
  86. package/dist/analytics/remote-submission/types.d.ts +169 -0
  87. package/dist/analytics/remote-submission/types.d.ts.map +1 -0
  88. package/dist/analytics/remote-submission/types.js +13 -0
  89. package/dist/analytics/remote-submission/types.js.map +1 -0
  90. package/dist/cli/commands/analytics.d.ts.map +1 -1
  91. package/dist/cli/commands/analytics.js +181 -12
  92. package/dist/cli/commands/analytics.js.map +1 -1
  93. package/dist/cli/commands/doctor/index.d.ts.map +1 -1
  94. package/dist/cli/commands/doctor/index.js +13 -1
  95. package/dist/cli/commands/doctor/index.js.map +1 -1
  96. package/dist/cli/commands/doctor/providers/AIRunSSOProviderCheck.d.ts.map +1 -1
  97. package/dist/cli/commands/doctor/providers/AIRunSSOProviderCheck.js +81 -9
  98. package/dist/cli/commands/doctor/providers/AIRunSSOProviderCheck.js.map +1 -1
  99. package/dist/cli/commands/profile.d.ts.map +1 -1
  100. package/dist/cli/commands/profile.js +25 -57
  101. package/dist/cli/commands/profile.js.map +1 -1
  102. package/dist/cli/commands/setup.d.ts.map +1 -1
  103. package/dist/cli/commands/setup.js +10 -0
  104. package/dist/cli/commands/setup.js.map +1 -1
  105. package/dist/cli/commands/workflow.js +1 -1
  106. package/dist/cli/commands/workflow.js.map +1 -1
  107. package/dist/cli/index.js +0 -4
  108. package/dist/cli/index.js.map +1 -1
  109. package/dist/utils/analytics-reader.js +1 -1
  110. package/dist/utils/analytics-reader.js.map +1 -1
  111. package/dist/utils/codemie-model-fetcher.d.ts.map +1 -1
  112. package/dist/utils/codemie-model-fetcher.js +197 -122
  113. package/dist/utils/codemie-model-fetcher.js.map +1 -1
  114. package/dist/utils/codemie-proxy.d.ts +41 -21
  115. package/dist/utils/codemie-proxy.d.ts.map +1 -1
  116. package/dist/utils/codemie-proxy.js +151 -86
  117. package/dist/utils/codemie-proxy.js.map +1 -1
  118. package/dist/utils/config-loader.d.ts +4 -0
  119. package/dist/utils/config-loader.d.ts.map +1 -1
  120. package/dist/utils/config-loader.js +42 -2
  121. package/dist/utils/config-loader.js.map +1 -1
  122. package/dist/utils/first-time.d.ts +0 -4
  123. package/dist/utils/first-time.d.ts.map +1 -1
  124. package/dist/utils/first-time.js +5 -117
  125. package/dist/utils/first-time.js.map +1 -1
  126. package/dist/utils/logger.d.ts +31 -1
  127. package/dist/utils/logger.d.ts.map +1 -1
  128. package/dist/utils/logger.js +112 -2
  129. package/dist/utils/logger.js.map +1 -1
  130. package/dist/utils/proxy/plugins/analytics.plugin.d.ts +19 -0
  131. package/dist/utils/proxy/plugins/analytics.plugin.d.ts.map +1 -0
  132. package/dist/utils/proxy/plugins/analytics.plugin.js +84 -0
  133. package/dist/utils/proxy/plugins/analytics.plugin.js.map +1 -0
  134. package/dist/utils/proxy/plugins/header-injection.plugin.d.ts +16 -0
  135. package/dist/utils/proxy/plugins/header-injection.plugin.d.ts.map +1 -0
  136. package/dist/utils/proxy/plugins/header-injection.plugin.js +48 -0
  137. package/dist/utils/proxy/plugins/header-injection.plugin.js.map +1 -0
  138. package/dist/utils/proxy/plugins/index.d.ts +18 -0
  139. package/dist/utils/proxy/plugins/index.d.ts.map +1 -0
  140. package/dist/utils/proxy/plugins/index.js +30 -0
  141. package/dist/utils/proxy/plugins/index.js.map +1 -0
  142. package/dist/utils/proxy/plugins/registry.d.ts +50 -0
  143. package/dist/utils/proxy/plugins/registry.d.ts.map +1 -0
  144. package/dist/utils/proxy/plugins/registry.js +124 -0
  145. package/dist/utils/proxy/plugins/registry.js.map +1 -0
  146. package/dist/utils/proxy/plugins/sso-auth.plugin.d.ts +16 -0
  147. package/dist/utils/proxy/plugins/sso-auth.plugin.d.ts.map +1 -0
  148. package/dist/utils/proxy/plugins/sso-auth.plugin.js +35 -0
  149. package/dist/utils/proxy/plugins/sso-auth.plugin.js.map +1 -0
  150. package/dist/utils/proxy/plugins/types.d.ts +79 -0
  151. package/dist/utils/proxy/plugins/types.d.ts.map +1 -0
  152. package/dist/utils/proxy/plugins/types.js +8 -0
  153. package/dist/utils/proxy/plugins/types.js.map +1 -0
  154. package/dist/utils/sanitize.d.ts +28 -0
  155. package/dist/utils/sanitize.d.ts.map +1 -0
  156. package/dist/utils/sanitize.js +213 -0
  157. package/dist/utils/sanitize.js.map +1 -0
  158. package/dist/workflows/installer.d.ts.map +1 -1
  159. package/dist/workflows/installer.js +3 -4
  160. package/dist/workflows/installer.js.map +1 -1
  161. package/package.json +1 -1
  162. package/dist/cli/commands/config.d.ts +0 -3
  163. package/dist/cli/commands/config.d.ts.map +0 -1
  164. package/dist/cli/commands/config.js +0 -198
  165. package/dist/cli/commands/config.js.map +0 -1
  166. package/dist/cli/commands/env.d.ts +0 -3
  167. package/dist/cli/commands/env.d.ts.map +0 -1
  168. package/dist/cli/commands/env.js +0 -19
  169. package/dist/cli/commands/env.js.map +0 -1
  170. package/dist/utils/proxy/interceptors.d.ts +0 -69
  171. package/dist/utils/proxy/interceptors.d.ts.map +0 -1
  172. package/dist/utils/proxy/interceptors.js +0 -308
  173. package/dist/utils/proxy/interceptors.js.map +0 -1
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Cursor Manager - Event-Level Tracking
3
+ *
4
+ * Manages cursor state for tracking which events have been submitted
5
+ * to prevent duplicate submissions across concurrent proxy instances.
6
+ *
7
+ * Uses event-level tracking (message IDs, tool call IDs) instead of
8
+ * session-level hashes to handle incremental session updates correctly.
9
+ */
10
+ import type { CursorState, AgentCursorState, SessionSubmissionState } from './types.js';
11
+ /**
12
+ * Cursor Manager
13
+ */
14
+ export declare class CursorManager {
15
+ private cursorPath;
16
+ constructor(analyticsDir?: string);
17
+ /**
18
+ * Ensure cursor directory exists
19
+ */
20
+ private ensureDir;
21
+ /**
22
+ * Load cursor state from disk
23
+ */
24
+ load(): Promise<CursorState>;
25
+ /**
26
+ * Save cursor state to disk
27
+ */
28
+ save(cursor: CursorState): Promise<void>;
29
+ /**
30
+ * Get or create agent cursor state
31
+ */
32
+ getAgentCursor(cursor: CursorState, agentName: string): AgentCursorState;
33
+ /**
34
+ * Get or create session submission state
35
+ */
36
+ getSessionState(agentCursor: AgentCursorState, sessionId: string): SessionSubmissionState;
37
+ /**
38
+ * Update session state with sent events
39
+ */
40
+ updateSessionState(cursor: CursorState, agentName: string, sessionId: string, updates: {
41
+ newMessageIds?: string[];
42
+ newToolCallIds?: string[];
43
+ metricsSubmitted: number;
44
+ lastActivityTime: string;
45
+ sessionMetrics?: Partial<SessionSubmissionState['sessionMetrics']>;
46
+ }): void;
47
+ /**
48
+ * Check if event was already sent
49
+ */
50
+ isEventSent(sessionState: SessionSubmissionState, eventId: string, eventType: 'message' | 'toolCall'): boolean;
51
+ /**
52
+ * Filter events to only include those not yet sent
53
+ */
54
+ filterNewEvents<T extends {
55
+ messageId?: string;
56
+ toolCallId?: string;
57
+ }>(events: T[], sessionState: SessionSubmissionState, eventType: 'message' | 'toolCall'): T[];
58
+ /**
59
+ * Increment failure count
60
+ */
61
+ recordFailure(cursor: CursorState): void;
62
+ /**
63
+ * Reset failure count
64
+ */
65
+ resetFailures(cursor: CursorState): void;
66
+ /**
67
+ * Update scan timestamp for agent
68
+ */
69
+ updateScanTime(cursor: CursorState, agentName: string): void;
70
+ }
71
+ //# sourceMappingURL=cursor-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-manager.d.ts","sourceRoot":"","sources":["../../../src/analytics/remote-submission/cursor-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAmDpB;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAS;gBAEf,YAAY,CAAC,EAAE,MAAM;IAKjC;;OAEG;YACW,SAAS;IAOvB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAwBlC;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAa9C;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB;IAOxE;;OAEG;IACH,eAAe,CACb,WAAW,EAAE,gBAAgB,EAC7B,SAAS,EAAE,MAAM,GAChB,sBAAsB;IAOzB;;OAEG;IACH,kBAAkB,CAChB,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;QACP,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,gBAAgB,CAAC,CAAC,CAAC;KACpE,GACA,IAAI;IA8BP;;OAEG;IACH,WAAW,CACT,YAAY,EAAE,sBAAsB,EACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,GAAG,UAAU,GAChC,OAAO;IAQV;;OAEG;IACH,eAAe,CAAC,CAAC,SAAS;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EACnE,MAAM,EAAE,CAAC,EAAE,EACX,YAAY,EAAE,sBAAsB,EACpC,SAAS,EAAE,SAAS,GAAG,UAAU,GAChC,CAAC,EAAE;IAYN;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIxC;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIxC;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;CAI7D"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Cursor Manager - Event-Level Tracking
3
+ *
4
+ * Manages cursor state for tracking which events have been submitted
5
+ * to prevent duplicate submissions across concurrent proxy instances.
6
+ *
7
+ * Uses event-level tracking (message IDs, tool call IDs) instead of
8
+ * session-level hashes to handle incremental session updates correctly.
9
+ */
10
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
11
+ import { existsSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { homedir } from 'node:os';
14
+ import { logger } from '../../utils/logger.js';
15
+ /**
16
+ * Default cursor state
17
+ */
18
+ function createDefaultCursor() {
19
+ return {
20
+ version: 2,
21
+ lastRun: new Date().toISOString(),
22
+ agents: {},
23
+ stats: {
24
+ totalSessionsSubmitted: 0,
25
+ totalMetricsSubmitted: 0,
26
+ consecutiveFailures: 0
27
+ }
28
+ };
29
+ }
30
+ /**
31
+ * Default agent cursor state
32
+ */
33
+ function createDefaultAgentCursor() {
34
+ return {
35
+ lastScan: new Date().toISOString(),
36
+ sessions: {}
37
+ };
38
+ }
39
+ /**
40
+ * Default session submission state
41
+ */
42
+ function createDefaultSessionState() {
43
+ return {
44
+ submitted: false,
45
+ timestamp: new Date().toISOString(),
46
+ sentEventIds: {
47
+ messages: [],
48
+ toolCalls: []
49
+ },
50
+ sessionMetrics: {
51
+ timeoutSent: false,
52
+ resumedSent: false,
53
+ completedSent: false
54
+ },
55
+ lastActivityTime: new Date().toISOString(),
56
+ metricsSubmitted: 0,
57
+ lastUpdate: new Date().toISOString()
58
+ };
59
+ }
60
+ /**
61
+ * Cursor Manager
62
+ */
63
+ export class CursorManager {
64
+ cursorPath;
65
+ constructor(analyticsDir) {
66
+ const baseDir = analyticsDir || join(homedir(), '.codemie', 'analytics');
67
+ this.cursorPath = join(baseDir, '.remote', 'cursor.json');
68
+ }
69
+ /**
70
+ * Ensure cursor directory exists
71
+ */
72
+ async ensureDir() {
73
+ const dir = join(this.cursorPath, '..');
74
+ if (!existsSync(dir)) {
75
+ await mkdir(dir, { recursive: true });
76
+ }
77
+ }
78
+ /**
79
+ * Load cursor state from disk
80
+ */
81
+ async load() {
82
+ await this.ensureDir();
83
+ if (!existsSync(this.cursorPath)) {
84
+ return createDefaultCursor();
85
+ }
86
+ try {
87
+ const content = await readFile(this.cursorPath, 'utf-8');
88
+ const cursor = JSON.parse(content);
89
+ // Validate version
90
+ if (cursor.version !== 2) {
91
+ logger.debug(`Cursor version ${cursor.version} not supported, resetting`);
92
+ return createDefaultCursor();
93
+ }
94
+ return cursor;
95
+ }
96
+ catch (error) {
97
+ logger.debug(`Failed to load cursor: ${error}`);
98
+ return createDefaultCursor();
99
+ }
100
+ }
101
+ /**
102
+ * Save cursor state to disk
103
+ */
104
+ async save(cursor) {
105
+ await this.ensureDir();
106
+ try {
107
+ cursor.lastRun = new Date().toISOString();
108
+ const content = JSON.stringify(cursor, null, 2);
109
+ await writeFile(this.cursorPath, content, 'utf-8');
110
+ }
111
+ catch (error) {
112
+ logger.debug(`Failed to save cursor: ${error}`);
113
+ throw error;
114
+ }
115
+ }
116
+ /**
117
+ * Get or create agent cursor state
118
+ */
119
+ getAgentCursor(cursor, agentName) {
120
+ if (!cursor.agents[agentName]) {
121
+ cursor.agents[agentName] = createDefaultAgentCursor();
122
+ }
123
+ return cursor.agents[agentName];
124
+ }
125
+ /**
126
+ * Get or create session submission state
127
+ */
128
+ getSessionState(agentCursor, sessionId) {
129
+ if (!agentCursor.sessions[sessionId]) {
130
+ agentCursor.sessions[sessionId] = createDefaultSessionState();
131
+ }
132
+ return agentCursor.sessions[sessionId];
133
+ }
134
+ /**
135
+ * Update session state with sent events
136
+ */
137
+ updateSessionState(cursor, agentName, sessionId, updates) {
138
+ const agentCursor = this.getAgentCursor(cursor, agentName);
139
+ const sessionState = this.getSessionState(agentCursor, sessionId);
140
+ // Append new event IDs
141
+ if (updates.newMessageIds) {
142
+ sessionState.sentEventIds.messages.push(...updates.newMessageIds);
143
+ }
144
+ if (updates.newToolCallIds) {
145
+ sessionState.sentEventIds.toolCalls.push(...updates.newToolCallIds);
146
+ }
147
+ // Update session metrics
148
+ if (updates.sessionMetrics) {
149
+ sessionState.sessionMetrics = {
150
+ ...sessionState.sessionMetrics,
151
+ ...updates.sessionMetrics
152
+ };
153
+ }
154
+ // Update metadata
155
+ sessionState.submitted = true;
156
+ sessionState.metricsSubmitted += updates.metricsSubmitted;
157
+ sessionState.lastActivityTime = updates.lastActivityTime;
158
+ sessionState.lastUpdate = new Date().toISOString();
159
+ // Update global stats
160
+ cursor.stats.totalMetricsSubmitted += updates.metricsSubmitted;
161
+ }
162
+ /**
163
+ * Check if event was already sent
164
+ */
165
+ isEventSent(sessionState, eventId, eventType) {
166
+ const sentIds = eventType === 'message'
167
+ ? sessionState.sentEventIds.messages
168
+ : sessionState.sentEventIds.toolCalls;
169
+ return sentIds.includes(eventId);
170
+ }
171
+ /**
172
+ * Filter events to only include those not yet sent
173
+ */
174
+ filterNewEvents(events, sessionState, eventType) {
175
+ return events.filter(event => {
176
+ const eventId = eventType === 'message'
177
+ ? event.messageId
178
+ : event.toolCallId;
179
+ if (!eventId)
180
+ return false;
181
+ return !this.isEventSent(sessionState, eventId, eventType);
182
+ });
183
+ }
184
+ /**
185
+ * Increment failure count
186
+ */
187
+ recordFailure(cursor) {
188
+ cursor.stats.consecutiveFailures++;
189
+ }
190
+ /**
191
+ * Reset failure count
192
+ */
193
+ resetFailures(cursor) {
194
+ cursor.stats.consecutiveFailures = 0;
195
+ }
196
+ /**
197
+ * Update scan timestamp for agent
198
+ */
199
+ updateScanTime(cursor, agentName) {
200
+ const agentCursor = this.getAgentCursor(cursor, agentName);
201
+ agentCursor.lastScan = new Date().toISOString();
202
+ }
203
+ }
204
+ //# sourceMappingURL=cursor-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-manager.js","sourceRoot":"","sources":["../../../src/analytics/remote-submission/cursor-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Remote Analytics Submission System
3
+ *
4
+ * Scheduled submission of analytics metrics to /v1/metrics endpoint
5
+ * with event-level tracking and backend-aligned metric transformation.
6
+ */
7
+ export { RemoteAnalyticsSubmitter } from './submitter.js';
8
+ export { CursorManager } from './cursor-manager.js';
9
+ export { LockManager } from './lock-manager.js';
10
+ export { transformSessionToMetrics, createSessionMetric } from './metric-transformer.js';
11
+ export type { MetricPayload, MetricName, BaseMetricAttributes, ToolSuccessAttributes, TokenMetricAttributes, ToolErrorAttributes, SessionMetricAttributes, CursorState, AgentCursorState, SessionSubmissionState, LockInfo, RemoteSubmissionConfig, SessionStatus } from './types.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/analytics/remote-submission/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACzF,YAAY,EACV,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,sBAAsB,EACtB,QAAQ,EACR,sBAAsB,EACtB,aAAa,EACd,MAAM,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Remote Analytics Submission System
3
+ *
4
+ * Scheduled submission of analytics metrics to /v1/metrics endpoint
5
+ * with event-level tracking and backend-aligned metric transformation.
6
+ */
7
+ export { RemoteAnalyticsSubmitter } from './submitter.js';
8
+ export { CursorManager } from './cursor-manager.js';
9
+ export { LockManager } from './lock-manager.js';
10
+ export { transformSessionToMetrics, createSessionMetric } from './metric-transformer.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analytics/remote-submission/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Lock Manager - File-Based Locking for Concurrency Control
3
+ *
4
+ * Implements file-based locking to ensure only one RemoteAnalyticsSubmitter
5
+ * runs at a time across multiple concurrent proxy instances.
6
+ *
7
+ * Features:
8
+ * - Exclusive lock acquisition with retries
9
+ * - Stale lock detection and recovery
10
+ * - Process liveness checking
11
+ * - Heartbeat to prevent false stale detection
12
+ * - Graceful cleanup on exit signals
13
+ */
14
+ /**
15
+ * Lock Manager
16
+ */
17
+ export declare class LockManager {
18
+ private lockPath;
19
+ private lockInfo;
20
+ private heartbeatTimer;
21
+ constructor(analyticsDir?: string);
22
+ /**
23
+ * Ensure lock directory exists
24
+ */
25
+ private ensureDir;
26
+ /**
27
+ * Check if a process is alive
28
+ */
29
+ private isProcessAlive;
30
+ /**
31
+ * Read lock file
32
+ */
33
+ private readLock;
34
+ /**
35
+ * Write lock file
36
+ */
37
+ private writeLock;
38
+ /**
39
+ * Remove lock file
40
+ */
41
+ private removeLock;
42
+ /**
43
+ * Check if lock is stale (old or process dead)
44
+ */
45
+ private isLockStale;
46
+ /**
47
+ * Start heartbeat to refresh lock timestamp
48
+ */
49
+ private startHeartbeat;
50
+ /**
51
+ * Stop heartbeat
52
+ */
53
+ private stopHeartbeat;
54
+ /**
55
+ * Acquire lock with retry
56
+ *
57
+ * @param name Lock name (for logging)
58
+ * @param maxRetries Maximum number of retries
59
+ * @returns true if lock acquired, false if failed
60
+ */
61
+ acquire(name: string, maxRetries?: number): Promise<boolean>;
62
+ /**
63
+ * Release lock
64
+ */
65
+ release(): Promise<void>;
66
+ /**
67
+ * Setup exit handlers to release lock on process termination
68
+ */
69
+ private setupExitHandlers;
70
+ }
71
+ //# sourceMappingURL=lock-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-manager.d.ts","sourceRoot":"","sources":["../../../src/analytics/remote-submission/lock-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,cAAc,CAA+B;gBAEzC,YAAY,CAAC,EAAE,MAAM;IAKjC;;OAEG;YACW,SAAS;IAOvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;YACW,QAAQ;IActB;;OAEG;YACW,SAAS;IAMvB;;OAEG;YACW,UAAU;IAUxB;;OAEG;YACW,WAAW;IAezB;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAyE7D;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAe9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAU1B"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Lock Manager - File-Based Locking for Concurrency Control
3
+ *
4
+ * Implements file-based locking to ensure only one RemoteAnalyticsSubmitter
5
+ * runs at a time across multiple concurrent proxy instances.
6
+ *
7
+ * Features:
8
+ * - Exclusive lock acquisition with retries
9
+ * - Stale lock detection and recovery
10
+ * - Process liveness checking
11
+ * - Heartbeat to prevent false stale detection
12
+ * - Graceful cleanup on exit signals
13
+ */
14
+ import { readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
15
+ import { existsSync } from 'node:fs';
16
+ import { join } from 'node:path';
17
+ import { homedir, hostname } from 'node:os';
18
+ import { logger } from '../../utils/logger.js';
19
+ const LOCK_TIMEOUT = 5 * 60 * 1000; // 5 minutes
20
+ const RETRY_DELAY = 2000; // 2 seconds
21
+ const HEARTBEAT_INTERVAL = 30 * 1000; // 30 seconds
22
+ /**
23
+ * Lock Manager
24
+ */
25
+ export class LockManager {
26
+ lockPath;
27
+ lockInfo = null;
28
+ heartbeatTimer = null;
29
+ constructor(analyticsDir) {
30
+ const baseDir = analyticsDir || join(homedir(), '.codemie', 'analytics');
31
+ this.lockPath = join(baseDir, '.remote', '.lock');
32
+ }
33
+ /**
34
+ * Ensure lock directory exists
35
+ */
36
+ async ensureDir() {
37
+ const dir = join(this.lockPath, '..');
38
+ if (!existsSync(dir)) {
39
+ await mkdir(dir, { recursive: true });
40
+ }
41
+ }
42
+ /**
43
+ * Check if a process is alive
44
+ */
45
+ isProcessAlive(pid) {
46
+ try {
47
+ // kill(pid, 0) doesn't actually kill, just checks if process exists
48
+ process.kill(pid, 0);
49
+ return true;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ /**
56
+ * Read lock file
57
+ */
58
+ async readLock() {
59
+ if (!existsSync(this.lockPath)) {
60
+ return null;
61
+ }
62
+ try {
63
+ const content = await readFile(this.lockPath, 'utf-8');
64
+ return JSON.parse(content);
65
+ }
66
+ catch (error) {
67
+ logger.debug(`Failed to read lock file: ${error}`);
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * Write lock file
73
+ */
74
+ async writeLock(lockInfo) {
75
+ await this.ensureDir();
76
+ const content = JSON.stringify(lockInfo, null, 2);
77
+ await writeFile(this.lockPath, content, 'utf-8');
78
+ }
79
+ /**
80
+ * Remove lock file
81
+ */
82
+ async removeLock() {
83
+ if (existsSync(this.lockPath)) {
84
+ try {
85
+ await unlink(this.lockPath);
86
+ }
87
+ catch (error) {
88
+ logger.debug(`Failed to remove lock: ${error}`);
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Check if lock is stale (old or process dead)
94
+ */
95
+ async isLockStale(lockInfo) {
96
+ // Check age
97
+ const age = Date.now() - new Date(lockInfo.timestamp).getTime();
98
+ if (age > LOCK_TIMEOUT) {
99
+ return true;
100
+ }
101
+ // Check if process is alive
102
+ if (!this.isProcessAlive(lockInfo.pid)) {
103
+ return true;
104
+ }
105
+ return false;
106
+ }
107
+ /**
108
+ * Start heartbeat to refresh lock timestamp
109
+ */
110
+ startHeartbeat() {
111
+ this.heartbeatTimer = setInterval(async () => {
112
+ if (this.lockInfo) {
113
+ this.lockInfo.timestamp = new Date().toISOString();
114
+ try {
115
+ await this.writeLock(this.lockInfo);
116
+ }
117
+ catch (error) {
118
+ logger.debug(`Heartbeat failed: ${error}`);
119
+ }
120
+ }
121
+ }, HEARTBEAT_INTERVAL);
122
+ // Ensure heartbeat doesn't prevent process exit
123
+ this.heartbeatTimer.unref();
124
+ }
125
+ /**
126
+ * Stop heartbeat
127
+ */
128
+ stopHeartbeat() {
129
+ if (this.heartbeatTimer) {
130
+ clearInterval(this.heartbeatTimer);
131
+ this.heartbeatTimer = null;
132
+ }
133
+ }
134
+ /**
135
+ * Acquire lock with retry
136
+ *
137
+ * @param name Lock name (for logging)
138
+ * @param maxRetries Maximum number of retries
139
+ * @returns true if lock acquired, false if failed
140
+ */
141
+ async acquire(name, maxRetries = 3) {
142
+ let attempts = 0;
143
+ while (attempts < maxRetries) {
144
+ attempts++;
145
+ // Check existing lock
146
+ const existingLock = await this.readLock();
147
+ if (existingLock) {
148
+ // Check if stale
149
+ if (await this.isLockStale(existingLock)) {
150
+ logger.debug(`Removing stale lock from ${existingLock.agent} (PID ${existingLock.pid})`);
151
+ await this.removeLock();
152
+ }
153
+ else {
154
+ // Lock is valid, wait and retry
155
+ if (attempts < maxRetries) {
156
+ logger.debug(`Lock held by ${existingLock.agent} (PID ${existingLock.pid}), ` +
157
+ `waiting ${RETRY_DELAY}ms (attempt ${attempts}/${maxRetries})`);
158
+ await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
159
+ continue;
160
+ }
161
+ else {
162
+ logger.debug(`Could not acquire lock after ${maxRetries} attempts`);
163
+ return false;
164
+ }
165
+ }
166
+ }
167
+ // Try to acquire lock
168
+ this.lockInfo = {
169
+ pid: process.pid,
170
+ timestamp: new Date().toISOString(),
171
+ hostname: hostname(),
172
+ agent: name
173
+ };
174
+ try {
175
+ await this.writeLock(this.lockInfo);
176
+ // Verify we own the lock (race condition check)
177
+ const verifyLock = await this.readLock();
178
+ if (verifyLock?.pid === process.pid) {
179
+ logger.debug(`Lock acquired by ${name} (PID ${process.pid})`);
180
+ this.startHeartbeat();
181
+ this.setupExitHandlers();
182
+ return true;
183
+ }
184
+ else {
185
+ // Someone else got the lock first
186
+ this.lockInfo = null;
187
+ if (attempts < maxRetries) {
188
+ await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
189
+ continue;
190
+ }
191
+ else {
192
+ return false;
193
+ }
194
+ }
195
+ }
196
+ catch (error) {
197
+ logger.debug(`Failed to acquire lock: ${error}`);
198
+ this.lockInfo = null;
199
+ if (attempts < maxRetries) {
200
+ await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
201
+ continue;
202
+ }
203
+ else {
204
+ return false;
205
+ }
206
+ }
207
+ }
208
+ return false;
209
+ }
210
+ /**
211
+ * Release lock
212
+ */
213
+ async release() {
214
+ this.stopHeartbeat();
215
+ if (this.lockInfo) {
216
+ // Verify we still own the lock
217
+ const currentLock = await this.readLock();
218
+ if (currentLock?.pid === process.pid) {
219
+ await this.removeLock();
220
+ logger.debug(`Lock released by ${this.lockInfo.agent} (PID ${process.pid})`);
221
+ }
222
+ this.lockInfo = null;
223
+ }
224
+ }
225
+ /**
226
+ * Setup exit handlers to release lock on process termination
227
+ */
228
+ setupExitHandlers() {
229
+ const cleanup = async () => {
230
+ await this.release();
231
+ };
232
+ // Handle various exit signals
233
+ process.once('SIGINT', cleanup);
234
+ process.once('SIGTERM', cleanup);
235
+ process.once('exit', cleanup);
236
+ }
237
+ }
238
+ //# sourceMappingURL=lock-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-manager.js","sourceRoot":"","sources":["../../../src/analytics/remote-submission/lock-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAChD,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,YAAY;AACtC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,aAAa;AAEnD;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,QAAQ,CAAS;IACjB,QAAQ,GAAoB,IAAI,CAAC;IACjC,cAAc,GAA0B,IAAI,CAAC;IAErD,YAAY,YAAqB;QAC/B,MAAM,OAAO,GAAG,YAAY,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,SAAS;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,GAAW;QAChC,IAAI,CAAC;YACH,oEAAoE;YACpE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAa,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;YACnD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,SAAS,CAAC,QAAkB;QACxC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClD,MAAM,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,WAAW,CAAC,QAAkB;QAC1C,YAAY;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAChE,IAAI,GAAG,GAAG,YAAY,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,cAAc;QACpB,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YAC3C,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBACnD,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACtC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,CAAC,qBAAqB,KAAK,EAAE,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC;QACH,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAEvB,gDAAgD;QAChD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED;;OAEG;IACK,aAAa;QACnB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACnC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,UAAU,GAAG,CAAC;QACxC,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEjB,OAAO,QAAQ,GAAG,UAAU,EAAE,CAAC;YAC7B,QAAQ,EAAE,CAAC;YAEX,sBAAsB;YACtB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YAE3C,IAAI,YAAY,EAAE,CAAC;gBACjB,iBAAiB;gBACjB,IAAI,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,CAAC;oBACzC,MAAM,CAAC,KAAK,CAAC,4BAA4B,YAAY,CAAC,KAAK,SAAS,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC;oBACzF,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACN,gCAAgC;oBAChC,IAAI,QAAQ,GAAG,UAAU,EAAE,CAAC;wBAC1B,MAAM,CAAC,KAAK,CACV,gBAAgB,YAAY,CAAC,KAAK,SAAS,YAAY,CAAC,GAAG,KAAK;4BAChE,WAAW,WAAW,eAAe,QAAQ,IAAI,UAAU,GAAG,CAC/D,CAAC;wBACF,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;wBAC/D,SAAS;oBACX,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,KAAK,CAAC,gCAAgC,UAAU,WAAW,CAAC,CAAC;wBACpE,OAAO,KAAK,CAAC;oBACf,CAAC;gBACH,CAAC;YACH,CAAC;YAED,sBAAsB;YACtB,IAAI,CAAC,QAAQ,GAAG;gBACd,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,QAAQ,EAAE,QAAQ,EAAE;gBACpB,KAAK,EAAE,IAAI;aACZ,CAAC;YAEF,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAEpC,gDAAgD;gBAChD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACzC,IAAI,UAAU,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC;oBACpC,MAAM,CAAC,KAAK,CAAC,oBAAoB,IAAI,SAAS,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;oBAC9D,IAAI,CAAC,cAAc,EAAE,CAAC;oBACtB,IAAI,CAAC,iBAAiB,EAAE,CAAC;oBACzB,OAAO,IAAI,CAAC;gBACd,CAAC;qBAAM,CAAC;oBACN,kCAAkC;oBAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;oBACrB,IAAI,QAAQ,GAAG,UAAU,EAAE,CAAC;wBAC1B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;wBAC/D,SAAS;oBACX,CAAC;yBAAM,CAAC;wBACN,OAAO,KAAK,CAAC;oBACf,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAC;gBACjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,QAAQ,GAAG,UAAU,EAAE,CAAC;oBAC1B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;oBAC/D,SAAS;gBACX,CAAC;qBAAM,CAAC;oBACN,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,+BAA+B;YAC/B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1C,IAAI,WAAW,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,EAAE,CAAC;gBACrC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxB,MAAM,CAAC,KAAK,CAAC,oBAAoB,IAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;YAC/E,CAAC;YAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,iBAAiB;QACvB,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;YACzB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACvB,CAAC,CAAC;QAEF,8BAA8B;QAC9B,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;CACF"}