centaurus-cli 2.0.0 → 2.0.2

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 (103) hide show
  1. package/CONFIG_GUIDE.md +100 -106
  2. package/README.md +68 -63
  3. package/dist/cli-adapter.d.ts +9 -3
  4. package/dist/cli-adapter.d.ts.map +1 -1
  5. package/dist/cli-adapter.js +123 -164
  6. package/dist/cli-adapter.js.map +1 -1
  7. package/dist/commands/CommandParser.d.ts +1 -1
  8. package/dist/commands/CommandParser.d.ts.map +1 -1
  9. package/dist/commands/CommandParser.js +3 -18
  10. package/dist/commands/CommandParser.js.map +1 -1
  11. package/dist/commands/view-duplication-logs.d.ts +5 -0
  12. package/dist/commands/view-duplication-logs.d.ts.map +1 -0
  13. package/dist/commands/view-duplication-logs.js +14 -0
  14. package/dist/commands/view-duplication-logs.js.map +1 -0
  15. package/dist/config/ConfigManager.d.ts +10 -7
  16. package/dist/config/ConfigManager.d.ts.map +1 -1
  17. package/dist/config/ConfigManager.js +43 -142
  18. package/dist/config/ConfigManager.js.map +1 -1
  19. package/dist/config/defaultConfig.d.ts +0 -4
  20. package/dist/config/defaultConfig.d.ts.map +1 -1
  21. package/dist/config/defaultConfig.js +1 -6
  22. package/dist/config/defaultConfig.js.map +1 -1
  23. package/dist/config/manager.d.ts +15 -13
  24. package/dist/config/manager.d.ts.map +1 -1
  25. package/dist/config/manager.js +52 -41
  26. package/dist/config/manager.js.map +1 -1
  27. package/dist/config/models.d.ts +31 -0
  28. package/dist/config/models.d.ts.map +1 -0
  29. package/dist/config/models.js +49 -0
  30. package/dist/config/models.js.map +1 -0
  31. package/dist/config/types.d.ts +0 -3
  32. package/dist/config/types.d.ts.map +1 -1
  33. package/dist/config/types.js +0 -1
  34. package/dist/config/types.js.map +1 -1
  35. package/dist/index.js +27 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/prompts/system-prompt.d.ts +1 -1
  38. package/dist/prompts/system-prompt.d.ts.map +1 -1
  39. package/dist/prompts/system-prompt.js +0 -1
  40. package/dist/prompts/system-prompt.js.map +1 -1
  41. package/dist/services/ai-service-client.d.ts +82 -0
  42. package/dist/services/ai-service-client.d.ts.map +1 -0
  43. package/dist/services/ai-service-client.js +254 -0
  44. package/dist/services/ai-service-client.js.map +1 -0
  45. package/dist/services/api-client.js +3 -3
  46. package/dist/services/api-client.js.map +1 -1
  47. package/dist/tools/ToolRegistry.d.ts +14 -3
  48. package/dist/tools/ToolRegistry.d.ts.map +1 -1
  49. package/dist/tools/ToolRegistry.js +46 -34
  50. package/dist/tools/ToolRegistry.js.map +1 -1
  51. package/dist/tools/command.d.ts.map +1 -1
  52. package/dist/tools/command.js +17 -3
  53. package/dist/tools/command.js.map +1 -1
  54. package/dist/tools/file-ops.js +3 -3
  55. package/dist/tools/file-ops.js.map +1 -1
  56. package/dist/tools/web-search.js +2 -2
  57. package/dist/tools/web-search.js.map +1 -1
  58. package/dist/types/index.d.ts +1 -0
  59. package/dist/types/index.d.ts.map +1 -1
  60. package/dist/ui/components/App.d.ts +3 -2
  61. package/dist/ui/components/App.d.ts.map +1 -1
  62. package/dist/ui/components/App.js +107 -16
  63. package/dist/ui/components/App.js.map +1 -1
  64. package/dist/ui/components/CodeBlock.d.ts.map +1 -1
  65. package/dist/ui/components/CodeBlock.js +15 -3
  66. package/dist/ui/components/CodeBlock.js.map +1 -1
  67. package/dist/ui/components/ConfirmPrompt.d.ts.map +1 -1
  68. package/dist/ui/components/ConfirmPrompt.js +32 -20
  69. package/dist/ui/components/ConfirmPrompt.js.map +1 -1
  70. package/dist/ui/components/DiffViewer.d.ts.map +1 -1
  71. package/dist/ui/components/DiffViewer.js +16 -2
  72. package/dist/ui/components/DiffViewer.js.map +1 -1
  73. package/dist/ui/components/InputBox.d.ts.map +1 -1
  74. package/dist/ui/components/InputBox.js +26 -9
  75. package/dist/ui/components/InputBox.js.map +1 -1
  76. package/dist/ui/components/LoadingIndicator.d.ts.map +1 -1
  77. package/dist/ui/components/LoadingIndicator.js +6 -2
  78. package/dist/ui/components/LoadingIndicator.js.map +1 -1
  79. package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -1
  80. package/dist/ui/components/MarkdownRenderer.js +8 -12
  81. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  82. package/dist/ui/components/StreamingMessageDisplay.d.ts +6 -7
  83. package/dist/ui/components/StreamingMessageDisplay.d.ts.map +1 -1
  84. package/dist/ui/components/StreamingMessageDisplay.js +69 -12
  85. package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
  86. package/dist/ui/components/ToolExecutionMessage.d.ts.map +1 -1
  87. package/dist/ui/components/ToolExecutionMessage.js +44 -16
  88. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  89. package/dist/ui/components/WelcomeBanner.d.ts.map +1 -1
  90. package/dist/ui/components/WelcomeBanner.js.map +1 -1
  91. package/dist/ui/utils/duplication-detector.d.ts +32 -0
  92. package/dist/ui/utils/duplication-detector.d.ts.map +1 -0
  93. package/dist/ui/utils/duplication-detector.js +227 -0
  94. package/dist/ui/utils/duplication-detector.js.map +1 -0
  95. package/dist/ui/utils/duplication-logger.d.ts +21 -0
  96. package/dist/ui/utils/duplication-logger.d.ts.map +1 -0
  97. package/dist/ui/utils/duplication-logger.js +85 -0
  98. package/dist/ui/utils/duplication-logger.js.map +1 -0
  99. package/dist/ui/utils/terminal-scanner.d.ts +19 -0
  100. package/dist/ui/utils/terminal-scanner.d.ts.map +1 -0
  101. package/dist/ui/utils/terminal-scanner.js +217 -0
  102. package/dist/ui/utils/terminal-scanner.js.map +1 -0
  103. package/package.json +2 -13
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Duplication Detector Utility
3
+ *
4
+ * Detects when the UI has been duplicated by monitoring the terminal output
5
+ * for multiple instances of the InputBox component.
6
+ */
7
+ import { useEffect, useRef } from 'react';
8
+ import { logDuplication } from './duplication-logger.js';
9
+ /**
10
+ * Detects UI duplication by scanning the terminal buffer for multiple input boxes
11
+ */
12
+ export function useDuplicationDetector({ onDuplicationDetected, checkIntervalMs = 500, enabled = true }) {
13
+ const lastCheckRef = useRef(0);
14
+ const duplicationDetectedRef = useRef(false);
15
+ useEffect(() => {
16
+ if (!enabled)
17
+ return;
18
+ const intervalId = setInterval(() => {
19
+ const now = Date.now();
20
+ // Throttle checks
21
+ if (now - lastCheckRef.current < checkIntervalMs) {
22
+ return;
23
+ }
24
+ lastCheckRef.current = now;
25
+ // Check for duplication
26
+ if (detectDuplication()) {
27
+ if (!duplicationDetectedRef.current) {
28
+ duplicationDetectedRef.current = true;
29
+ console.error('[Duplication Detector] UI duplication detected! Triggering recovery...');
30
+ onDuplicationDetected();
31
+ // Reset flag after a delay to allow re-detection if needed
32
+ setTimeout(() => {
33
+ duplicationDetectedRef.current = false;
34
+ }, 2000);
35
+ }
36
+ }
37
+ }, checkIntervalMs);
38
+ return () => clearInterval(intervalId);
39
+ }, [onDuplicationDetected, checkIntervalMs, enabled]);
40
+ }
41
+ /**
42
+ * Detects duplication by analyzing the terminal output
43
+ * Returns true if duplication is detected
44
+ */
45
+ function detectDuplication() {
46
+ try {
47
+ // Get the terminal output by reading stdout
48
+ // We'll look for multiple instances of the InputBox border pattern
49
+ const terminalOutput = getTerminalOutput();
50
+ if (!terminalOutput) {
51
+ return false;
52
+ }
53
+ // Count occurrences of the InputBox component markers
54
+ const inputBoxCount = countInputBoxes(terminalOutput);
55
+ // If we find more than 1 input box, duplication has occurred
56
+ if (inputBoxCount > 1) {
57
+ console.error(`[Duplication Detector] Found ${inputBoxCount} input boxes (expected 1)`);
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ catch (error) {
63
+ console.error('[Duplication Detector] Error during detection:', error);
64
+ return false;
65
+ }
66
+ }
67
+ /**
68
+ * Gets the current terminal output
69
+ */
70
+ function getTerminalOutput() {
71
+ try {
72
+ // In Node.js, we can't directly read the terminal buffer
73
+ // Instead, we'll use a different approach: check if Ink is rendering multiple times
74
+ // by looking at the process.stdout content
75
+ // For now, we'll use a heuristic based on the terminal rows
76
+ if (process.stdout.rows && process.stdout.columns) {
77
+ // We can't directly read the buffer, so we'll use an alternative approach
78
+ // Store a marker in the component and check for duplicates
79
+ return null;
80
+ }
81
+ return null;
82
+ }
83
+ catch (error) {
84
+ return null;
85
+ }
86
+ }
87
+ /**
88
+ * Counts the number of InputBox components in the terminal output
89
+ */
90
+ function countInputBoxes(output) {
91
+ // Look for the InputBox border pattern (round border style)
92
+ // The InputBox has distinctive markers:
93
+ // 1. "CWD:" text
94
+ // 2. "Model:" text
95
+ // 3. "AUTO-ACCEPT:" text
96
+ // 4. "> " prompt
97
+ // 5. "Ctrl+T to toggle" help text
98
+ const markers = [
99
+ /CWD:/g,
100
+ /Model:/g,
101
+ /AUTO-ACCEPT:/g,
102
+ /Ctrl\+T to toggle auto-accept/g
103
+ ];
104
+ let maxCount = 0;
105
+ for (const marker of markers) {
106
+ const matches = output.match(marker);
107
+ const count = matches ? matches.length : 0;
108
+ maxCount = Math.max(maxCount, count);
109
+ }
110
+ return maxCount;
111
+ }
112
+ /**
113
+ * Alternative approach: Use a global counter to track InputBox renders
114
+ */
115
+ let inputBoxRenderCount = 0;
116
+ let lastResetTime = Date.now();
117
+ export function registerInputBoxRender() {
118
+ const now = Date.now();
119
+ // Reset counter every 100ms (one render cycle)
120
+ if (now - lastResetTime > 100) {
121
+ inputBoxRenderCount = 0;
122
+ lastResetTime = now;
123
+ }
124
+ inputBoxRenderCount++;
125
+ }
126
+ export function getInputBoxRenderCount() {
127
+ return inputBoxRenderCount;
128
+ }
129
+ export function resetInputBoxRenderCount() {
130
+ inputBoxRenderCount = 0;
131
+ lastResetTime = Date.now();
132
+ }
133
+ /**
134
+ * Track WelcomeBanner renders
135
+ * Banner should only render once per session, so we don't reset the counter automatically
136
+ */
137
+ let bannerRenderCount = 0;
138
+ let bannerRenderTimestamps = [];
139
+ let duplicationCallback = null;
140
+ export function setDuplicationCallback(callback) {
141
+ logDuplication('Callback registered', 'INFO');
142
+ duplicationCallback = callback;
143
+ }
144
+ export function registerBannerRender() {
145
+ const now = Date.now();
146
+ bannerRenderCount++;
147
+ bannerRenderTimestamps.push(now);
148
+ logDuplication(`Banner render #${bannerRenderCount} at ${now}`, 'INFO');
149
+ // Keep only last 10 timestamps for analysis
150
+ if (bannerRenderTimestamps.length > 10) {
151
+ bannerRenderTimestamps.shift();
152
+ }
153
+ // Immediate check: if banner count > 1, trigger duplication callback
154
+ if (bannerRenderCount > 1) {
155
+ logDuplication(`DUPLICATION! Banner render #${bannerRenderCount} detected!`, 'ERROR');
156
+ if (duplicationCallback) {
157
+ logDuplication('Triggering immediate recovery callback...', 'ERROR');
158
+ duplicationCallback();
159
+ }
160
+ else {
161
+ logDuplication('WARNING: No callback registered yet!', 'WARN');
162
+ }
163
+ }
164
+ }
165
+ export function getBannerRenderCount() {
166
+ return bannerRenderCount;
167
+ }
168
+ export function resetBannerRenderCount() {
169
+ bannerRenderCount = 0;
170
+ bannerRenderTimestamps = [];
171
+ }
172
+ /**
173
+ * Hook to detect duplication using render counting
174
+ * Checks both InputBox and Banner render counts
175
+ * Banner check is cumulative (never resets automatically), InputBox resets per cycle
176
+ */
177
+ export function useRenderCountDuplicationDetector({ onDuplicationDetected, threshold = 2, checkIntervalMs = 100, enabled = true }) {
178
+ const duplicationDetectedRef = useRef(false);
179
+ const lastBannerCountRef = useRef(0);
180
+ useEffect(() => {
181
+ if (!enabled)
182
+ return;
183
+ logDuplication('Periodic monitoring started', 'INFO');
184
+ const intervalId = setInterval(() => {
185
+ const inputBoxCount = getInputBoxRenderCount();
186
+ const bannerCount = getBannerRenderCount();
187
+ // Log current counts for debugging
188
+ if (inputBoxCount > 0 || bannerCount > 0) {
189
+ logDuplication(`Check: InputBox=${inputBoxCount}, Banner=${bannerCount}, LastBanner=${lastBannerCountRef.current}`, 'INFO');
190
+ }
191
+ // Check if InputBox has been rendered multiple times in current cycle
192
+ const inputBoxDuplicated = inputBoxCount > threshold;
193
+ // Check if banner count has increased (meaning a new banner was rendered)
194
+ // Banner should only render once, so any increase after initial render is duplication
195
+ const bannerDuplicated = bannerCount > 1 && bannerCount > lastBannerCountRef.current;
196
+ const isDuplicated = inputBoxDuplicated || bannerDuplicated;
197
+ if (isDuplicated) {
198
+ if (!duplicationDetectedRef.current) {
199
+ duplicationDetectedRef.current = true;
200
+ if (inputBoxDuplicated) {
201
+ logDuplication(`Multiple InputBox renders detected (${inputBoxCount})! Triggering recovery...`, 'ERROR');
202
+ }
203
+ if (bannerDuplicated) {
204
+ logDuplication(`Multiple Banner renders detected (${bannerCount}, was ${lastBannerCountRef.current})! Triggering recovery...`, 'ERROR');
205
+ }
206
+ onDuplicationDetected();
207
+ resetInputBoxRenderCount();
208
+ // Don't reset banner count here - let the recovery handler do it
209
+ // Reset flag after a delay
210
+ setTimeout(() => {
211
+ duplicationDetectedRef.current = false;
212
+ lastBannerCountRef.current = 1; // After recovery, we expect 1 banner
213
+ }, 1000);
214
+ }
215
+ }
216
+ else {
217
+ // Update last banner count for next check
218
+ lastBannerCountRef.current = bannerCount;
219
+ }
220
+ }, checkIntervalMs);
221
+ return () => {
222
+ logDuplication('Periodic monitoring stopped', 'INFO');
223
+ clearInterval(intervalId);
224
+ };
225
+ }, [onDuplicationDetected, threshold, checkIntervalMs, enabled]);
226
+ }
227
+ //# sourceMappingURL=duplication-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplication-detector.js","sourceRoot":"","sources":["../../../src/ui/utils/duplication-detector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAQzD;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,qBAAqB,EACrB,eAAe,GAAG,GAAG,EACrB,OAAO,GAAG,IAAI,EACa;IAC3B,MAAM,YAAY,GAAG,MAAM,CAAS,CAAC,CAAC,CAAC;IACvC,MAAM,sBAAsB,GAAG,MAAM,CAAU,KAAK,CAAC,CAAC;IAEtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEvB,kBAAkB;YAClB,IAAI,GAAG,GAAG,YAAY,CAAC,OAAO,GAAG,eAAe,EAAE,CAAC;gBACjD,OAAO;YACT,CAAC;YAED,YAAY,CAAC,OAAO,GAAG,GAAG,CAAC;YAE3B,wBAAwB;YACxB,IAAI,iBAAiB,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,CAAC;oBACpC,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;oBACtC,OAAO,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;oBACxF,qBAAqB,EAAE,CAAC;oBAExB,2DAA2D;oBAC3D,UAAU,CAAC,GAAG,EAAE;wBACd,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC;oBACzC,CAAC,EAAE,IAAI,CAAC,CAAC;gBACX,CAAC;YACH,CAAC;QACH,CAAC,EAAE,eAAe,CAAC,CAAC;QAEpB,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC,EAAE,CAAC,qBAAqB,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB;IACxB,IAAI,CAAC;QACH,4CAA4C;QAC5C,mEAAmE;QACnE,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;QAE3C,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,sDAAsD;QACtD,MAAM,aAAa,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC;QAEtD,6DAA6D;QAC7D,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,gCAAgC,aAAa,2BAA2B,CAAC,CAAC;YACxF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,KAAK,CAAC,CAAC;QACvE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB;IACxB,IAAI,CAAC;QACH,yDAAyD;QACzD,oFAAoF;QACpF,2CAA2C;QAE3C,4DAA4D;QAC5D,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAClD,0EAA0E;YAC1E,2DAA2D;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,4DAA4D;IAC5D,wCAAwC;IACxC,iBAAiB;IACjB,mBAAmB;IACnB,yBAAyB;IACzB,iBAAiB;IACjB,kCAAkC;IAElC,MAAM,OAAO,GAAG;QACd,OAAO;QACP,SAAS;QACT,eAAe;QACf,gCAAgC;KACjC,CAAC;IAEF,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,IAAI,mBAAmB,GAAG,CAAC,CAAC;AAC5B,IAAI,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE/B,MAAM,UAAU,sBAAsB;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,+CAA+C;IAC/C,IAAI,GAAG,GAAG,aAAa,GAAG,GAAG,EAAE,CAAC;QAC9B,mBAAmB,GAAG,CAAC,CAAC;QACxB,aAAa,GAAG,GAAG,CAAC;IACtB,CAAC;IAED,mBAAmB,EAAE,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,mBAAmB,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,mBAAmB,GAAG,CAAC,CAAC;IACxB,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAC1B,IAAI,sBAAsB,GAAa,EAAE,CAAC;AAC1C,IAAI,mBAAmB,GAAwB,IAAI,CAAC;AAEpD,MAAM,UAAU,sBAAsB,CAAC,QAAoB;IACzD,cAAc,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC9C,mBAAmB,GAAG,QAAQ,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,iBAAiB,EAAE,CAAC;IACpB,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEjC,cAAc,CAAC,kBAAkB,iBAAiB,OAAO,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IAExE,4CAA4C;IAC5C,IAAI,sBAAsB,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACvC,sBAAsB,CAAC,KAAK,EAAE,CAAC;IACjC,CAAC;IAED,qEAAqE;IACrE,IAAI,iBAAiB,GAAG,CAAC,EAAE,CAAC;QAC1B,cAAc,CAAC,+BAA+B,iBAAiB,YAAY,EAAE,OAAO,CAAC,CAAC;QACtF,IAAI,mBAAmB,EAAE,CAAC;YACxB,cAAc,CAAC,2CAA2C,EAAE,OAAO,CAAC,CAAC;YACrE,mBAAmB,EAAE,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,iBAAiB,GAAG,CAAC,CAAC;IACtB,sBAAsB,GAAG,EAAE,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iCAAiC,CAAC,EAChD,qBAAqB,EACrB,SAAS,GAAG,CAAC,EACb,eAAe,GAAG,GAAG,EACrB,OAAO,GAAG,IAAI,EACsC;IACpD,MAAM,sBAAsB,GAAG,MAAM,CAAU,KAAK,CAAC,CAAC;IACtD,MAAM,kBAAkB,GAAG,MAAM,CAAS,CAAC,CAAC,CAAC;IAE7C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,cAAc,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;QAEtD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YAClC,MAAM,aAAa,GAAG,sBAAsB,EAAE,CAAC;YAC/C,MAAM,WAAW,GAAG,oBAAoB,EAAE,CAAC;YAE3C,mCAAmC;YACnC,IAAI,aAAa,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACzC,cAAc,CAAC,mBAAmB,aAAa,YAAY,WAAW,gBAAgB,kBAAkB,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;YAC9H,CAAC;YAED,sEAAsE;YACtE,MAAM,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAAC;YAErD,0EAA0E;YAC1E,sFAAsF;YACtF,MAAM,gBAAgB,GAAG,WAAW,GAAG,CAAC,IAAI,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC;YAErF,MAAM,YAAY,GAAG,kBAAkB,IAAI,gBAAgB,CAAC;YAE5D,IAAI,YAAY,EAAE,CAAC;gBACjB,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,CAAC;oBACpC,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;oBAEtC,IAAI,kBAAkB,EAAE,CAAC;wBACvB,cAAc,CAAC,uCAAuC,aAAa,2BAA2B,EAAE,OAAO,CAAC,CAAC;oBAC3G,CAAC;oBACD,IAAI,gBAAgB,EAAE,CAAC;wBACrB,cAAc,CAAC,qCAAqC,WAAW,SAAS,kBAAkB,CAAC,OAAO,2BAA2B,EAAE,OAAO,CAAC,CAAC;oBAC1I,CAAC;oBAED,qBAAqB,EAAE,CAAC;oBACxB,wBAAwB,EAAE,CAAC;oBAC3B,iEAAiE;oBAEjE,2BAA2B;oBAC3B,UAAU,CAAC,GAAG,EAAE;wBACd,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC;wBACvC,kBAAkB,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,qCAAqC;oBACvE,CAAC,EAAE,IAAI,CAAC,CAAC;gBACX,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,0CAA0C;gBAC1C,kBAAkB,CAAC,OAAO,GAAG,WAAW,CAAC;YAC3C,CAAC;QACH,CAAC,EAAE,eAAe,CAAC,CAAC;QAEpB,OAAO,GAAG,EAAE;YACV,cAAc,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YACtD,aAAa,CAAC,UAAU,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,qBAAqB,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * File-based logging system for duplication detection
3
+ * Logs to a file instead of console to avoid cluttering the terminal
4
+ */
5
+ /**
6
+ * Write a log entry to the file
7
+ */
8
+ export declare function logDuplication(message: string, level?: 'INFO' | 'WARN' | 'ERROR'): void;
9
+ /**
10
+ * Clear the log file
11
+ */
12
+ export declare function clearDuplicationLog(): void;
13
+ /**
14
+ * Get the log file path
15
+ */
16
+ export declare function getLogFilePath(): string;
17
+ /**
18
+ * Read the last N lines from the log file
19
+ */
20
+ export declare function readLastLogLines(lines?: number): string;
21
+ //# sourceMappingURL=duplication-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplication-logger.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/duplication-logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,GAAG,MAAM,GAAG,OAAgB,GAAG,IAAI,CAuB/F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAS1C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,GAAE,MAAW,GAAG,MAAM,CAa3D"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * File-based logging system for duplication detection
3
+ * Logs to a file instead of console to avoid cluttering the terminal
4
+ */
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import os from 'os';
8
+ const LOG_DIR = path.join(os.tmpdir(), 'centaurus-cli-logs');
9
+ const LOG_FILE = path.join(LOG_DIR, 'duplication-detector.log');
10
+ const MAX_LOG_SIZE = 1024 * 1024; // 1MB
11
+ // Ensure log directory exists
12
+ try {
13
+ if (!fs.existsSync(LOG_DIR)) {
14
+ fs.mkdirSync(LOG_DIR, { recursive: true });
15
+ }
16
+ }
17
+ catch (error) {
18
+ // Silently fail if we can't create log directory
19
+ }
20
+ /**
21
+ * Write a log entry to the file
22
+ */
23
+ export function logDuplication(message, level = 'INFO') {
24
+ try {
25
+ const timestamp = new Date().toISOString();
26
+ const logEntry = `[${timestamp}] [${level}] ${message}\n`;
27
+ // Check file size and rotate if needed
28
+ if (fs.existsSync(LOG_FILE)) {
29
+ const stats = fs.statSync(LOG_FILE);
30
+ if (stats.size > MAX_LOG_SIZE) {
31
+ // Rotate log file
32
+ const backupFile = path.join(LOG_DIR, `duplication-detector.log.old`);
33
+ if (fs.existsSync(backupFile)) {
34
+ fs.unlinkSync(backupFile);
35
+ }
36
+ fs.renameSync(LOG_FILE, backupFile);
37
+ }
38
+ }
39
+ // Append to log file
40
+ fs.appendFileSync(LOG_FILE, logEntry);
41
+ }
42
+ catch (error) {
43
+ // Silently fail if we can't write to log
44
+ }
45
+ }
46
+ /**
47
+ * Clear the log file
48
+ */
49
+ export function clearDuplicationLog() {
50
+ try {
51
+ if (fs.existsSync(LOG_FILE)) {
52
+ fs.unlinkSync(LOG_FILE);
53
+ }
54
+ logDuplication('=== Log cleared ===', 'INFO');
55
+ }
56
+ catch (error) {
57
+ // Silently fail
58
+ }
59
+ }
60
+ /**
61
+ * Get the log file path
62
+ */
63
+ export function getLogFilePath() {
64
+ return LOG_FILE;
65
+ }
66
+ /**
67
+ * Read the last N lines from the log file
68
+ */
69
+ export function readLastLogLines(lines = 50) {
70
+ try {
71
+ if (!fs.existsSync(LOG_FILE)) {
72
+ return 'No log file found';
73
+ }
74
+ const content = fs.readFileSync(LOG_FILE, 'utf-8');
75
+ const allLines = content.split('\n').filter(line => line.trim());
76
+ const lastLines = allLines.slice(-lines);
77
+ return lastLines.join('\n');
78
+ }
79
+ catch (error) {
80
+ return `Error reading log: ${error}`;
81
+ }
82
+ }
83
+ // Initialize log on module load
84
+ logDuplication('=== Duplication detector initialized ===', 'INFO');
85
+ //# sourceMappingURL=duplication-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplication-logger.js","sourceRoot":"","sources":["../../../src/ui/utils/duplication-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Terminal Output Scanner
3
+ * Detects UI duplication by analyzing the actual terminal buffer content
4
+ */
5
+ /**
6
+ * Scan terminal output for duplication patterns
7
+ * Returns true if duplication is detected
8
+ */
9
+ export declare function scanTerminalForDuplication(): boolean;
10
+ export declare function injectTerminalMarker(): void;
11
+ export declare function getMarkerCount(): number;
12
+ export declare function resetMarkerCount(): void;
13
+ export declare function captureInkOutput(chunk: string): void;
14
+ export declare function clearInkOutputBuffer(): void;
15
+ export declare function pauseDetection(): void;
16
+ export declare function resumeDetection(): void;
17
+ export declare function hookStdout(onDuplicationDetected: () => void): void;
18
+ export declare function unhookStdout(): void;
19
+ //# sourceMappingURL=terminal-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-scanner.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/terminal-scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAuBpD;AASD,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC;AASD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CA6BpD;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C;AASD,wBAAgB,cAAc,IAAI,IAAI,CAGrC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED,wBAAgB,UAAU,CAAC,qBAAqB,EAAE,MAAM,IAAI,GAAG,IAAI,CAkIlE;AAED,wBAAgB,YAAY,IAAI,IAAI,CAanC"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Terminal Output Scanner
3
+ * Detects UI duplication by analyzing the actual terminal buffer content
4
+ */
5
+ import { logDuplication } from './duplication-logger.js';
6
+ // Store the last known good state
7
+ let lastKnownLineCount = 0;
8
+ let consecutiveDuplicationDetections = 0;
9
+ /**
10
+ * Scan terminal output for duplication patterns
11
+ * Returns true if duplication is detected
12
+ */
13
+ export function scanTerminalForDuplication() {
14
+ try {
15
+ // Get terminal dimensions
16
+ const rows = process.stdout.rows || 0;
17
+ const cols = process.stdout.columns || 0;
18
+ if (rows === 0 || cols === 0) {
19
+ return false;
20
+ }
21
+ // Try to detect duplication by checking for repeated patterns
22
+ // We'll use a heuristic: if we see the same distinctive text multiple times,
23
+ // it's likely duplicated
24
+ // Since we can't directly read the terminal buffer in Node.js,
25
+ // we'll use a different approach: track cursor position changes
26
+ // and detect anomalies
27
+ return false; // Placeholder - terminal buffer reading not available in Node.js
28
+ }
29
+ catch (error) {
30
+ logDuplication(`Terminal scan error: ${error}`, 'WARN');
31
+ return false;
32
+ }
33
+ }
34
+ /**
35
+ * Alternative: Use a marker-based detection system
36
+ * Inject invisible markers and count them
37
+ */
38
+ let markerCount = 0;
39
+ const MARKER_ID = `\x1b]1337;marker=${Date.now()}\x07`;
40
+ export function injectTerminalMarker() {
41
+ // Inject an invisible marker that we can count
42
+ process.stdout.write(MARKER_ID);
43
+ markerCount++;
44
+ logDuplication(`Marker injected, count: ${markerCount}`, 'INFO');
45
+ }
46
+ export function getMarkerCount() {
47
+ return markerCount;
48
+ }
49
+ export function resetMarkerCount() {
50
+ markerCount = 0;
51
+ logDuplication('Marker count reset', 'INFO');
52
+ }
53
+ /**
54
+ * Better approach: Monitor Ink's render output
55
+ * Hook into Ink's output stream
56
+ */
57
+ let inkOutputBuffer = [];
58
+ const MAX_BUFFER_SIZE = 1000;
59
+ export function captureInkOutput(chunk) {
60
+ inkOutputBuffer.push(chunk);
61
+ // Keep buffer size manageable
62
+ if (inkOutputBuffer.length > MAX_BUFFER_SIZE) {
63
+ inkOutputBuffer.shift();
64
+ }
65
+ // Check for duplication patterns in recent output
66
+ if (inkOutputBuffer.length > 10) {
67
+ const recentOutput = inkOutputBuffer.slice(-10).join('');
68
+ // Look for the banner ASCII art pattern
69
+ const bannerPattern = /██████╗███████╗███╗ ██╗████████╗/g;
70
+ const bannerMatches = recentOutput.match(bannerPattern);
71
+ if (bannerMatches && bannerMatches.length > 1) {
72
+ logDuplication(`Banner pattern found ${bannerMatches.length} times in recent output!`, 'ERROR');
73
+ return;
74
+ }
75
+ // Look for InputBox pattern
76
+ const inputBoxPattern = /CWD:.*Model:.*AUTO-ACCEPT:/g;
77
+ const inputBoxMatches = recentOutput.match(inputBoxPattern);
78
+ if (inputBoxMatches && inputBoxMatches.length > 1) {
79
+ logDuplication(`InputBox pattern found ${inputBoxMatches.length} times in recent output!`, 'ERROR');
80
+ }
81
+ }
82
+ }
83
+ export function clearInkOutputBuffer() {
84
+ inkOutputBuffer = [];
85
+ logDuplication('Ink output buffer cleared', 'INFO');
86
+ }
87
+ /**
88
+ * Hook into process.stdout.write to intercept all output
89
+ */
90
+ const originalWrite = process.stdout.write.bind(process.stdout);
91
+ let isHooked = false;
92
+ let detectionEnabled = true;
93
+ export function pauseDetection() {
94
+ detectionEnabled = false;
95
+ logDuplication('Detection paused', 'INFO');
96
+ }
97
+ export function resumeDetection() {
98
+ detectionEnabled = true;
99
+ logDuplication('Detection resumed', 'INFO');
100
+ }
101
+ export function hookStdout(onDuplicationDetected) {
102
+ if (isHooked)
103
+ return;
104
+ logDuplication('Hooking into stdout for duplication detection', 'INFO');
105
+ isHooked = true;
106
+ let outputBuffer = '';
107
+ let lastCheckTime = Date.now();
108
+ let recoveryScheduled = false;
109
+ let lastRecoveryTime = 0;
110
+ // Continuous monitoring - check buffer every 100ms
111
+ const monitoringInterval = setInterval(() => {
112
+ if (!detectionEnabled || recoveryScheduled) {
113
+ return;
114
+ }
115
+ const now = Date.now();
116
+ // Prevent recovery spam
117
+ if (now - lastRecoveryTime < 2000) {
118
+ return;
119
+ }
120
+ // Check for banner duplication
121
+ const bannerPattern = /██████╗███████╗███╗ ██╗████████╗ █████╗ ██╗ ██╗██████╗ ██╗ ██╗███████╗/g;
122
+ const bannerMatches = outputBuffer.match(bannerPattern);
123
+ // Log buffer state periodically for debugging
124
+ if (now % 5000 < 100) { // Every ~5 seconds
125
+ const bufferPreview = outputBuffer.slice(-500).replace(/\n/g, '\\n').substring(0, 200);
126
+ logDuplication(`[MONITOR] Buffer size: ${outputBuffer.length}, Banners: ${bannerMatches ? bannerMatches.length : 0}, Preview: ${bufferPreview}`, 'INFO');
127
+ }
128
+ if (bannerMatches && bannerMatches.length > 1) {
129
+ logDuplication(`[MONITOR] DUPLICATION DETECTED! Banner found ${bannerMatches.length} times`, 'ERROR');
130
+ logDuplication(`[MONITOR] Buffer content (last 1000 chars): ${outputBuffer.slice(-1000)}`, 'ERROR');
131
+ recoveryScheduled = true;
132
+ lastRecoveryTime = now;
133
+ outputBuffer = '';
134
+ pauseDetection();
135
+ setImmediate(() => {
136
+ logDuplication('[MONITOR] Executing recovery', 'ERROR');
137
+ onDuplicationDetected();
138
+ recoveryScheduled = false;
139
+ setTimeout(() => {
140
+ resumeDetection();
141
+ outputBuffer = '';
142
+ }, 800);
143
+ });
144
+ }
145
+ }, 100); // Check every 100ms
146
+ // Store interval ID for cleanup
147
+ hookStdout.monitoringInterval = monitoringInterval;
148
+ process.stdout.write = function (chunk, ...args) {
149
+ const str = chunk.toString();
150
+ // Always write to actual stdout first
151
+ const result = originalWrite(chunk, ...args);
152
+ // Then add to our monitoring buffer
153
+ outputBuffer += str;
154
+ // Skip detection if paused (during recovery)
155
+ if (!detectionEnabled) {
156
+ return result;
157
+ }
158
+ const now = Date.now();
159
+ // Prevent recovery spam - at least 2 seconds between recoveries
160
+ if (now - lastRecoveryTime < 2000) {
161
+ return result;
162
+ }
163
+ // Look for banner duplication in the buffer
164
+ const bannerPattern = /██████╗███████╗███╗ ██╗████████╗ █████╗ ██╗ ██╗██████╗ ██╗ ██╗███████╗/g;
165
+ const bannerMatches = outputBuffer.match(bannerPattern);
166
+ if (bannerMatches && bannerMatches.length > 1 && !recoveryScheduled) {
167
+ logDuplication(`DUPLICATION DETECTED! Banner found ${bannerMatches.length} times in output buffer (${outputBuffer.length} bytes)`, 'ERROR');
168
+ logDuplication(`Time since last recovery: ${now - lastRecoveryTime}ms`, 'ERROR');
169
+ logDuplication(`Buffer content (last 2000 chars): ${outputBuffer.slice(-2000)}`, 'ERROR');
170
+ recoveryScheduled = true;
171
+ lastRecoveryTime = now;
172
+ // IMMEDIATELY clear the output buffer
173
+ outputBuffer = '';
174
+ logDuplication('Output buffer cleared immediately', 'ERROR');
175
+ // Pause detection during recovery
176
+ pauseDetection();
177
+ // Use setImmediate to defer recovery until after current render completes
178
+ setImmediate(() => {
179
+ logDuplication('Executing immediate recovery', 'ERROR');
180
+ onDuplicationDetected();
181
+ consecutiveDuplicationDetections = 0;
182
+ recoveryScheduled = false;
183
+ // Resume detection after recovery completes
184
+ setTimeout(() => {
185
+ logDuplication('Resuming detection after recovery', 'INFO');
186
+ resumeDetection();
187
+ outputBuffer = ''; // Clear buffer again to start fresh
188
+ }, 800);
189
+ });
190
+ }
191
+ else {
192
+ // Reset counter if no duplication found
193
+ if (now - lastCheckTime > 1000) {
194
+ consecutiveDuplicationDetections = 0;
195
+ lastCheckTime = now;
196
+ }
197
+ }
198
+ // Keep buffer size manageable (last 150KB to catch more duplication)
199
+ if (outputBuffer.length > 150000) {
200
+ outputBuffer = outputBuffer.slice(-150000);
201
+ }
202
+ return result;
203
+ };
204
+ }
205
+ export function unhookStdout() {
206
+ if (!isHooked)
207
+ return;
208
+ logDuplication('Unhooking stdout', 'INFO');
209
+ // Clear monitoring interval
210
+ if (hookStdout.monitoringInterval) {
211
+ clearInterval(hookStdout.monitoringInterval);
212
+ logDuplication('Monitoring interval cleared', 'INFO');
213
+ }
214
+ process.stdout.write = originalWrite;
215
+ isHooked = false;
216
+ }
217
+ //# sourceMappingURL=terminal-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-scanner.js","sourceRoot":"","sources":["../../../src/ui/utils/terminal-scanner.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "centaurus-cli",
3
- "version": "2.0.0",
4
- "description": "A powerful command-line AI coding assistant with Google Gemini and OpenRouter support",
3
+ "version": "2.0.2",
4
+ "description": "A powerful command-line AI coding assistant with Google Gemini support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -21,26 +21,16 @@
21
21
  "cli",
22
22
  "coding-assistant",
23
23
  "gemini",
24
- "openrouter",
25
24
  "agentic",
26
25
  "code-editor",
27
26
  "ai-assistant",
28
27
  "terminal",
29
28
  "developer-tools",
30
- "chatgpt",
31
29
  "llm",
32
30
  "artificial-intelligence"
33
31
  ],
34
32
  "author": "Rohan Abhilash S",
35
33
  "license": "MIT",
36
- "repository": {
37
- "type": "git",
38
- "url": "https://github.com/Rohan-Abhilash/centaurus-cli.git"
39
- },
40
- "bugs": {
41
- "url": "https://github.com/Rohan-Abhilash/centaurus-cli/issues"
42
- },
43
- "homepage": "https://github.com/Rohan-Abhilash/centaurus-cli#readme",
44
34
  "engines": {
45
35
  "node": ">=18.0.0"
46
36
  },
@@ -53,7 +43,6 @@
53
43
  "AUTH_FLOW.md"
54
44
  ],
55
45
  "dependencies": {
56
- "@google/generative-ai": "^0.24.1",
57
46
  "@types/node": "^24.7.2",
58
47
  "@types/react": "^18.3.26",
59
48
  "axios": "^1.12.2",