@xagent-ai/cli 1.2.0 → 1.2.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 (80) hide show
  1. package/README.md +1 -1
  2. package/README_CN.md +1 -1
  3. package/dist/agents.js +164 -164
  4. package/dist/agents.js.map +1 -1
  5. package/dist/ai-client.d.ts +4 -6
  6. package/dist/ai-client.d.ts.map +1 -1
  7. package/dist/ai-client.js +137 -115
  8. package/dist/ai-client.js.map +1 -1
  9. package/dist/auth.js +4 -4
  10. package/dist/auth.js.map +1 -1
  11. package/dist/cli.js +184 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/config.js +3 -3
  14. package/dist/config.js.map +1 -1
  15. package/dist/context-compressor.d.ts.map +1 -1
  16. package/dist/context-compressor.js +65 -81
  17. package/dist/context-compressor.js.map +1 -1
  18. package/dist/conversation.d.ts +1 -1
  19. package/dist/conversation.d.ts.map +1 -1
  20. package/dist/conversation.js +5 -31
  21. package/dist/conversation.js.map +1 -1
  22. package/dist/memory.d.ts +5 -1
  23. package/dist/memory.d.ts.map +1 -1
  24. package/dist/memory.js +77 -37
  25. package/dist/memory.js.map +1 -1
  26. package/dist/remote-ai-client.d.ts +1 -8
  27. package/dist/remote-ai-client.d.ts.map +1 -1
  28. package/dist/remote-ai-client.js +55 -65
  29. package/dist/remote-ai-client.js.map +1 -1
  30. package/dist/retry.d.ts +35 -0
  31. package/dist/retry.d.ts.map +1 -0
  32. package/dist/retry.js +166 -0
  33. package/dist/retry.js.map +1 -0
  34. package/dist/session.d.ts +0 -5
  35. package/dist/session.d.ts.map +1 -1
  36. package/dist/session.js +243 -312
  37. package/dist/session.js.map +1 -1
  38. package/dist/slash-commands.d.ts +1 -0
  39. package/dist/slash-commands.d.ts.map +1 -1
  40. package/dist/slash-commands.js +91 -9
  41. package/dist/slash-commands.js.map +1 -1
  42. package/dist/smart-approval.d.ts.map +1 -1
  43. package/dist/smart-approval.js +18 -17
  44. package/dist/smart-approval.js.map +1 -1
  45. package/dist/system-prompt-generator.d.ts.map +1 -1
  46. package/dist/system-prompt-generator.js +149 -139
  47. package/dist/system-prompt-generator.js.map +1 -1
  48. package/dist/theme.d.ts +48 -0
  49. package/dist/theme.d.ts.map +1 -1
  50. package/dist/theme.js +254 -0
  51. package/dist/theme.js.map +1 -1
  52. package/dist/tools/edit-diff.d.ts +32 -0
  53. package/dist/tools/edit-diff.d.ts.map +1 -0
  54. package/dist/tools/edit-diff.js +185 -0
  55. package/dist/tools/edit-diff.js.map +1 -0
  56. package/dist/tools/edit.d.ts +11 -0
  57. package/dist/tools/edit.d.ts.map +1 -0
  58. package/dist/tools/edit.js +129 -0
  59. package/dist/tools/edit.js.map +1 -0
  60. package/dist/tools.d.ts +19 -5
  61. package/dist/tools.d.ts.map +1 -1
  62. package/dist/tools.js +979 -631
  63. package/dist/tools.js.map +1 -1
  64. package/dist/types.d.ts +6 -31
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +3 -2
  67. package/src/agents.ts +504 -504
  68. package/src/ai-client.ts +1559 -1458
  69. package/src/auth.ts +4 -4
  70. package/src/cli.ts +195 -1
  71. package/src/config.ts +3 -3
  72. package/src/memory.ts +55 -14
  73. package/src/remote-ai-client.ts +663 -683
  74. package/src/retry.ts +217 -0
  75. package/src/session.ts +1736 -1840
  76. package/src/slash-commands.ts +98 -9
  77. package/src/smart-approval.ts +626 -625
  78. package/src/system-prompt-generator.ts +853 -843
  79. package/src/theme.ts +284 -0
  80. package/src/tools.ts +390 -70
