erosolar-cli 1.7.14 → 1.7.16
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.
- package/dist/core/responseVerifier.d.ts +79 -0
- package/dist/core/responseVerifier.d.ts.map +1 -0
- package/dist/core/responseVerifier.js +443 -0
- package/dist/core/responseVerifier.js.map +1 -0
- package/dist/shell/interactiveShell.d.ts +10 -0
- package/dist/shell/interactiveShell.d.ts.map +1 -1
- package/dist/shell/interactiveShell.js +80 -0
- package/dist/shell/interactiveShell.js.map +1 -1
- package/dist/ui/ShellUIAdapter.d.ts +3 -0
- package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
- package/dist/ui/ShellUIAdapter.js +4 -10
- package/dist/ui/ShellUIAdapter.js.map +1 -1
- package/dist/ui/persistentPrompt.d.ts +4 -0
- package/dist/ui/persistentPrompt.d.ts.map +1 -1
- package/dist/ui/persistentPrompt.js +10 -11
- package/dist/ui/persistentPrompt.js.map +1 -1
- package/package.json +1 -1
- package/dist/bin/core/agent.js +0 -362
- package/dist/bin/core/agentProfileManifest.js +0 -187
- package/dist/bin/core/agentProfiles.js +0 -34
- package/dist/bin/core/agentRulebook.js +0 -135
- package/dist/bin/core/agentSchemaLoader.js +0 -233
- package/dist/bin/core/contextManager.js +0 -412
- package/dist/bin/core/contextWindow.js +0 -122
- package/dist/bin/core/customCommands.js +0 -80
- package/dist/bin/core/errors/apiKeyErrors.js +0 -114
- package/dist/bin/core/errors/errorTypes.js +0 -340
- package/dist/bin/core/errors/safetyValidator.js +0 -304
- package/dist/bin/core/errors.js +0 -32
- package/dist/bin/core/modelDiscovery.js +0 -755
- package/dist/bin/core/preferences.js +0 -224
- package/dist/bin/core/schemaValidator.js +0 -92
- package/dist/bin/core/secretStore.js +0 -199
- package/dist/bin/core/sessionStore.js +0 -187
- package/dist/bin/core/toolRuntime.js +0 -290
- package/dist/bin/core/types.js +0 -1
- package/dist/bin/shell/bracketedPasteManager.js +0 -350
- package/dist/bin/shell/fileChangeTracker.js +0 -65
- package/dist/bin/shell/interactiveShell.js +0 -2908
- package/dist/bin/shell/liveStatus.js +0 -78
- package/dist/bin/shell/shellApp.js +0 -290
- package/dist/bin/shell/systemPrompt.js +0 -60
- package/dist/bin/shell/updateManager.js +0 -108
- package/dist/bin/ui/ShellUIAdapter.js +0 -459
- package/dist/bin/ui/UnifiedUIController.js +0 -183
- package/dist/bin/ui/animation/AnimationScheduler.js +0 -430
- package/dist/bin/ui/codeHighlighter.js +0 -854
- package/dist/bin/ui/designSystem.js +0 -121
- package/dist/bin/ui/display.js +0 -1222
- package/dist/bin/ui/interrupts/InterruptManager.js +0 -437
- package/dist/bin/ui/layout.js +0 -139
- package/dist/bin/ui/orchestration/StatusOrchestrator.js +0 -403
- package/dist/bin/ui/outputMode.js +0 -38
- package/dist/bin/ui/persistentPrompt.js +0 -183
- package/dist/bin/ui/richText.js +0 -338
- package/dist/bin/ui/shortcutsHelp.js +0 -87
- package/dist/bin/ui/telemetry/UITelemetry.js +0 -443
- package/dist/bin/ui/textHighlighter.js +0 -210
- package/dist/bin/ui/theme.js +0 -116
- package/dist/bin/ui/toolDisplay.js +0 -423
- package/dist/bin/ui/toolDisplayAdapter.js +0 -357
|
@@ -1,437 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* InterruptManager - Manages user interruptions with priority queuing
|
|
3
|
-
* Handles interrupt prioritization, deferred execution, and smooth transitions
|
|
4
|
-
*/
|
|
5
|
-
import { EventEmitter } from 'events';
|
|
6
|
-
export var InterruptPriority;
|
|
7
|
-
(function (InterruptPriority) {
|
|
8
|
-
InterruptPriority[InterruptPriority["CRITICAL"] = 100] = "CRITICAL";
|
|
9
|
-
InterruptPriority[InterruptPriority["HIGH"] = 75] = "HIGH";
|
|
10
|
-
InterruptPriority[InterruptPriority["NORMAL"] = 50] = "NORMAL";
|
|
11
|
-
InterruptPriority[InterruptPriority["LOW"] = 25] = "LOW";
|
|
12
|
-
InterruptPriority[InterruptPriority["BACKGROUND"] = 0] = "BACKGROUND";
|
|
13
|
-
})(InterruptPriority || (InterruptPriority = {}));
|
|
14
|
-
export class InterruptManager extends EventEmitter {
|
|
15
|
-
constructor(policy = {}) {
|
|
16
|
-
super();
|
|
17
|
-
this.pendingQueue = [];
|
|
18
|
-
this.activeInterrupts = new Map();
|
|
19
|
-
this.deferredInterrupts = new Map();
|
|
20
|
-
this.isProcessing = false;
|
|
21
|
-
this.transitionTimer = null;
|
|
22
|
-
this.policy = {
|
|
23
|
-
maxQueueSize: 100,
|
|
24
|
-
maxDeferrals: 3,
|
|
25
|
-
defaultTTL: 30000, // 30 seconds default TTL
|
|
26
|
-
allowConcurrent: false,
|
|
27
|
-
transitionDuration: 200,
|
|
28
|
-
...policy,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Queue a new interrupt
|
|
33
|
-
*/
|
|
34
|
-
queue(config) {
|
|
35
|
-
const id = this.generateId();
|
|
36
|
-
const interrupt = {
|
|
37
|
-
...config,
|
|
38
|
-
id,
|
|
39
|
-
timestamp: Date.now(),
|
|
40
|
-
ttl: config.ttl || this.policy.defaultTTL,
|
|
41
|
-
deferrable: config.deferrable ?? true,
|
|
42
|
-
blocking: config.blocking ?? false,
|
|
43
|
-
status: 'pending',
|
|
44
|
-
deferredCount: 0,
|
|
45
|
-
};
|
|
46
|
-
// Check queue size limit
|
|
47
|
-
if (this.pendingQueue.length >= this.policy.maxQueueSize) {
|
|
48
|
-
// Remove lowest priority expired or old interrupts
|
|
49
|
-
this.pruneQueue();
|
|
50
|
-
if (this.pendingQueue.length >= this.policy.maxQueueSize) {
|
|
51
|
-
this.emit('interrupt:rejected', {
|
|
52
|
-
interrupt,
|
|
53
|
-
reason: 'queue-full',
|
|
54
|
-
});
|
|
55
|
-
return '';
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// Insert based on priority
|
|
59
|
-
const insertIndex = this.findInsertIndex(interrupt.priority);
|
|
60
|
-
this.pendingQueue.splice(insertIndex, 0, interrupt);
|
|
61
|
-
this.emit('interrupt:queued', interrupt);
|
|
62
|
-
// Start expiry timer if TTL is set
|
|
63
|
-
if (interrupt.ttl && interrupt.ttl > 0) {
|
|
64
|
-
this.scheduleExpiry(interrupt);
|
|
65
|
-
}
|
|
66
|
-
// Process queue
|
|
67
|
-
this.processQueue();
|
|
68
|
-
return id;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Process the interrupt queue
|
|
72
|
-
*/
|
|
73
|
-
async processQueue() {
|
|
74
|
-
if (this.isProcessing) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
this.isProcessing = true;
|
|
78
|
-
try {
|
|
79
|
-
while (this.pendingQueue.length > 0) {
|
|
80
|
-
const interrupt = this.pendingQueue[0];
|
|
81
|
-
if (!interrupt)
|
|
82
|
-
break;
|
|
83
|
-
// Check if interrupt has expired
|
|
84
|
-
if (this.isExpired(interrupt)) {
|
|
85
|
-
this.expireInterrupt(interrupt);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
// Check if we can activate this interrupt
|
|
89
|
-
if (!this.canActivate(interrupt)) {
|
|
90
|
-
// If it's deferrable and hasn't exceeded max deferrals, defer it
|
|
91
|
-
if (interrupt.deferrable && interrupt.deferredCount < this.policy.maxDeferrals) {
|
|
92
|
-
this.deferInterrupt(interrupt);
|
|
93
|
-
}
|
|
94
|
-
break; // Wait for active interrupts to complete
|
|
95
|
-
}
|
|
96
|
-
// Remove from queue and activate
|
|
97
|
-
this.pendingQueue.shift();
|
|
98
|
-
await this.activateInterrupt(interrupt);
|
|
99
|
-
// If this interrupt is blocking, wait for it to complete
|
|
100
|
-
if (interrupt.blocking) {
|
|
101
|
-
await this.waitForCompletion(interrupt.id);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
this.isProcessing = false;
|
|
107
|
-
}
|
|
108
|
-
// Process deferred interrupts if queue is empty
|
|
109
|
-
if (this.pendingQueue.length === 0 && this.deferredInterrupts.size > 0) {
|
|
110
|
-
this.restoreDeferredInterrupts();
|
|
111
|
-
this.processQueue();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Check if interrupt can be activated
|
|
116
|
-
*/
|
|
117
|
-
canActivate(interrupt) {
|
|
118
|
-
// If no concurrent interrupts allowed and there are active ones
|
|
119
|
-
if (!this.policy.allowConcurrent && this.activeInterrupts.size > 0) {
|
|
120
|
-
// Check if this interrupt has higher priority than all active ones
|
|
121
|
-
for (const active of this.activeInterrupts.values()) {
|
|
122
|
-
if (active.priority >= interrupt.priority) {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
// Higher priority interrupt can preempt if active ones are deferrable
|
|
127
|
-
for (const active of this.activeInterrupts.values()) {
|
|
128
|
-
if (!active.deferrable) {
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Activate an interrupt
|
|
137
|
-
*/
|
|
138
|
-
async activateInterrupt(interrupt) {
|
|
139
|
-
interrupt.status = 'active';
|
|
140
|
-
interrupt.activatedAt = Date.now();
|
|
141
|
-
this.activeInterrupts.set(interrupt.id, interrupt);
|
|
142
|
-
// Handle smooth transition
|
|
143
|
-
if (this.policy.transitionDuration > 0) {
|
|
144
|
-
await this.smoothTransition('in', interrupt);
|
|
145
|
-
}
|
|
146
|
-
this.emit('interrupt:activated', interrupt);
|
|
147
|
-
// Execute handler if provided
|
|
148
|
-
if (interrupt.handler) {
|
|
149
|
-
try {
|
|
150
|
-
await interrupt.handler(interrupt);
|
|
151
|
-
this.completeInterrupt(interrupt.id);
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
this.emit('interrupt:error', {
|
|
155
|
-
interrupt,
|
|
156
|
-
error,
|
|
157
|
-
});
|
|
158
|
-
this.cancelInterrupt(interrupt.id);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Complete an interrupt
|
|
164
|
-
*/
|
|
165
|
-
completeInterrupt(id) {
|
|
166
|
-
const interrupt = this.activeInterrupts.get(id);
|
|
167
|
-
if (!interrupt)
|
|
168
|
-
return;
|
|
169
|
-
interrupt.status = 'completed';
|
|
170
|
-
interrupt.completedAt = Date.now();
|
|
171
|
-
this.activeInterrupts.delete(id);
|
|
172
|
-
// Handle smooth transition
|
|
173
|
-
if (this.policy.transitionDuration > 0) {
|
|
174
|
-
this.smoothTransition('out', interrupt);
|
|
175
|
-
}
|
|
176
|
-
this.emit('interrupt:completed', interrupt);
|
|
177
|
-
// Process next in queue
|
|
178
|
-
this.processQueue();
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Cancel an interrupt
|
|
182
|
-
*/
|
|
183
|
-
cancelInterrupt(id) {
|
|
184
|
-
// Check in queue
|
|
185
|
-
const queueIndex = this.pendingQueue.findIndex((i) => i.id === id);
|
|
186
|
-
if (queueIndex !== -1) {
|
|
187
|
-
const interrupt = this.pendingQueue[queueIndex];
|
|
188
|
-
if (interrupt) {
|
|
189
|
-
interrupt.status = 'cancelled';
|
|
190
|
-
this.pendingQueue.splice(queueIndex, 1);
|
|
191
|
-
this.emit('interrupt:cancelled', interrupt);
|
|
192
|
-
}
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
// Check in active
|
|
196
|
-
const active = this.activeInterrupts.get(id);
|
|
197
|
-
if (active) {
|
|
198
|
-
active.status = 'cancelled';
|
|
199
|
-
this.activeInterrupts.delete(id);
|
|
200
|
-
this.emit('interrupt:cancelled', active);
|
|
201
|
-
this.processQueue();
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
// Check in deferred
|
|
205
|
-
const deferred = this.deferredInterrupts.get(id);
|
|
206
|
-
if (deferred) {
|
|
207
|
-
deferred.status = 'cancelled';
|
|
208
|
-
this.deferredInterrupts.delete(id);
|
|
209
|
-
this.emit('interrupt:cancelled', deferred);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Defer an interrupt
|
|
214
|
-
*/
|
|
215
|
-
deferInterrupt(interrupt) {
|
|
216
|
-
this.pendingQueue.shift(); // Remove from queue
|
|
217
|
-
interrupt.status = 'deferred';
|
|
218
|
-
interrupt.deferredCount++;
|
|
219
|
-
this.deferredInterrupts.set(interrupt.id, interrupt);
|
|
220
|
-
this.emit('interrupt:deferred', interrupt);
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Restore deferred interrupts to queue
|
|
224
|
-
*/
|
|
225
|
-
restoreDeferredInterrupts() {
|
|
226
|
-
const deferred = Array.from(this.deferredInterrupts.values());
|
|
227
|
-
this.deferredInterrupts.clear();
|
|
228
|
-
for (const interrupt of deferred) {
|
|
229
|
-
interrupt.status = 'pending';
|
|
230
|
-
const insertIndex = this.findInsertIndex(interrupt.priority);
|
|
231
|
-
this.pendingQueue.splice(insertIndex, 0, interrupt);
|
|
232
|
-
this.emit('interrupt:restored', interrupt);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Expire an interrupt
|
|
237
|
-
*/
|
|
238
|
-
expireInterrupt(interrupt) {
|
|
239
|
-
interrupt.status = 'expired';
|
|
240
|
-
this.pendingQueue.shift();
|
|
241
|
-
this.emit('interrupt:expired', interrupt);
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Check if interrupt has expired
|
|
245
|
-
*/
|
|
246
|
-
isExpired(interrupt) {
|
|
247
|
-
if (!interrupt.ttl || interrupt.ttl <= 0) {
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
const age = Date.now() - interrupt.timestamp;
|
|
251
|
-
return age > interrupt.ttl;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Schedule interrupt expiry
|
|
255
|
-
*/
|
|
256
|
-
scheduleExpiry(interrupt) {
|
|
257
|
-
if (!interrupt.ttl || interrupt.ttl <= 0)
|
|
258
|
-
return;
|
|
259
|
-
setTimeout(() => {
|
|
260
|
-
if (interrupt.status === 'pending') {
|
|
261
|
-
const index = this.pendingQueue.indexOf(interrupt);
|
|
262
|
-
if (index !== -1) {
|
|
263
|
-
this.expireInterrupt(interrupt);
|
|
264
|
-
this.processQueue();
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}, interrupt.ttl);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Wait for interrupt completion
|
|
271
|
-
*/
|
|
272
|
-
waitForCompletion(id) {
|
|
273
|
-
return new Promise((resolve) => {
|
|
274
|
-
const checkCompletion = () => {
|
|
275
|
-
if (!this.activeInterrupts.has(id)) {
|
|
276
|
-
resolve();
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
setTimeout(checkCompletion, 50);
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
checkCompletion();
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Handle smooth transitions
|
|
287
|
-
*/
|
|
288
|
-
async smoothTransition(direction, interrupt) {
|
|
289
|
-
return new Promise((resolve) => {
|
|
290
|
-
this.emit('interrupt:transition', {
|
|
291
|
-
direction,
|
|
292
|
-
interrupt,
|
|
293
|
-
duration: this.policy.transitionDuration,
|
|
294
|
-
});
|
|
295
|
-
setTimeout(resolve, this.policy.transitionDuration);
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Find insertion index based on priority
|
|
300
|
-
*/
|
|
301
|
-
findInsertIndex(priority) {
|
|
302
|
-
for (let i = 0; i < this.pendingQueue.length; i++) {
|
|
303
|
-
const item = this.pendingQueue[i];
|
|
304
|
-
if (item && item.priority < priority) {
|
|
305
|
-
return i;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return this.pendingQueue.length;
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Prune expired and low-priority interrupts from queue
|
|
312
|
-
*/
|
|
313
|
-
pruneQueue() {
|
|
314
|
-
// Remove expired interrupts
|
|
315
|
-
this.pendingQueue = this.pendingQueue.filter((interrupt) => {
|
|
316
|
-
if (this.isExpired(interrupt)) {
|
|
317
|
-
interrupt.status = 'expired';
|
|
318
|
-
this.emit('interrupt:expired', interrupt);
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
return true;
|
|
322
|
-
});
|
|
323
|
-
// If still over limit, remove lowest priority
|
|
324
|
-
while (this.pendingQueue.length >= this.policy.maxQueueSize) {
|
|
325
|
-
const removed = this.pendingQueue.pop();
|
|
326
|
-
if (removed) {
|
|
327
|
-
removed.status = 'cancelled';
|
|
328
|
-
this.emit('interrupt:cancelled', removed);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* Generate unique interrupt ID
|
|
334
|
-
*/
|
|
335
|
-
generateId() {
|
|
336
|
-
return `interrupt-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Get interrupt by ID
|
|
340
|
-
*/
|
|
341
|
-
getInterrupt(id) {
|
|
342
|
-
// Check active
|
|
343
|
-
if (this.activeInterrupts.has(id)) {
|
|
344
|
-
return this.activeInterrupts.get(id);
|
|
345
|
-
}
|
|
346
|
-
// Check queue
|
|
347
|
-
const queued = this.pendingQueue.find((i) => i.id === id);
|
|
348
|
-
if (queued)
|
|
349
|
-
return queued;
|
|
350
|
-
// Check deferred
|
|
351
|
-
return this.deferredInterrupts.get(id);
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Get all interrupts with a specific status
|
|
355
|
-
*/
|
|
356
|
-
getInterruptsByStatus(status) {
|
|
357
|
-
const results = [];
|
|
358
|
-
if (status === 'active') {
|
|
359
|
-
results.push(...this.activeInterrupts.values());
|
|
360
|
-
}
|
|
361
|
-
else if (status === 'pending') {
|
|
362
|
-
results.push(...this.pendingQueue);
|
|
363
|
-
}
|
|
364
|
-
else if (status === 'deferred') {
|
|
365
|
-
results.push(...this.deferredInterrupts.values());
|
|
366
|
-
}
|
|
367
|
-
return results;
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* Get queue statistics
|
|
371
|
-
*/
|
|
372
|
-
getStatistics() {
|
|
373
|
-
const allInterrupts = [
|
|
374
|
-
...this.pendingQueue,
|
|
375
|
-
...this.activeInterrupts.values(),
|
|
376
|
-
...this.deferredInterrupts.values(),
|
|
377
|
-
];
|
|
378
|
-
const avgPriority = allInterrupts.length > 0
|
|
379
|
-
? allInterrupts.reduce((sum, i) => sum + i.priority, 0) / allInterrupts.length
|
|
380
|
-
: 0;
|
|
381
|
-
const oldestTimestamp = allInterrupts.length > 0
|
|
382
|
-
? Math.min(...allInterrupts.map((i) => i.timestamp))
|
|
383
|
-
: null;
|
|
384
|
-
return {
|
|
385
|
-
queueLength: this.pendingQueue.length,
|
|
386
|
-
activeCount: this.activeInterrupts.size,
|
|
387
|
-
deferredCount: this.deferredInterrupts.size,
|
|
388
|
-
averagePriority: avgPriority,
|
|
389
|
-
oldestTimestamp,
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Clear all interrupts
|
|
394
|
-
*/
|
|
395
|
-
clearAll() {
|
|
396
|
-
// Cancel all active
|
|
397
|
-
for (const interrupt of this.activeInterrupts.values()) {
|
|
398
|
-
interrupt.status = 'cancelled';
|
|
399
|
-
this.emit('interrupt:cancelled', interrupt);
|
|
400
|
-
}
|
|
401
|
-
this.activeInterrupts.clear();
|
|
402
|
-
// Cancel all queued
|
|
403
|
-
for (const interrupt of this.pendingQueue) {
|
|
404
|
-
interrupt.status = 'cancelled';
|
|
405
|
-
this.emit('interrupt:cancelled', interrupt);
|
|
406
|
-
}
|
|
407
|
-
this.pendingQueue = [];
|
|
408
|
-
// Cancel all deferred
|
|
409
|
-
for (const interrupt of this.deferredInterrupts.values()) {
|
|
410
|
-
interrupt.status = 'cancelled';
|
|
411
|
-
this.emit('interrupt:cancelled', interrupt);
|
|
412
|
-
}
|
|
413
|
-
this.deferredInterrupts.clear();
|
|
414
|
-
this.emit('interrupt:cleared');
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Update interrupt policy
|
|
418
|
-
*/
|
|
419
|
-
updatePolicy(policy) {
|
|
420
|
-
this.policy = {
|
|
421
|
-
...this.policy,
|
|
422
|
-
...policy,
|
|
423
|
-
};
|
|
424
|
-
this.emit('policy:updated', this.policy);
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Dispose of the manager
|
|
428
|
-
*/
|
|
429
|
-
dispose() {
|
|
430
|
-
this.clearAll();
|
|
431
|
-
this.removeAllListeners();
|
|
432
|
-
if (this.transitionTimer) {
|
|
433
|
-
clearTimeout(this.transitionTimer);
|
|
434
|
-
this.transitionTimer = null;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
package/dist/bin/ui/layout.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { theme } from './theme.js';
|
|
2
|
-
import { isPlainOutputMode } from './outputMode.js';
|
|
3
|
-
const MIN_WIDTH = 42;
|
|
4
|
-
const MAX_WIDTH = 110;
|
|
5
|
-
const ANSI_REGEX = /\u001B\[[0-9;]*m/g;
|
|
6
|
-
export function getTerminalColumns(defaultWidth = 80) {
|
|
7
|
-
if (typeof process.stdout.columns === 'number' &&
|
|
8
|
-
Number.isFinite(process.stdout.columns) &&
|
|
9
|
-
process.stdout.columns > 0) {
|
|
10
|
-
return process.stdout.columns;
|
|
11
|
-
}
|
|
12
|
-
return defaultWidth;
|
|
13
|
-
}
|
|
14
|
-
export function getContentWidth() {
|
|
15
|
-
const columns = getTerminalColumns();
|
|
16
|
-
const usable = typeof columns === 'number' && Number.isFinite(columns) ? columns - 6 : MAX_WIDTH;
|
|
17
|
-
return clampWidth(usable, columns);
|
|
18
|
-
}
|
|
19
|
-
export function wrapParagraph(text, width) {
|
|
20
|
-
const words = text.split(/\s+/).filter(Boolean);
|
|
21
|
-
if (!words.length) {
|
|
22
|
-
return [''];
|
|
23
|
-
}
|
|
24
|
-
const lines = [];
|
|
25
|
-
let current = words.shift();
|
|
26
|
-
for (const word of words) {
|
|
27
|
-
if (measure(`${current} ${word}`) > width) {
|
|
28
|
-
lines.push(current);
|
|
29
|
-
current = word;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
current += ` ${word}`;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
lines.push(current);
|
|
36
|
-
return lines;
|
|
37
|
-
}
|
|
38
|
-
export function wrapPreformatted(text, width) {
|
|
39
|
-
if (!text) {
|
|
40
|
-
return [''];
|
|
41
|
-
}
|
|
42
|
-
const result = [];
|
|
43
|
-
let remaining = text;
|
|
44
|
-
while (measure(remaining) > width) {
|
|
45
|
-
result.push(remaining.slice(0, width));
|
|
46
|
-
remaining = remaining.slice(width);
|
|
47
|
-
}
|
|
48
|
-
if (remaining) {
|
|
49
|
-
result.push(remaining);
|
|
50
|
-
}
|
|
51
|
-
return result.length ? result : [''];
|
|
52
|
-
}
|
|
53
|
-
export function normalizePanelWidth(width) {
|
|
54
|
-
if (typeof width === 'number' && Number.isFinite(width)) {
|
|
55
|
-
return clampWidth(width, getTerminalColumns());
|
|
56
|
-
}
|
|
57
|
-
return clampWidth(getContentWidth(), getTerminalColumns());
|
|
58
|
-
}
|
|
59
|
-
export function renderPanel(lines, options = {}) {
|
|
60
|
-
// Check if plain output mode is enabled for clipboard-friendly text
|
|
61
|
-
if (isPlainOutputMode()) {
|
|
62
|
-
return renderPlainPanel(lines, options);
|
|
63
|
-
}
|
|
64
|
-
const width = normalizePanelWidth(options.width);
|
|
65
|
-
const accent = options.accentColor ?? theme.primary;
|
|
66
|
-
const iconSegment = options.icon ? `${options.icon} ` : '';
|
|
67
|
-
const titleText = options.title ? `${iconSegment}${options.title}` : '';
|
|
68
|
-
const output = [];
|
|
69
|
-
// Add empty line for spacing
|
|
70
|
-
output.push('');
|
|
71
|
-
if (titleText) {
|
|
72
|
-
const paddedTitle = padLine(accent(truncate(titleText, width)), width);
|
|
73
|
-
output.push(paddedTitle);
|
|
74
|
-
output.push('');
|
|
75
|
-
}
|
|
76
|
-
if (!lines.length) {
|
|
77
|
-
lines = [''];
|
|
78
|
-
}
|
|
79
|
-
for (const line of lines) {
|
|
80
|
-
const padded = padLine(line, width);
|
|
81
|
-
output.push(padded);
|
|
82
|
-
}
|
|
83
|
-
// Add empty line for spacing
|
|
84
|
-
output.push('');
|
|
85
|
-
return output.join('\n');
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Renders a panel in plain text mode without box-drawing characters.
|
|
89
|
-
* Outputs clean text that's clipboard-friendly.
|
|
90
|
-
*/
|
|
91
|
-
function renderPlainPanel(lines, options = {}) {
|
|
92
|
-
const accent = options.accentColor ?? theme.primary;
|
|
93
|
-
const iconSegment = options.icon ? `${options.icon} ` : '';
|
|
94
|
-
const titleText = options.title ? `${iconSegment}${options.title}` : '';
|
|
95
|
-
const output = [];
|
|
96
|
-
if (titleText) {
|
|
97
|
-
output.push(`[${accent(titleText)}]`);
|
|
98
|
-
output.push('');
|
|
99
|
-
}
|
|
100
|
-
if (!lines.length) {
|
|
101
|
-
lines = [''];
|
|
102
|
-
}
|
|
103
|
-
for (const line of lines) {
|
|
104
|
-
output.push(line.trimEnd());
|
|
105
|
-
}
|
|
106
|
-
return output.join('\n');
|
|
107
|
-
}
|
|
108
|
-
export function measure(text) {
|
|
109
|
-
return stripAnsi(text).length;
|
|
110
|
-
}
|
|
111
|
-
export function stripAnsi(text) {
|
|
112
|
-
return text.replace(ANSI_REGEX, '');
|
|
113
|
-
}
|
|
114
|
-
function clampWidth(value, columns) {
|
|
115
|
-
const maxWidth = typeof columns === 'number' && Number.isFinite(columns) && columns > 0
|
|
116
|
-
? Math.max(10, Math.floor(columns - 6))
|
|
117
|
-
: MAX_WIDTH;
|
|
118
|
-
const minWidth = Math.min(MIN_WIDTH, maxWidth);
|
|
119
|
-
const normalized = Math.min(MAX_WIDTH, Math.floor(value));
|
|
120
|
-
return Math.max(minWidth, Math.min(normalized, maxWidth));
|
|
121
|
-
}
|
|
122
|
-
function padLine(text, width) {
|
|
123
|
-
const visible = measure(text);
|
|
124
|
-
if (visible === width) {
|
|
125
|
-
return text;
|
|
126
|
-
}
|
|
127
|
-
if (visible > width) {
|
|
128
|
-
return truncate(text, width);
|
|
129
|
-
}
|
|
130
|
-
return `${text}${' '.repeat(width - visible)}`;
|
|
131
|
-
}
|
|
132
|
-
function truncate(text, width) {
|
|
133
|
-
const visible = stripAnsi(text);
|
|
134
|
-
if (visible.length <= width) {
|
|
135
|
-
return text;
|
|
136
|
-
}
|
|
137
|
-
const truncated = visible.slice(0, Math.max(1, width - 1));
|
|
138
|
-
return `${truncated}…`;
|
|
139
|
-
}
|