kumo-cli 1.0.6 → 1.2.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 (241) hide show
  1. package/README.md +26 -13
  2. package/dist/auth/credentialsStore.js +20 -7
  3. package/dist/auth/credentialsStore.js.map +1 -1
  4. package/dist/claude/conversation.js +272 -0
  5. package/dist/claude/conversation.js.map +1 -0
  6. package/dist/claude/transcriptParser.js +140 -36
  7. package/dist/claude/transcriptParser.js.map +1 -1
  8. package/dist/commands/cliArgs.js +1 -0
  9. package/dist/commands/cliArgs.js.map +1 -1
  10. package/dist/core/config.js +1 -9
  11. package/dist/core/config.js.map +1 -1
  12. package/dist/core/logger.js +50 -21
  13. package/dist/core/logger.js.map +1 -1
  14. package/dist/core/projectFileWatcher.js +100 -36
  15. package/dist/core/projectFileWatcher.js.map +1 -1
  16. package/dist/engine/claudeArgs.js +106 -0
  17. package/dist/engine/claudeArgs.js.map +1 -0
  18. package/dist/engine/claudeBinary.js +94 -0
  19. package/dist/engine/claudeBinary.js.map +1 -0
  20. package/dist/engine/claudeConfig.js +127 -0
  21. package/dist/engine/claudeConfig.js.map +1 -0
  22. package/dist/engine/claudeLogin.js +76 -0
  23. package/dist/engine/claudeLogin.js.map +1 -0
  24. package/dist/engine/controlChannel.js +75 -0
  25. package/dist/engine/controlChannel.js.map +1 -0
  26. package/dist/engine/liveTranscript.js +150 -0
  27. package/dist/engine/liveTranscript.js.map +1 -0
  28. package/dist/engine/ndjson.js +48 -0
  29. package/dist/engine/ndjson.js.map +1 -0
  30. package/dist/engine/permissions.js +101 -0
  31. package/dist/engine/permissions.js.map +1 -0
  32. package/dist/engine/probePool.js +51 -0
  33. package/dist/engine/probePool.js.map +1 -0
  34. package/dist/engine/processTree.js +45 -0
  35. package/dist/engine/processTree.js.map +1 -0
  36. package/dist/engine/remoteConfig.js +17 -0
  37. package/dist/engine/remoteConfig.js.map +1 -0
  38. package/dist/engine/sessionManager.js +444 -0
  39. package/dist/engine/sessionManager.js.map +1 -0
  40. package/dist/engine/settingsCommands.js +260 -0
  41. package/dist/engine/settingsCommands.js.map +1 -0
  42. package/dist/engine/streamSession.js +502 -0
  43. package/dist/engine/streamSession.js.map +1 -0
  44. package/dist/engine/taskTracker.js +110 -0
  45. package/dist/engine/taskTracker.js.map +1 -0
  46. package/dist/engine/toolLabels.js +32 -0
  47. package/dist/engine/toolLabels.js.map +1 -0
  48. package/dist/handlers/controlRequest.js +17 -0
  49. package/dist/handlers/controlRequest.js.map +1 -0
  50. package/dist/handlers/fileHandlers.js +12 -0
  51. package/dist/handlers/fileHandlers.js.map +1 -1
  52. package/dist/handlers/messageRouter.js +8 -1
  53. package/dist/handlers/messageRouter.js.map +1 -1
  54. package/dist/handlers/promptImages.js +5 -91
  55. package/dist/handlers/promptImages.js.map +1 -1
  56. package/dist/handlers/runtimeHandlers.js +100 -32
  57. package/dist/handlers/runtimeHandlers.js.map +1 -1
  58. package/dist/handlers/sessionHandlers.js +85 -80
  59. package/dist/handlers/sessionHandlers.js.map +1 -1
  60. package/dist/handlers/terminalHandlers.js +9 -2
  61. package/dist/handlers/terminalHandlers.js.map +1 -1
  62. package/dist/http/httpClient.js +6 -0
  63. package/dist/http/httpClient.js.map +1 -1
  64. package/dist/index.js +87 -50
  65. package/dist/index.js.map +1 -1
  66. package/dist/pty/terminalManager.js +58 -11
  67. package/dist/pty/terminalManager.js.map +1 -1
  68. package/dist/services/bootstrapService.js +17 -1
  69. package/dist/services/bootstrapService.js.map +1 -1
  70. package/dist/services/claudeAdapterProxy.js +68 -21
  71. package/dist/services/claudeAdapterProxy.js.map +1 -1
  72. package/dist/services/cliRuntime.js +39 -32
  73. package/dist/services/cliRuntime.js.map +1 -1
  74. package/dist/services/effortService.js +13 -60
  75. package/dist/services/effortService.js.map +1 -1
  76. package/dist/services/fileService.js +50 -24
  77. package/dist/services/fileService.js.map +1 -1
  78. package/dist/services/forkService.js +120 -0
  79. package/dist/services/forkService.js.map +1 -0
  80. package/dist/services/modelService.js +86 -89
  81. package/dist/services/modelService.js.map +1 -1
  82. package/dist/services/pairingService.js +21 -15
  83. package/dist/services/pairingService.js.map +1 -1
  84. package/dist/services/sessionListService.js +7 -9
  85. package/dist/services/sessionListService.js.map +1 -1
  86. package/dist/services/sessionService.js +245 -106
  87. package/dist/services/sessionService.js.map +1 -1
  88. package/dist/services/tunnelHelpers.js +9 -5
  89. package/dist/services/tunnelHelpers.js.map +1 -1
  90. package/dist/services/tunnelService.js +21 -5
  91. package/dist/services/tunnelService.js.map +1 -1
  92. package/dist/transport/wsClient.js +60 -42
  93. package/dist/transport/wsClient.js.map +1 -1
  94. package/dist/utils/ignorePaths.js +3 -3
  95. package/dist/utils/ignorePaths.js.map +1 -1
  96. package/dist/utils/json.js +7 -0
  97. package/dist/utils/json.js.map +1 -0
  98. package/dist/utils/localHost.js +17 -0
  99. package/dist/utils/localHost.js.map +1 -0
  100. package/dist/utils/safePath.js +51 -20
  101. package/dist/utils/safePath.js.map +1 -1
  102. package/package.json +5 -12
  103. package/dist/ansiCodes.js +0 -107
  104. package/dist/ansiCodes.js.map +0 -1
  105. package/dist/auth/credentialsStore.test.js +0 -60
  106. package/dist/auth/credentialsStore.test.js.map +0 -1
  107. package/dist/claude/fileHistory.js +0 -79
  108. package/dist/claude/fileHistory.js.map +0 -1
  109. package/dist/claude/generateHookSettings.js +0 -23
  110. package/dist/claude/generateHookSettings.js.map +0 -1
  111. package/dist/claude/hookServer.js +0 -33
  112. package/dist/claude/hookServer.js.map +0 -1
  113. package/dist/claude/sessionScanner.js +0 -162
  114. package/dist/claude/sessionScanner.js.map +0 -1
  115. package/dist/claude/sessionScanner.test.js +0 -24
  116. package/dist/claude/sessionScanner.test.js.map +0 -1
  117. package/dist/claude/transcriptParser.test.js +0 -78
  118. package/dist/claude/transcriptParser.test.js.map +0 -1
  119. package/dist/commands/cliArgs.test.js +0 -25
  120. package/dist/commands/cliArgs.test.js.map +0 -1
  121. package/dist/config.js +0 -40
  122. package/dist/config.js.map +0 -1
  123. package/dist/credentialsStore.js +0 -57
  124. package/dist/credentialsStore.js.map +0 -1
  125. package/dist/generateHookSettings.js +0 -30
  126. package/dist/generateHookSettings.js.map +0 -1
  127. package/dist/handlers/fileHandlerPayloads.test.js +0 -55
  128. package/dist/handlers/fileHandlerPayloads.test.js.map +0 -1
  129. package/dist/handlers/promptImages.test.js +0 -52
  130. package/dist/handlers/promptImages.test.js.map +0 -1
  131. package/dist/hookServer.js +0 -32
  132. package/dist/hookServer.js.map +0 -1
  133. package/dist/ignorePaths.js +0 -68
  134. package/dist/ignorePaths.js.map +0 -1
  135. package/dist/loadDotEnv.js +0 -79
  136. package/dist/loadDotEnv.js.map +0 -1
  137. package/dist/logger.js +0 -29
  138. package/dist/logger.js.map +0 -1
  139. package/dist/portForwardManager.js +0 -97
  140. package/dist/portForwardManager.js.map +0 -1
  141. package/dist/projectHistoryReader.js +0 -85
  142. package/dist/projectHistoryReader.js.map +0 -1
  143. package/dist/pty/ansiCodes.js +0 -14
  144. package/dist/pty/ansiCodes.js.map +0 -1
  145. package/dist/pty/notificationDetector.js +0 -29
  146. package/dist/pty/notificationDetector.js.map +0 -1
  147. package/dist/pty/notificationDetector.test.js +0 -24
  148. package/dist/pty/notificationDetector.test.js.map +0 -1
  149. package/dist/pty/ptyMenuParser.js +0 -91
  150. package/dist/pty/ptyMenuParser.js.map +0 -1
  151. package/dist/pty/ptyMenuParser.test.js +0 -26
  152. package/dist/pty/ptyMenuParser.test.js.map +0 -1
  153. package/dist/pty/ptySnapshotRenderer.js +0 -71
  154. package/dist/pty/ptySnapshotRenderer.js.map +0 -1
  155. package/dist/pty/selectionMenuDetector.js +0 -49
  156. package/dist/pty/selectionMenuDetector.js.map +0 -1
  157. package/dist/pty/selectionMenuDetector.test.js +0 -62
  158. package/dist/pty/selectionMenuDetector.test.js.map +0 -1
  159. package/dist/pty/selectionMenuMeta.js +0 -54
  160. package/dist/pty/selectionMenuMeta.js.map +0 -1
  161. package/dist/pty/selectionMenuMeta.test.js +0 -26
  162. package/dist/pty/selectionMenuMeta.test.js.map +0 -1
  163. package/dist/pty/selectionMenuParser.js +0 -83
  164. package/dist/pty/selectionMenuParser.js.map +0 -1
  165. package/dist/pty/selectionMenuParser.test.js +0 -30
  166. package/dist/pty/selectionMenuParser.test.js.map +0 -1
  167. package/dist/pty/spawn.js +0 -104
  168. package/dist/pty/spawn.js.map +0 -1
  169. package/dist/pty/spawn.test.js +0 -17
  170. package/dist/pty/spawn.test.js.map +0 -1
  171. package/dist/pty/statusSessionDetector.js +0 -28
  172. package/dist/pty/statusSessionDetector.js.map +0 -1
  173. package/dist/pty/statusSessionDetector.test.js +0 -23
  174. package/dist/pty/statusSessionDetector.test.js.map +0 -1
  175. package/dist/pty/textInputDetector.js +0 -60
  176. package/dist/pty/textInputDetector.js.map +0 -1
  177. package/dist/pty/textInputDetector.test.js +0 -32
  178. package/dist/pty/textInputDetector.test.js.map +0 -1
  179. package/dist/ptyMenuParser.js +0 -470
  180. package/dist/ptyMenuParser.js.map +0 -1
  181. package/dist/ptySnapshotRenderer.js +0 -78
  182. package/dist/ptySnapshotRenderer.js.map +0 -1
  183. package/dist/services/checkpointService.js +0 -113
  184. package/dist/services/checkpointService.js.map +0 -1
  185. package/dist/services/checkpointService.test.js +0 -61
  186. package/dist/services/checkpointService.test.js.map +0 -1
  187. package/dist/services/claudeMenuBridge.js +0 -116
  188. package/dist/services/claudeMenuBridge.js.map +0 -1
  189. package/dist/services/claudeMenuBridge.test.js +0 -90
  190. package/dist/services/claudeMenuBridge.test.js.map +0 -1
  191. package/dist/services/claudeService.js +0 -146
  192. package/dist/services/claudeService.js.map +0 -1
  193. package/dist/services/claudeService.test.js +0 -39
  194. package/dist/services/claudeService.test.js.map +0 -1
  195. package/dist/services/cliRuntime.test.js +0 -55
  196. package/dist/services/cliRuntime.test.js.map +0 -1
  197. package/dist/services/modelAdapter.test.js +0 -47
  198. package/dist/services/modelAdapter.test.js.map +0 -1
  199. package/dist/services/modelArgs.test.js +0 -64
  200. package/dist/services/modelArgs.test.js.map +0 -1
  201. package/dist/services/modelBaseUrl.test.js +0 -32
  202. package/dist/services/modelBaseUrl.test.js.map +0 -1
  203. package/dist/services/modelService.test.js +0 -136
  204. package/dist/services/modelService.test.js.map +0 -1
  205. package/dist/services/notificationDedupe.js +0 -23
  206. package/dist/services/notificationDedupe.js.map +0 -1
  207. package/dist/services/notificationDedupe.test.js +0 -20
  208. package/dist/services/notificationDedupe.test.js.map +0 -1
  209. package/dist/services/sessionListService.test.js +0 -22
  210. package/dist/services/sessionListService.test.js.map +0 -1
  211. package/dist/services/sessionRollbackService.js +0 -195
  212. package/dist/services/sessionRollbackService.js.map +0 -1
  213. package/dist/services/sessionRollbackService.test.js +0 -142
  214. package/dist/services/sessionRollbackService.test.js.map +0 -1
  215. package/dist/services/tunnelHelpers.test.js +0 -42
  216. package/dist/services/tunnelHelpers.test.js.map +0 -1
  217. package/dist/services/tunnelService.test.js +0 -91
  218. package/dist/services/tunnelService.test.js.map +0 -1
  219. package/dist/sessionScanner.js +0 -271
  220. package/dist/sessionScanner.js.map +0 -1
  221. package/dist/snapshotScanner.js +0 -154
  222. package/dist/snapshotScanner.js.map +0 -1
  223. package/dist/spawn.js +0 -79
  224. package/dist/spawn.js.map +0 -1
  225. package/dist/terminalManager.js +0 -73
  226. package/dist/terminalManager.js.map +0 -1
  227. package/dist/transport/directWsServer.js +0 -135
  228. package/dist/transport/directWsServer.js.map +0 -1
  229. package/dist/transport/webrtcTransport.js +0 -145
  230. package/dist/transport/webrtcTransport.js.map +0 -1
  231. package/dist/transport/webrtcTransport.test.js +0 -104
  232. package/dist/transport/webrtcTransport.test.js.map +0 -1
  233. package/dist/transport/webrtcTypes.js +0 -29
  234. package/dist/transport/webrtcTypes.js.map +0 -1
  235. package/dist/transport/webrtcTypes.test.js +0 -20
  236. package/dist/transport/webrtcTypes.test.js.map +0 -1
  237. package/dist/utils/ptyBuffer.js +0 -46
  238. package/dist/utils/ptyBuffer.js.map +0 -1
  239. package/scripts/claude_launcher.cjs +0 -71
  240. package/scripts/run-tests.mjs +0 -46
  241. package/scripts/session_hook_forwarder.cjs +0 -44