package/src/retry.ts ADDED
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Retry utility with exponential backoff and jitter
3
+ */
4
+
5
+ export interface RetryConfig {
6
+ maxRetries: number; // Maximum number of retry attempts (default: 3)
7
+ baseDelay: number; // Base delay in ms (default: 1000)
8
+ maxDelay: number; // Maximum delay in ms (default: 10000)
9
+ maxTotalTime: number; // Maximum total time in ms (default: 600000 = 10min)
10
+ jitter: boolean; // Add random jitter to delay (default: true)
11
+ retryOnTimeout: boolean; // Retry on timeout errors (default: true)
12
+ retryOn5xx: boolean; // Retry on 5xx server errors (default: true)
13
+ retryOn429: boolean; // Retry on 429 rate limit (default: true)
14
+ backoffMultiplier: number; // Delay multiplier for each retry (default: 2)
15
+ }
16
+
17
+ export interface RetryResult<T> {
18
+ success: boolean;
19
+ data?: T;
20
+ error?: Error;
21
+ attempts: number;
22
+ totalTime: number;
23
+ lastError?: Error;
24
+ }
25
+
26
+ const DEFAULT_CONFIG: RetryConfig = {
27
+ maxRetries: 3,
28
+ baseDelay: 1000,
29
+ maxDelay: 10000,
30
+ maxTotalTime: 600000,
31
+ jitter: true,
32
+ retryOnTimeout: true,
33
+ retryOn5xx: true,
34
+ retryOn429: true,
35
+ backoffMultiplier: 2
36
+ };
37
+
38
+ /**
39
+ * Check if an error is retryable
40
+ */
41
+ function isRetryableError(error: unknown, config: RetryConfig): boolean {
42
+ // Extract status code from different error formats
43
+ let statusCode: number | undefined;
44
+
45
+ if (error && typeof error === 'object') {
46
+ const err = error as Record<string, unknown>;
47
+
48
+ // axios error format
49
+ if (err.response && typeof err.response === 'object') {
50
+ const response = err.response as Record<string, unknown>;
51
+ statusCode = response.status as number | undefined;
52
+ }
53
+ // Direct status code
54
+ else if (err.statusCode) {
55
+ statusCode = err.statusCode as number;
56
+ }
57
+ else if (err.status) {
58
+ statusCode = err.status as number;
59
+ }
60
+ }
61
+
62
+ // Check error message for timeout
63
+ const errorMessage = error instanceof Error ? error.message : String(error);
64
+ const isTimeout = errorMessage.includes('timeout') ||
65
+ errorMessage.includes('Timeout') ||
66
+ errorMessage.includes('No response received');
67
+
68
+ // Check if should retry based on status code
69
+ if (statusCode !== undefined) {
70
+ // Retry on 429 (rate limit) and 5xx (server errors)
71
+ if (statusCode === 429 && config.retryOn429) return true;
72
+ if (statusCode >= 500 && statusCode < 600 && config.retryOn5xx) return true;
73
+ return false;
74
+ }
75
+
76
+ // Retry on timeout
77
+ if (isTimeout && config.retryOnTimeout) return true;
78
+
79
+ return false;
80
+ }
81
+
82
+ /**
83
+ * Calculate delay with exponential backoff and jitter
84
+ */
85
+ function calculateDelay(attempt: number, config: RetryConfig): number {
86
+ const exponentialDelay = config.baseDelay * Math.pow(config.backoffMultiplier, attempt);
87
+ const delay = Math.min(exponentialDelay, config.maxDelay);
88
+
89
+ // Add jitter (0.5 to 1.5 of the delay)
90
+ if (config.jitter) {
91
+ const jitterFactor = 0.5 + Math.random();
92
+ return Math.floor(delay * jitterFactor);
93
+ }
94
+
95
+ return delay;
96
+ }
97
+
98
+ /**
99
+ * Sleep for a specified duration
100
+ */
101
+ function sleep(ms: number): Promise<void> {
102
+ return new Promise(resolve => setTimeout(resolve, ms));
103
+ }
104
+
105
+ /**
106
+ * Check if total time exceeds maximum allowed
107
+ */
108
+ function wouldExceedTotalTime(
109
+ startTime: number,
110
+ attempt: number,
111
+ delay: number,
112
+ config: RetryConfig
113
+ ): boolean {
114
+ const elapsed = Date.now() - startTime;
115
+ const remaining = config.maxTotalTime - elapsed;
116
+ return remaining <= delay;
117
+ }
118
+
119
+ /**
120
+ * Execute a function with retry logic
121
+ *
122
+ * @param fn - The async function to execute
123
+ * @param config - Retry configuration (optional)
124
+ * @returns RetryResult containing success status and data/error
125
+ */
126
+ export async function withRetry<T>(
127
+ fn: () => Promise<T>,
128
+ config?: Partial<RetryConfig>
129
+ ): Promise<RetryResult<T>> {
130
+ const mergedConfig: RetryConfig = { ...DEFAULT_CONFIG, ...config };
131
+ const startTime = Date.now();
132
+ let lastError: Error | undefined;
133
+
134
+ for (let attempt = 0; attempt <= mergedConfig.maxRetries; attempt++) {
135
+ const attemptStartTime = Date.now();
136
+
137
+ try {
138
+ const data = await fn();
139
+
140
+ return {
141
+ success: true,
142
+ data,
143
+ attempts: attempt + 1,
144
+ totalTime: Date.now() - startTime
145
+ };
146
+ } catch (error) {
147
+ lastError = error instanceof Error ? error : new Error(String(error));
148
+
149
+ // Check if this error is retryable
150
+ if (!isRetryableError(error, mergedConfig)) {
151
+ return {
152
+ success: false,
153
+ error: lastError,
154
+ attempts: attempt + 1,
155
+ totalTime: Date.now() - startTime,
156
+ lastError
157
+ };
158
+ }
159
+
160
+ // Check if we've exceeded maximum total time
161
+ if (Date.now() - startTime >= mergedConfig.maxTotalTime) {
162
+ return {
163
+ success: false,
164
+ error: new Error(`Max total time exceeded after ${attempt + 1} attempts`),
165
+ attempts: attempt + 1,
166
+ totalTime: Date.now() - startTime,
167
+ lastError
168
+ };
169
+ }
170
+
171
+ // Calculate delay for next retry
172
+ const delay = calculateDelay(attempt, mergedConfig);
173
+
174
+ // Check if next retry would exceed max total time
175
+ if (wouldExceedTotalTime(startTime, attempt, delay, mergedConfig)) {
176
+ return {
177
+ success: false,
178
+ error: new Error(`Would exceed max total time`),
179
+ attempts: attempt + 1,
180
+ totalTime: Date.now() - startTime,
181
+ lastError
182
+ };
183
+ }
184
+
185
+ // Wait before next retry (don't wait after last attempt)
186
+ if (attempt < mergedConfig.maxRetries) {
187
+ await sleep(delay);
188
+ }
189
+ }
190
+ }
191
+
192
+ // Should not reach here, but just in case
193
+ return {
194
+ success: false,
195
+ error: lastError || new Error('Unknown error'),
196
+ attempts: mergedConfig.maxRetries + 1,
197
+ totalTime: Date.now() - startTime,
198
+ lastError
199
+ };
200
+ }
201
+
202
+ /**
203
+ * Create a retryable version of a function
204
+ */
205
+ export function createRetryable<T extends (...args: unknown[]) => Promise<unknown>>(
206
+ fn: T,
207
+ config?: Partial<RetryConfig>
208
+ ): T {
209
+ return ((...args: Parameters<T>) => {
210
+ return withRetry(() => fn(...args), config).then(result => {
211
+ if (result.success) {
212
+ return result.data;
213
+ }
214
+ throw result.error;
215
+ });
216
+ }) as T;
217
+ }