@@ -1,113 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { readSessionHistory } from './sessionService.js';
4
- import { safePath } from '../utils/safePath.js';
5
- export function buildRollbackResult(sessionId, targetMessageId, history = readSessionHistory(sessionId)) {
6
- const targetIndex = history.findIndex((m) => m.id === targetMessageId);
7
- if (targetIndex < 0)
8
- throw new Error('rollback target message not found');
9
- const target = history[targetIndex];
10
- if (target.role !== 'user')
11
- throw new Error('rollback target must be a user message');
12
- const cutoff = findTurnEndIndex(history, targetIndex);
13
- return {
14
- sessionId,
15
- targetMessageId,
16
- restoredPrompt: target.content,
17
- messages: history.slice(0, cutoff + 1),
18
- };
19
- }
20
- export function rollbackChatTurnOnDisk(sessionId, targetMessageId, history = readSessionHistory(sessionId)) {
21
- const plan = buildRollbackPlan(sessionId, targetMessageId, history);
22
- for (const operation of plan.operations)
23
- operation();
24
- return plan.result;
25
- }
26
- function buildRollbackPlan(sessionId, targetMessageId, history) {
27
- const targetIndex = history.findIndex((m) => m.id === targetMessageId);
28
- if (targetIndex < 0)
29
- throw new Error('rollback target message not found');
30
- const target = history[targetIndex];
31
- if (target.role !== 'user')
32
- throw new Error('rollback target must be a user message');
33
- const cutoff = findTurnEndIndex(history, targetIndex);
34
- const laterMessages = history.slice(cutoff + 1);
35
- const operations = [];
36
- const restoredFiles = new Set();
37
- for (let i = laterMessages.length - 1; i >= 0; i--) {
38
- const message = laterMessages[i];
39
- for (const tool of [...(message.toolUses ?? [])].reverse()) {
40
- addToolRollbackOperation(tool, operations, restoredFiles);
41
- }
42
- }
43
- return {
44
- result: {
45
- sessionId,
46
- targetMessageId,
47
- restoredPrompt: target.content,
48
- messages: history.slice(0, cutoff + 1),
49
- restoredFiles: [...restoredFiles],
50
- },
51
- operations,
52
- };
53
- }
54
- function findTurnEndIndex(history, userIndex) {
55
- let end = history.length - 1;
56
- for (let i = userIndex + 1; i < history.length; i++) {
57
- if (history[i].role === 'user') {
58
- end = i - 1;
59
- break;
60
- }
61
- }
62
- return end;
63
- }
64
- function addToolRollbackOperation(tool, operations, restoredFiles) {
65
- const filePath = getToolPath(tool);
66
- if (!filePath)
67
- return;
68
- switch (tool.toolName) {
69
- case 'Write': {
70
- restoredFiles.add(filePath);
71
- const oldContent = tool.input['old_content'];
72
- if (typeof oldContent === 'string')
73
- operations.push(() => writeFile(filePath, oldContent));
74
- else
75
- operations.push(() => removePath(filePath));
76
- return;
77
- }
78
- case 'Edit':
79
- case 'SearchReplace': {
80
- const oldStr = tool.input['old_str'] ?? tool.input['old_string'];
81
- const newStr = tool.input['new_str'] ?? tool.input['new_string'];
82
- if (typeof oldStr !== 'string' || typeof newStr !== 'string')
83
- return;
84
- restoredFiles.add(filePath);
85
- operations.push(() => revertTextReplacement(filePath, oldStr, newStr));
86
- return;
87
- }
88
- }
89
- }
90
- function getToolPath(tool) {
91
- const value = tool.input['file_path'] ?? tool.input['path'];
92
- return typeof value === 'string' ? value : '';
93
- }
94
- function writeFile(filePath, content) {
95
- const resolved = safePath(filePath);
96
- fs.mkdirSync(path.dirname(resolved), { recursive: true });
97
- fs.writeFileSync(resolved, content, 'utf-8');
98
- }
99
- function removePath(targetPath) {
100
- const resolved = safePath(targetPath);
101
- if (fs.existsSync(resolved))
102
- fs.rmSync(resolved, { recursive: true, force: false });
103
- }
104
- function revertTextReplacement(filePath, oldStr, newStr) {
105
- const resolved = safePath(filePath);
106
- const content = fs.readFileSync(resolved, 'utf-8');
107
- const index = content.indexOf(newStr);
108
- if (index < 0)
109
- throw new Error(`rollback replacement not found for ${filePath}`);
110
- const next = `${content.slice(0, index)}${oldStr}${content.slice(index + newStr.length)}`;
111
- fs.writeFileSync(resolved, next, 'utf-8');
112
- }
113
- //# sourceMappingURL=checkpointService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"checkpointService.js","sourceRoot":"","sources":["../../src/services/checkpointService.ts"],"names":[],"mappings":"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"}
@@ -1,61 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
- import { buildRollbackResult, rollbackChatTurnOnDisk } from './checkpointService.js';
7
- test('buildRollbackResult truncates history to selected user message', () => {
8
- const result = buildRollbackResult('sess-1', 'u1', [
9
- { id: 'u1', role: 'user', content: 'first' },
10
- { id: 'a1', role: 'assistant', content: 'reply' },
11
- { id: 'u2', role: 'user', content: 'second' },
12
- { id: 'a2', role: 'assistant', content: 'reply2' },
13
- ]);
14
- assert.equal(result.sessionId, 'sess-1');
15
- assert.equal(result.restoredPrompt, 'first');
16
- assert.deepEqual(result.messages.map((m) => m.id), ['u1', 'a1']);
17
- });
18
- test('rollbackChatTurnOnDisk restores file changes from later turns', () => {
19
- const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'kumo-rollback-'));
20
- const prevCwd = process.cwd();
21
- process.chdir(tempRoot);
22
- try {
23
- fs.mkdirSync(path.join(tempRoot, 'lib'), { recursive: true });
24
- fs.writeFileSync(path.join(tempRoot, 'lib', 'demo.txt'), 'after second', 'utf-8');
25
- const result = rollbackChatTurnOnDisk('sess-1', 'u1', [
26
- { id: 'u1', role: 'user', content: 'first' },
27
- {
28
- id: 'a1',
29
- role: 'assistant',
30
- content: 'reply1',
31
- toolUses: [
32
- { toolName: 'Write', input: { file_path: 'lib/demo.txt', content: 'first version' } },
33
- ],
34
- },
35
- { id: 'u2', role: 'user', content: 'second' },
36
- {
37
- id: 'a2',
38
- role: 'assistant',
39
- content: 'reply2',
40
- toolUses: [
41
- {
42
- toolName: 'Write',
43
- input: {
44
- file_path: 'lib/demo.txt',
45
- content: 'after second',
46
- old_content: 'first version',
47
- },
48
- },
49
- ],
50
- },
51
- ]);
52
- assert.equal(fs.readFileSync(path.join(tempRoot, 'lib', 'demo.txt'), 'utf-8'), 'first version');
53
- assert.deepEqual(result.restoredFiles, ['lib/demo.txt']);
54
- assert.deepEqual(result.messages.map((m) => m.id), ['u1', 'a1']);
55
- }
56
- finally {
57
- process.chdir(prevCwd);
58
- fs.rmSync(tempRoot, { recursive: true, force: true });
59
- }
60
- });
61
- //# sourceMappingURL=checkpointService.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"checkpointService.test.js","sourceRoot":"","sources":["../../src/services/checkpointService.test.ts"],"names":[],"mappings":"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"}
@@ -1,116 +0,0 @@
1
- import { log } from '../core/logger.js';
2
- import { NotificationDedupe } from './notificationDedupe.js';
3
- const LOGIN_WARNING_MESSAGE = 'Not logged in · Run /login';
4
- // translate parsed pty elements into ws messages and handle safe auto-accept flows
5
- export class ClaudeMenuBridge {
6
- send;
7
- getEffectiveEffort;
8
- getWorkingDir;
9
- autoAcceptedApiKeyDialog = false;
10
- menuIdCounter = 0;
11
- notificationDedupe = new NotificationDedupe();
12
- constructor(send, getEffectiveEffort, getWorkingDir) {
13
- this.send = send;
14
- this.getEffectiveEffort = getEffectiveEffort;
15
- this.getWorkingDir = getWorkingDir;
16
- }
17
- // reset transient state whenever a fresh claude process is spawned
18
- reset() {
19
- this.autoAcceptedApiKeyDialog = false;
20
- }
21
- // handle a parser event and emit ws payloads or synthetic process input
22
- handleElement(element, process) {
23
- switch (element.type) {
24
- case 'selection':
25
- this.handleSelection(element, process);
26
- break;
27
- case 'input':
28
- log(`[parser] input: "${element.label}" = "${element.value}"`);
29
- this.send({
30
- type: 'text_input',
31
- label: element.label,
32
- value: element.value,
33
- placeholder: element.placeholder,
34
- cursorPosition: element.cursorPosition,
35
- });
36
- break;
37
- case 'notification':
38
- this.handleNotification(element);
39
- break;
40
- case 'status': {
41
- const effort = element.effort ?? this.getEffectiveEffort();
42
- log(`[parser] status: model=${element.model}, effort=${effort}, logged=${element.loggedIn}`);
43
- this.send({ type: 'cli_status', loggedIn: element.loggedIn, effort, workingDir: element.workingDir });
44
- break;
45
- }
46
- case 'session':
47
- log(`[parser] session: ${element.sessionId}`);
48
- this.send({ type: 'session_info', sessionId: element.sessionId, resumeCommand: element.resumeCommand });
49
- break;
50
- }
51
- }
52
- // auto-accept known safe dialogs or forward the menu to the app
53
- handleSelection(element, process) {
54
- if (element.options.length === 0) {
55
- log('[parser] ignoring empty menu');
56
- return;
57
- }
58
- if (element.title.includes('Bypass Permissions')) {
59
- if (this.tryAcceptYes(element, process, 'auto-accepted bypass permissions dialog'))
60
- return;
61
- }
62
- if (!this.autoAcceptedApiKeyDialog &&
63
- (element.title.includes('Detected a custom API key') || element.title.includes('Do you want to use this API key'))) {
64
- if (this.tryAcceptYes(element, process, 'auto-accepted custom api key dialog', true)) {
65
- this.autoAcceptedApiKeyDialog = true;
66
- return;
67
- }
68
- }
69
- this.menuIdCounter += 1;
70
- const id = `menu-${this.menuIdCounter}`;
71
- log(`[parser] menu detected: "${element.title}" (${element.options.length} opts, selected: ${element.selectedIndex})`);
72
- log(`[parser] options: ${JSON.stringify(element.options)}`);
73
- this.send({
74
- type: 'prompt_options',
75
- id,
76
- title: element.title,
77
- description: element.description,
78
- options: element.options,
79
- selectedIndex: element.selectedIndex,
80
- hint: element.hint,
81
- footer: element.footer,
82
- });
83
- }
84
- // forward deduped notifications and update cli status for login warnings
85
- handleNotification(element) {
86
- log(`[parser] notification: [${element.level}] ${element.message}`);
87
- if (this.notificationDedupe.shouldSend(element.level, element.message)) {
88
- this.send({ type: 'notification', level: element.level, message: element.message });
89
- }
90
- if (element.level === 'warning' && element.message.trim().toLowerCase() === LOGIN_WARNING_MESSAGE.toLowerCase()) {
91
- this.send({
92
- type: 'cli_status',
93
- loggedIn: false,
94
- effort: this.getEffectiveEffort(),
95
- workingDir: this.getWorkingDir(),
96
- });
97
- }
98
- }
99
- // try to auto-press "yes" inside a selection dialog
100
- tryAcceptYes(element, process, logMessage, exact = false) {
101
- const yesIndex = element.options.findIndex((option) => (exact
102
- ? option.label.trim().toLowerCase() === 'yes'
103
- : option.label.trim().toLowerCase().includes('yes')));
104
- if (yesIndex < 0 || !process)
105
- return false;
106
- const delta = yesIndex - element.selectedIndex;
107
- const key = delta < 0 ? '\x1b[A' : '\x1b[B';
108
- for (let index = 0; index < Math.abs(delta); index += 1) {
109
- process.write(key);
110
- }
111
- process.write('\r');
112
- log(`[parser] ${logMessage}`);
113
- return true;
114
- }
115
- }
116
- //# sourceMappingURL=claudeMenuBridge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claudeMenuBridge.js","sourceRoot":"","sources":["../../src/services/claudeMenuBridge.ts"],"names":[],"mappings":"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"}
@@ -1,90 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { ClaudeMenuBridge } from './claudeMenuBridge.js';
4
- function createBridge(sent) {
5
- return new ClaudeMenuBridge((data) => sent.push(data), () => 'high', () => 'E:\\Data\\new_journey\\kumo\\cli');
6
- }
7
- function createProcessRecorder() {
8
- const writes = [];
9
- return {
10
- process: {
11
- write(data) {
12
- writes.push(data);
13
- },
14
- },
15
- writes,
16
- };
17
- }
18
- test('auto accepts bypass permissions dialog without sending prompt options', () => {
19
- const sent = [];
20
- const bridge = createBridge(sent);
21
- const recorder = createProcessRecorder();
22
- bridge.handleElement({
23
- type: 'selection',
24
- title: 'Bypass Permissions',
25
- options: [
26
- { index: 0, label: 'Yes', isSelected: false },
27
- { index: 1, label: 'No', isSelected: true },
28
- ],
29
- selectedIndex: 1,
30
- }, recorder.process);
31
- assert.deepEqual(recorder.writes, ['\x1b[A', '\r']);
32
- assert.equal(sent.length, 0);
33
- });
34
- test('auto accepts custom api key dialog only once', () => {
35
- const sent = [];
36
- const bridge = createBridge(sent);
37
- const recorder = createProcessRecorder();
38
- const element = {
39
- type: 'selection',
40
- title: 'Detected a custom API key',
41
- options: [
42
- { index: 0, label: 'Yes', isSelected: true },
43
- { index: 1, label: 'No', isSelected: false },
44
- ],
45
- selectedIndex: 0,
46
- };
47
- bridge.handleElement(element, recorder.process);
48
- bridge.handleElement(element, recorder.process);
49
- assert.deepEqual(recorder.writes, ['\r']);
50
- assert.equal(sent.length, 1);
51
- assert.equal(sent[0]?.type, 'prompt_options');
52
- });
53
- test('login warning sends both notification and logged-out status', () => {
54
- const sent = [];
55
- const bridge = createBridge(sent);
56
- bridge.handleElement({
57
- type: 'notification',
58
- level: 'warning',
59
- message: 'Not logged in · Run /login',
60
- }, null);
61
- assert.deepEqual(sent, [
62
- { type: 'notification', level: 'warning', message: 'Not logged in · Run /login' },
63
- { type: 'cli_status', loggedIn: false, effort: 'high', workingDir: 'E:\\Data\\new_journey\\kumo\\cli' },
64
- ]);
65
- });
66
- test('selection prompts receive stable incremental ids', () => {
67
- const sent = [];
68
- const bridge = createBridge(sent);
69
- bridge.handleElement({
70
- type: 'selection',
71
- title: 'Select model',
72
- options: [
73
- { index: 0, label: 'Sonnet', isSelected: true },
74
- { index: 1, label: 'Opus', isSelected: false },
75
- ],
76
- selectedIndex: 0,
77
- }, null);
78
- bridge.handleElement({
79
- type: 'selection',
80
- title: 'Select effort',
81
- options: [
82
- { index: 0, label: 'High', isSelected: true },
83
- { index: 1, label: 'Max', isSelected: false },
84
- ],
85
- selectedIndex: 0,
86
- }, null);
87
- assert.equal(sent[0]?.id, 'menu-1');
88
- assert.equal(sent[1]?.id, 'menu-2');
89
- });
90
- //# sourceMappingURL=claudeMenuBridge.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claudeMenuBridge.test.js","sourceRoot":"","sources":["../../src/services/claudeMenuBridge.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,SAAS,YAAY,CAAC,IAAmB;IACvC,OAAO,IAAI,gBAAgB,CACzB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAmB,CAAC,EACxC,GAAG,EAAE,CAAC,MAAM,EACZ,GAAG,EAAE,CAAC,kCAAkC,CACzC,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,OAAO;QACL,OAAO,EAAE;YACP,KAAK,CAAC,IAAY;gBAChB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;SACiB;QACpB,MAAM;KACP,CAAC;AACJ,CAAC;AAED,IAAI,CAAC,uEAAuE,EAAE,GAAG,EAAE;IACjF,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IAEzC,MAAM,CAAC,aAAa,CAAC;QACnB,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,oBAAoB;QAC3B,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;YAC7C,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;SAC5C;QACD,aAAa,EAAE,CAAC;KACjB,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAErB,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;IACxD,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG;QACd,IAAI,EAAE,WAAoB;QAC1B,KAAK,EAAE,2BAA2B;QAClC,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE;YAC5C,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE;SAC7C;QACD,aAAa,EAAE,CAAC;KACjB,CAAC;IAEF,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEhD,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAElC,MAAM,CAAC,aAAa,CAAC;QACnB,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,4BAA4B;KACtC,EAAE,IAAI,CAAC,CAAC;IAET,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE;QACrB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,4BAA4B,EAAE;QACjF,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,kCAAkC,EAAE;KACxG,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC5D,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAElC,MAAM,CAAC,aAAa,CAAC;QACnB,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,cAAc;QACrB,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE;YAC/C,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE;SAC/C;QACD,aAAa,EAAE,CAAC;KACjB,EAAE,IAAI,CAAC,CAAC;IAET,MAAM,CAAC,aAAa,CAAC;QACnB,IAAI,EAAE,WAAW;QACjB,KAAK,EAAE,eAAe;QACtB,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE;YAC7C,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE;SAC9C;QACD,aAAa,EAAE,CAAC;KACjB,EAAE,IAAI,CAAC,CAAC;IAET,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC"}
@@ -1,146 +0,0 @@
1
- import { spawnClaude, writeToProcess } from '../pty/spawn.js';
2
- import { PtyMenuParser } from '../pty/ptyMenuParser.js';
3
- import { PtySnapshotRenderer } from '../pty/ptySnapshotRenderer.js';
4
- import { PtyBuffer } from '../utils/ptyBuffer.js';
5
- import { log, debugWrite } from '../core/logger.js';
6
- import { ClaudeMenuBridge } from './claudeMenuBridge.js';
7
- // manage the lifecycle of a claude pty process plus its snapshot/parser
8
- export class ClaudeService {
9
- send;
10
- model;
11
- effort;
12
- getDeviceToken;
13
- process = null;
14
- cleanup = null;
15
- isRespawning = false;
16
- pendingSelectNudgeTimer = null;
17
- menuParser;
18
- menuBridge;
19
- snapshotRenderer;
20
- buffer;
21
- lastWsSendAt = 0;
22
- args = [];
23
- settingsPath = '';
24
- onExit = null;
25
- constructor(send, model, effort, getDeviceToken) {
26
- this.send = send;
27
- this.model = model;
28
- this.effort = effort;
29
- this.getDeviceToken = getDeviceToken;
30
- this.snapshotRenderer = new PtySnapshotRenderer(process.stdout.columns ?? 120, process.stdout.rows ?? 30);
31
- this.buffer = new PtyBuffer(this.snapshotRenderer);
32
- this.menuBridge = new ClaudeMenuBridge(this.send, () => this.effort.getEffective(), () => process.cwd());
33
- this.menuParser = new PtyMenuParser((el) => this.handleMenuElement(el));
34
- }
35
- // expose a wrapper so wsClient can stamp the last-send timestamp here
36
- notifySent() { this.lastWsSendAt = Date.now(); }
37
- getProcess() { return this.process; }
38
- resetSnapshot() {
39
- this.snapshotRenderer.reset(process.stdout.columns ?? 120, process.stdout.rows ?? 30);
40
- }
41
- resizeSnapshot() {
42
- this.snapshotRenderer.resize(process.stdout.columns ?? 120, process.stdout.rows ?? 30);
43
- }
44
- resetMenu() { this.menuParser.reset(); }
45
- flushBuffer() { this.buffer.flush(); }
46
- // dispatch a typed prompt into the running claude process
47
- dispatchPrompt(text) {
48
- if (!this.process)
49
- return;
50
- if (text.trim() === '/login')
51
- this.menuParser.reset();
52
- writeToProcess(this.process, text);
53
- }
54
- // send a single key/option select (no Enter), then nudge if no echo soon
55
- selectOption(value) {
56
- if (!this.process) {
57
- log(`[select_option] no claude process!`);
58
- return;
59
- }
60
- log(`[select_option] sending: "${value}" (without Enter)`);
61
- this.menuParser.reset();
62
- this.process.write(value);
63
- if (this.pendingSelectNudgeTimer)
64
- clearTimeout(this.pendingSelectNudgeTimer);
65
- const baseline = this.lastWsSendAt;
66
- this.pendingSelectNudgeTimer = setTimeout(() => {
67
- this.pendingSelectNudgeTimer = null;
68
- if (!this.process)
69
- return;
70
- if (this.lastWsSendAt === baseline)
71
- this.nudgeResize();
72
- }, 1000);
73
- }
74
- // submit a textual input by clearing existing chars then writing+enter
75
- submitInput(value) {
76
- if (!this.process)
77
- return;
78
- this.menuParser.reset();
79
- this.process.write('\x15');
80
- this.process.write(value);
81
- this.process.write('\r');
82
- }
83
- // forward a synthetic key press (only esc currently supported)
84
- sendKey(key) {
85
- if (!this.process || key !== 'esc')
86
- return;
87
- this.menuParser.reset();
88
- this.process.write('\x1b');
89
- }
90
- // toggle pty size by 1 col then back to force claude to redraw
91
- nudgeResize() {
92
- if (!this.process)
93
- return;
94
- const cols = process.stdout.columns ?? 120;
95
- const rows = process.stdout.rows ?? 30;
96
- try {
97
- this.process.resize(cols + 1, rows);
98
- setTimeout(() => { try {
99
- this.process?.resize(cols, rows);
100
- }
101
- catch { } }, 5);
102
- }
103
- catch { }
104
- }
105
- // (re)spawn claude with current args; refreshes default model just-in-time
106
- async spawn() {
107
- log(`[spawn] spawning claude, args=${JSON.stringify(this.args)}, cwd=${process.cwd()}`);
108
- if (this.process) {
109
- this.isRespawning = true;
110
- try {
111
- this.process.kill();
112
- }
113
- catch { }
114
- this.process = null;
115
- }
116
- this.cleanup?.();
117
- this.cleanup = null;
118
- this.menuBridge.reset();
119
- this.resetSnapshot();
120
- this.args = await this.model.ensureBeforeSpawn(this.args, this.getDeviceToken());
121
- this.args = this.effort.ensureBeforeSpawn(this.args);
122
- const env = await this.model.buildEnv();
123
- const { pty, cleanup } = spawnClaude([...this.args, '--settings', this.settingsPath], (active) => this.send({ type: 'thinking', active }), (data) => { debugWrite(data); this.menuParser.feed(data); this.buffer.feed(data); }, (cols, rows) => this.menuParser.resize(cols, rows), (p) => { this.process = p; }, undefined, env);
124
- this.cleanup = cleanup;
125
- this.send({
126
- type: 'cli_status',
127
- effort: this.effort.getEffective(),
128
- workingDir: process.cwd(),
129
- });
130
- pty.onExit(({ exitCode }) => {
131
- log(`[spawn] claude exited, exitCode=${exitCode}, isRespawning=${this.isRespawning}`);
132
- this.flushBuffer();
133
- if (this.isRespawning) {
134
- this.isRespawning = false;
135
- return;
136
- }
137
- this.onExit?.(exitCode);
138
- });
139
- process.on('SIGINT', () => { pty.kill(); });
140
- }
141
- // handle a parsed pty menu element and translate into ws message
142
- handleMenuElement(element) {
143
- this.menuBridge.handleElement(element, this.process);
144
- }
145
- }
146
- //# sourceMappingURL=claudeService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claudeService.js","sourceRoot":"","sources":["../../src/services/claudeService.ts"],"names":[],"mappings":"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"}
@@ -1,39 +0,0 @@
1
- import test from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { ClaudeService } from './claudeService.js';
4
- import { ModelService } from './modelService.js';
5
- import { EffortService } from './effortService.js';
6
- function createService(sent) {
7
- return new ClaudeService((data) => sent.push(data), new ModelService(), new EffortService(), () => undefined);
8
- }
9
- test('dedupes same notification within 5 minutes', () => {
10
- const sent = [];
11
- const service = createService(sent);
12
- const now = new Date('2026-05-29T10:09:17.389Z').getTime();
13
- const originalNow = Date.now;
14
- const handleMenuElement = Reflect.get(service, 'handleMenuElement');
15
- Date.now = () => now;
16
- handleMenuElement.call(service, { type: 'notification', level: 'error', message: 'IDE extension install failed (see /status for info)' });
17
- handleMenuElement.call(service, { type: 'notification', level: 'error', message: ' IDE extension install failed (see /status for info) ' });
18
- Date.now = originalNow;
19
- assert.equal(sent.length, 1);
20
- assert.deepEqual(sent[0], {
21
- type: 'notification',
22
- level: 'error',
23
- message: 'IDE extension install failed (see /status for info)',
24
- });
25
- });
26
- test('allows same notification again after 5 minutes', () => {
27
- const sent = [];
28
- const service = createService(sent);
29
- const base = new Date('2026-05-29T10:09:17.389Z').getTime();
30
- const originalNow = Date.now;
31
- const handleMenuElement = Reflect.get(service, 'handleMenuElement');
32
- Date.now = () => base;
33
- handleMenuElement.call(service, { type: 'notification', level: 'error', message: 'IDE extension install failed (see /status for info)' });
34
- Date.now = () => base + 5 * 60 * 1000 + 1;
35
- handleMenuElement.call(service, { type: 'notification', level: 'error', message: 'IDE extension install failed (see /status for info)' });
36
- Date.now = originalNow;
37
- assert.equal(sent.length, 2);
38
- });
39
- //# sourceMappingURL=claudeService.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"claudeService.test.js","sourceRoot":"","sources":["../../src/services/claudeService.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAInD,SAAS,aAAa,CAAC,IAAmB;IACxC,OAAO,IAAI,aAAa,CACtB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAmB,CAAC,EACxC,IAAI,YAAY,EAAE,EAClB,IAAI,aAAa,EAAE,EACnB,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;AACJ,CAAC;AAED,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;IACtD,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC;IAC7B,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,mBAAmB,CAA+B,CAAC;IAElG,IAAI,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC;IACrB,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC,CAAC;IAC1I,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,yDAAyD,EAAE,CAAC,CAAC;IAE9I,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC;IAEvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7B,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QACxB,IAAI,EAAE,cAAc;QACpB,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,qDAAqD;KAC/D,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC;IAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC;IAC7B,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,mBAAmB,CAA+B,CAAC;IAElG,IAAI,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;IACtB,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC,CAAC;IAE1I,IAAI,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;IAC1C,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC,CAAC;IAE1I,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC;IAEvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC"}