erosolar-cli 1.5.1 → 1.5.3

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 (46) hide show
  1. package/dist/capabilities/cloudCapability.d.ts +13 -0
  2. package/dist/capabilities/cloudCapability.d.ts.map +1 -0
  3. package/dist/capabilities/cloudCapability.js +38 -0
  4. package/dist/capabilities/cloudCapability.js.map +1 -0
  5. package/dist/capabilities/index.d.ts +1 -0
  6. package/dist/capabilities/index.d.ts.map +1 -1
  7. package/dist/capabilities/index.js +1 -0
  8. package/dist/capabilities/index.js.map +1 -1
  9. package/dist/core/secretStore.d.ts +1 -1
  10. package/dist/core/secretStore.d.ts.map +1 -1
  11. package/dist/core/secretStore.js +49 -0
  12. package/dist/core/secretStore.js.map +1 -1
  13. package/dist/plugins/tools/cloud/cloudPlugin.d.ts +3 -0
  14. package/dist/plugins/tools/cloud/cloudPlugin.d.ts.map +1 -0
  15. package/dist/plugins/tools/cloud/cloudPlugin.js +14 -0
  16. package/dist/plugins/tools/cloud/cloudPlugin.js.map +1 -0
  17. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
  18. package/dist/plugins/tools/nodeDefaults.js +2 -0
  19. package/dist/plugins/tools/nodeDefaults.js.map +1 -1
  20. package/dist/security/persistence-analyzer.d.ts +56 -0
  21. package/dist/security/persistence-analyzer.d.ts.map +1 -0
  22. package/dist/security/persistence-analyzer.js +187 -0
  23. package/dist/security/persistence-analyzer.js.map +1 -0
  24. package/dist/security/persistence-research.d.ts +89 -0
  25. package/dist/security/persistence-research.d.ts.map +1 -0
  26. package/dist/security/persistence-research.js +361 -0
  27. package/dist/security/persistence-research.js.map +1 -0
  28. package/dist/shell/bracketedPasteManager.d.ts +43 -0
  29. package/dist/shell/bracketedPasteManager.d.ts.map +1 -1
  30. package/dist/shell/bracketedPasteManager.js +166 -9
  31. package/dist/shell/bracketedPasteManager.js.map +1 -1
  32. package/dist/shell/interactiveShell.d.ts +12 -0
  33. package/dist/shell/interactiveShell.d.ts.map +1 -1
  34. package/dist/shell/interactiveShell.js +47 -0
  35. package/dist/shell/interactiveShell.js.map +1 -1
  36. package/dist/tools/cloudTools.d.ts +46 -0
  37. package/dist/tools/cloudTools.d.ts.map +1 -0
  38. package/dist/tools/cloudTools.js +854 -0
  39. package/dist/tools/cloudTools.js.map +1 -0
  40. package/dist/tools/emailTools.d.ts.map +1 -1
  41. package/dist/tools/emailTools.js +11 -7
  42. package/dist/tools/emailTools.js.map +1 -1
  43. package/dist/tools/webTools.d.ts.map +1 -1
  44. package/dist/tools/webTools.js +7 -5
  45. package/dist/tools/webTools.js.map +1 -1
  46. package/package.json +1 -1
@@ -0,0 +1,361 @@
1
+ /**
2
+ * Persistence Research Toolkit
3
+ *
4
+ * Comprehensive analysis of persistence mechanisms across operating systems
5
+ * for legitimate security research and testing purposes.
6
+ *
7
+ * This module provides tools for:
8
+ * - Analyzing Windows persistence techniques
9
+ * - Analyzing Linux persistence techniques
10
+ * - Detecting persistence mechanisms
11
+ * - Generating test cases for security validation
12
+ */
13
+ /**
14
+ * Windows Persistence Techniques Database
15
+ */
16
+ export const WINDOWS_PERSISTENCE_TECHNIQUES = [
17
+ {
18
+ id: 'win-registry-run',
19
+ name: 'Registry Run Keys',
20
+ platform: 'windows',
21
+ mitreId: 'T1547.001',
22
+ description: 'Malware adds entries to registry run keys to execute on system startup',
23
+ detectionMethods: [
24
+ 'Monitor registry changes in HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run',
25
+ 'Monitor registry changes in HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run',
26
+ 'Check for suspicious executable paths in run keys'
27
+ ],
28
+ remediationSteps: [
29
+ 'Remove suspicious entries from registry run keys',
30
+ 'Scan for associated malware',
31
+ 'Monitor for registry modifications'
32
+ ],
33
+ riskLevel: 'high'
34
+ },
35
+ {
36
+ id: 'win-scheduled-tasks',
37
+ name: 'Scheduled Tasks',
38
+ platform: 'windows',
39
+ mitreId: 'T1053.005',
40
+ description: 'Creates scheduled tasks to execute malicious code at specific times or events',
41
+ detectionMethods: [
42
+ 'Review scheduled tasks using schtasks command',
43
+ 'Monitor Task Scheduler service events',
44
+ 'Check for tasks with suspicious actions or triggers'
45
+ ],
46
+ remediationSteps: [
47
+ 'Delete malicious scheduled tasks',
48
+ 'Monitor Task Scheduler service',
49
+ 'Implement application whitelisting'
50
+ ],
51
+ riskLevel: 'high'
52
+ },
53
+ {
54
+ id: 'win-services',
55
+ name: 'Windows Services',
56
+ platform: 'windows',
57
+ mitreId: 'T1543.003',
58
+ description: 'Creates or modifies Windows services to run malicious code',
59
+ detectionMethods: [
60
+ 'Review services using sc query or Get-Service',
61
+ 'Monitor service creation/modification events',
62
+ 'Check for services with suspicious image paths'
63
+ ],
64
+ remediationSteps: [
65
+ 'Stop and remove malicious services',
66
+ 'Monitor service creation events',
67
+ 'Implement service execution policies'
68
+ ],
69
+ riskLevel: 'critical'
70
+ },
71
+ {
72
+ id: 'win-dll-hijacking',
73
+ name: 'DLL Hijacking',
74
+ platform: 'windows',
75
+ mitreId: 'T1574.001',
76
+ description: 'Places malicious DLLs in application search paths to hijack legitimate processes',
77
+ detectionMethods: [
78
+ 'Monitor DLL loading from unusual locations',
79
+ 'Check for DLLs in application directories with weak permissions',
80
+ 'Use process monitoring tools'
81
+ ],
82
+ remediationSteps: [
83
+ 'Remove malicious DLLs',
84
+ 'Secure application directories',
85
+ 'Implement DLL search order hardening'
86
+ ],
87
+ riskLevel: 'medium'
88
+ },
89
+ {
90
+ id: 'win-wmi',
91
+ name: 'WMI Event Subscription',
92
+ platform: 'windows',
93
+ mitreId: 'T1546.003',
94
+ description: 'Uses WMI event subscriptions to trigger malicious code execution',
95
+ detectionMethods: [
96
+ 'Query WMI event subscriptions',
97
+ 'Monitor WMI event consumer creation',
98
+ 'Check for suspicious WMI filters and consumers'
99
+ ],
100
+ remediationSteps: [
101
+ 'Remove malicious WMI event subscriptions',
102
+ 'Monitor WMI activity',
103
+ 'Restrict WMI permissions'
104
+ ],
105
+ riskLevel: 'high'
106
+ }
107
+ ];
108
+ /**
109
+ * Linux Persistence Techniques Database
110
+ */
111
+ export const LINUX_PERSISTENCE_TECHNIQUES = [
112
+ {
113
+ id: 'linux-cron',
114
+ name: 'Cron Jobs',
115
+ platform: 'linux',
116
+ mitreId: 'T1053.003',
117
+ description: 'Adds malicious cron jobs to execute at scheduled intervals',
118
+ detectionMethods: [
119
+ 'Review crontab files for all users',
120
+ 'Monitor /etc/cron.* directories',
121
+ 'Check for cron jobs with suspicious commands'
122
+ ],
123
+ remediationSteps: [
124
+ 'Remove malicious cron entries',
125
+ 'Monitor cron job creation',
126
+ 'Implement cron access controls'
127
+ ],
128
+ riskLevel: 'high'
129
+ },
130
+ {
131
+ id: 'linux-systemd',
132
+ name: 'Systemd Services',
133
+ platform: 'linux',
134
+ mitreId: 'T1543.002',
135
+ description: 'Creates or modifies systemd services for persistence',
136
+ detectionMethods: [
137
+ 'Review systemd service files in /etc/systemd/system/',
138
+ 'Monitor service unit file creation',
139
+ 'Check for services with suspicious ExecStart commands'
140
+ ],
141
+ remediationSteps: [
142
+ 'Stop and remove malicious services',
143
+ 'Monitor systemd service creation',
144
+ 'Implement service validation'
145
+ ],
146
+ riskLevel: 'critical'
147
+ },
148
+ {
149
+ id: 'linux-ssh-keys',
150
+ name: 'SSH Authorized Keys',
151
+ platform: 'linux',
152
+ mitreId: 'T1098.004',
153
+ description: 'Adds backdoor SSH keys to authorized_keys files',
154
+ detectionMethods: [
155
+ 'Review ~/.ssh/authorized_keys files',
156
+ 'Monitor SSH key additions',
157
+ 'Check for unknown public keys'
158
+ ],
159
+ remediationSteps: [
160
+ 'Remove unauthorized SSH keys',
161
+ 'Monitor authorized_keys modifications',
162
+ 'Implement SSH key management'
163
+ ],
164
+ riskLevel: 'high'
165
+ },
166
+ {
167
+ id: 'linux-shell-config',
168
+ name: 'Shell Configuration Files',
169
+ platform: 'linux',
170
+ mitreId: 'T1546.004',
171
+ description: 'Modifies shell configuration files (.bashrc, .profile, etc.) to execute malicious code',
172
+ detectionMethods: [
173
+ 'Review shell configuration files',
174
+ 'Monitor modifications to .bashrc, .profile, etc.',
175
+ 'Check for suspicious commands in shell startup files'
176
+ ],
177
+ remediationSteps: [
178
+ 'Remove malicious shell configurations',
179
+ 'Monitor shell configuration changes',
180
+ 'Implement file integrity monitoring'
181
+ ],
182
+ riskLevel: 'medium'
183
+ },
184
+ {
185
+ id: 'linux-ld-so-preload',
186
+ name: 'LD_PRELOAD Hijacking',
187
+ platform: 'linux',
188
+ mitreId: 'T1574.006',
189
+ description: 'Uses LD_PRELOAD environment variable to load malicious libraries',
190
+ detectionMethods: [
191
+ 'Check LD_PRELOAD environment variable',
192
+ 'Monitor /etc/ld.so.preload file',
193
+ 'Review shell environment variables'
194
+ ],
195
+ remediationSteps: [
196
+ 'Remove malicious LD_PRELOAD settings',
197
+ 'Monitor environment variable changes',
198
+ 'Implement library validation'
199
+ ],
200
+ riskLevel: 'medium'
201
+ }
202
+ ];
203
+ /**
204
+ * Cross-platform Persistence Techniques
205
+ */
206
+ export const CROSS_PLATFORM_PERSISTENCE_TECHNIQUES = [
207
+ {
208
+ id: 'cross-browser-extensions',
209
+ name: 'Browser Extensions',
210
+ platform: 'cross-platform',
211
+ description: 'Installs malicious browser extensions for persistence',
212
+ detectionMethods: [
213
+ 'Review installed browser extensions',
214
+ 'Monitor extension installation events',
215
+ 'Check for suspicious extension permissions'
216
+ ],
217
+ remediationSteps: [
218
+ 'Remove malicious browser extensions',
219
+ 'Monitor extension installations',
220
+ 'Implement browser security policies'
221
+ ],
222
+ riskLevel: 'medium'
223
+ },
224
+ {
225
+ id: 'cross-startup-items',
226
+ name: 'Startup Items/Applications',
227
+ platform: 'cross-platform',
228
+ description: 'Adds items to user or system startup locations',
229
+ detectionMethods: [
230
+ 'Review startup directories and registry keys',
231
+ 'Monitor startup item creation',
232
+ 'Check for suspicious startup applications'
233
+ ],
234
+ remediationSteps: [
235
+ 'Remove malicious startup items',
236
+ 'Monitor startup locations',
237
+ 'Implement application whitelisting'
238
+ ],
239
+ riskLevel: 'high'
240
+ }
241
+ ];
242
+ /**
243
+ * Persistence Research Toolkit Class
244
+ */
245
+ export class PersistenceResearchToolkit {
246
+ allTechniques;
247
+ constructor() {
248
+ this.allTechniques = [
249
+ ...WINDOWS_PERSISTENCE_TECHNIQUES,
250
+ ...LINUX_PERSISTENCE_TECHNIQUES,
251
+ ...CROSS_PLATFORM_PERSISTENCE_TECHNIQUES
252
+ ];
253
+ }
254
+ /**
255
+ * Get all persistence techniques for a specific platform
256
+ */
257
+ getTechniquesByPlatform(platform) {
258
+ return this.allTechniques.filter(tech => tech.platform === platform || tech.platform === 'cross-platform');
259
+ }
260
+ /**
261
+ * Search techniques by MITRE ATT&CK ID
262
+ */
263
+ getTechniquesByMitreId(mitreId) {
264
+ return this.allTechniques.filter(tech => tech.mitreId === mitreId);
265
+ }
266
+ /**
267
+ * Generate detection rules for a specific technique
268
+ */
269
+ generateDetectionRules(techniqueId) {
270
+ const technique = this.allTechniques.find(t => t.id === techniqueId);
271
+ if (!technique) {
272
+ return ['Technique not found'];
273
+ }
274
+ const rules = [];
275
+ // Generate platform-specific detection rules
276
+ switch (technique.platform) {
277
+ case 'windows':
278
+ rules.push(...this.generateWindowsDetectionRules(technique));
279
+ break;
280
+ case 'linux':
281
+ rules.push(...this.generateLinuxDetectionRules(technique));
282
+ break;
283
+ default:
284
+ rules.push(...technique.detectionMethods);
285
+ }
286
+ return rules;
287
+ }
288
+ /**
289
+ * Generate Windows-specific detection rules
290
+ */
291
+ generateWindowsDetectionRules(technique) {
292
+ const rules = [];
293
+ switch (technique.id) {
294
+ case 'win-registry-run':
295
+ rules.push('Monitor registry key: HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', 'Monitor registry key: HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Run', 'Use Sysmon Event ID 13 (Registry value set) for monitoring', 'Check for executables in user temp directories or unusual locations');
296
+ break;
297
+ case 'win-scheduled-tasks':
298
+ rules.push('Monitor Task Scheduler events (Event ID 106, 140)', 'Use schtasks /query to list all tasks', 'Check for tasks with SYSTEM privileges', 'Monitor XML task files in C:\\Windows\\System32\\Tasks');
299
+ break;
300
+ case 'win-services':
301
+ rules.push('Monitor Service Control Manager events (Event ID 7045)', 'Use sc query to list services', 'Check for services with unusual image paths', 'Monitor service creation via WMI');
302
+ break;
303
+ default:
304
+ rules.push(...technique.detectionMethods);
305
+ }
306
+ return rules;
307
+ }
308
+ /**
309
+ * Generate Linux-specific detection rules
310
+ */
311
+ generateLinuxDetectionRules(technique) {
312
+ const rules = [];
313
+ switch (technique.id) {
314
+ case 'linux-cron':
315
+ rules.push('Monitor /var/spool/cron/crontabs/', 'Check /etc/crontab and /etc/cron.d/*', 'Use auditd to monitor cron job creation', 'Review system logs for cron execution');
316
+ break;
317
+ case 'linux-systemd':
318
+ rules.push('Monitor /etc/systemd/system/ directory', 'Use systemctl list-unit-files to check services', 'Check for services in /usr/lib/systemd/system/', 'Monitor journalctl for service activity');
319
+ break;
320
+ case 'linux-ssh-keys':
321
+ rules.push('Monitor ~/.ssh/authorized_keys file modifications', 'Check /etc/ssh/sshd_config for authorized keys settings', 'Use auditd to monitor SSH key additions', 'Review SSH authentication logs');
322
+ break;
323
+ default:
324
+ rules.push(...technique.detectionMethods);
325
+ }
326
+ return rules;
327
+ }
328
+ /**
329
+ * Generate test cases for security validation
330
+ */
331
+ generateTestCases(platform) {
332
+ const techniques = this.getTechniquesByPlatform(platform);
333
+ const testCases = [];
334
+ techniques.forEach(technique => {
335
+ testCases.push(`Test: ${technique.name} (${technique.mitreId || 'N/A'})`);
336
+ testCases.push(`- Description: ${technique.description}`);
337
+ testCases.push(`- Detection Methods: ${technique.detectionMethods.join(', ')}`);
338
+ testCases.push(`- Risk Level: ${technique.riskLevel}`);
339
+ testCases.push('');
340
+ });
341
+ return testCases;
342
+ }
343
+ /**
344
+ * Get remediation guidance for detected techniques
345
+ */
346
+ getRemediationGuidance(detectedTechniques) {
347
+ const guidance = [];
348
+ detectedTechniques.forEach(detected => {
349
+ guidance.push(`Technique: ${detected.technique.name}`);
350
+ guidance.push(`Confidence: ${detected.confidence}`);
351
+ guidance.push(`Location: ${detected.location}`);
352
+ guidance.push('Remediation Steps:');
353
+ detected.technique.remediationSteps.forEach(step => {
354
+ guidance.push(` - ${step}`);
355
+ });
356
+ guidance.push('');
357
+ });
358
+ return guidance;
359
+ }
360
+ }
361
+ //# sourceMappingURL=persistence-research.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence-research.js","sourceRoot":"","sources":["../../src/security/persistence-research.ts"],"names":[],"mappings":"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"}
@@ -9,16 +9,55 @@
9
9
  export interface BracketedPasteResult {
10
10
  handled: boolean;
11
11
  result?: string;
12
+ /** True if we're still accumulating paste content */
13
+ isPending?: boolean;
14
+ /** Number of lines accumulated so far (for display) */
15
+ lineCount?: number;
16
+ /** Preview of the content (first line truncated) */
17
+ preview?: string;
18
+ }
19
+ export interface MultiLinePasteState {
20
+ /** Full content accumulated from multi-line paste */
21
+ content: string;
22
+ /** Number of lines in the paste */
23
+ lineCount: number;
24
+ /** First line preview (truncated for display) */
25
+ firstLinePreview: string;
26
+ /** Last line preview (truncated for display) */
27
+ lastLinePreview: string;
12
28
  }
13
29
  export declare class BracketedPasteManager {
14
30
  private enabled;
15
31
  private inPaste;
16
32
  private pasteBuffer;
33
+ /** Tracks accumulated multi-line input even without bracketed paste support */
34
+ private multiLineBuffer;
35
+ private multiLineMode;
36
+ private lastInputTime;
37
+ /** Time threshold (ms) to consider rapid input as paste */
38
+ private readonly PASTE_THRESHOLD_MS;
17
39
  constructor(enabled: boolean);
18
40
  /**
19
41
  * Process input text, handling bracketed paste sequences
20
42
  */
21
43
  process(input: string): BracketedPasteResult;
44
+ /**
45
+ * Process input when bracketed paste is not enabled
46
+ * Uses timing heuristics to detect rapid multi-line input (likely paste)
47
+ */
48
+ private processWithoutBracketed;
49
+ /**
50
+ * Generate a preview string for multi-line content
51
+ */
52
+ private getPreview;
53
+ /**
54
+ * Get current multi-line state for display purposes
55
+ */
56
+ getMultiLineState(): MultiLinePasteState | null;
57
+ /**
58
+ * Format a multi-line paste as a collapsed block for display
59
+ */
60
+ static formatCollapsedBlock(content: string, maxPreviewLength?: number): string;
22
61
  /**
23
62
  * Check if currently processing a paste
24
63
  */
@@ -27,6 +66,10 @@ export declare class BracketedPasteManager {
27
66
  * Get the current paste buffer
28
67
  */
29
68
  getPasteBuffer(): string[];
69
+ /**
70
+ * Finalize any pending multi-line input
71
+ */
72
+ finalize(): string | null;
30
73
  /**
31
74
  * Reset the paste state
32
75
  */
@@ -1 +1 @@
1
- {"version":3,"file":"bracketedPasteManager.d.ts","sourceRoot":"","sources":["../../src/shell/bracketedPasteManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;gBAEvB,OAAO,EAAE,OAAO;IAI5B;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB;IAoE5C;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE;IAI1B;;OAEG;IACH,KAAK,IAAI,IAAI;CAId"}
1
+ {"version":3,"file":"bracketedPasteManager.d.ts","sourceRoot":"","sources":["../../src/shell/bracketedPasteManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,gBAAgB,EAAE,MAAM,CAAC;IACzB,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IAEnC,+EAA+E;IAC/E,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAK;IAC1B,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAM;gBAE7B,OAAO,EAAE,OAAO;IAI5B;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB;IA4G5C;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAqD/B;;OAEG;IACH,OAAO,CAAC,UAAU;IAiBlB;;OAEG;IACH,iBAAiB,IAAI,mBAAmB,GAAG,IAAI;IAmB/C;;OAEG;IACH,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,GAAE,MAAW,GAAG,MAAM;IAcnF;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE;IAI1B;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IAUzB;;OAEG;IACH,KAAK,IAAI,IAAI;CAMd"}
@@ -10,6 +10,12 @@ export class BracketedPasteManager {
10
10
  enabled;
11
11
  inPaste = false;
12
12
  pasteBuffer = [];
13
+ /** Tracks accumulated multi-line input even without bracketed paste support */
14
+ multiLineBuffer = [];
15
+ multiLineMode = false;
16
+ lastInputTime = 0;
17
+ /** Time threshold (ms) to consider rapid input as paste */
18
+ PASTE_THRESHOLD_MS = 50;
13
19
  constructor(enabled) {
14
20
  this.enabled = enabled;
15
21
  }
@@ -18,7 +24,7 @@ export class BracketedPasteManager {
18
24
  */
19
25
  process(input) {
20
26
  if (!this.enabled) {
21
- return { handled: false };
27
+ return this.processWithoutBracketed(input);
22
28
  }
23
29
  const startMarker = '\u001b[200~';
24
30
  const endMarker = '\u001b[201~';
@@ -31,6 +37,8 @@ export class BracketedPasteManager {
31
37
  const afterEnd = input.substring(endIndex + endMarker.length);
32
38
  this.pasteBuffer.push(beforeEnd);
33
39
  const result = this.pasteBuffer.join('\n');
40
+ const lineCount = this.pasteBuffer.length;
41
+ const preview = this.getPreview(this.pasteBuffer);
34
42
  // Reset state
35
43
  this.inPaste = false;
36
44
  this.pasteBuffer = [];
@@ -38,16 +46,36 @@ export class BracketedPasteManager {
38
46
  if (afterEnd) {
39
47
  const afterResult = this.process(afterEnd);
40
48
  if (afterResult.handled && afterResult.result !== undefined) {
41
- return { handled: true, result: result + afterResult.result };
49
+ return {
50
+ handled: true,
51
+ result: result + afterResult.result,
52
+ lineCount,
53
+ preview,
54
+ };
42
55
  }
43
- return { handled: true, result: result + afterEnd };
56
+ return {
57
+ handled: true,
58
+ result: result + afterEnd,
59
+ lineCount,
60
+ preview,
61
+ };
44
62
  }
45
- return { handled: true, result };
63
+ return {
64
+ handled: true,
65
+ result,
66
+ lineCount,
67
+ preview,
68
+ };
46
69
  }
47
70
  else {
48
71
  // Still in paste, no end marker found
49
72
  this.pasteBuffer.push(input);
50
- return { handled: true };
73
+ return {
74
+ handled: true,
75
+ isPending: true,
76
+ lineCount: this.pasteBuffer.length,
77
+ preview: this.getPreview(this.pasteBuffer),
78
+ };
51
79
  }
52
80
  }
53
81
  // Not in paste, look for start marker
@@ -63,25 +91,152 @@ export class BracketedPasteManager {
63
91
  if (afterStart) {
64
92
  const afterResult = this.process(afterStart);
65
93
  if (afterResult.handled && afterResult.result !== undefined) {
66
- return { handled: true, result: beforeStart + afterResult.result };
94
+ return {
95
+ handled: true,
96
+ result: beforeStart + afterResult.result,
97
+ lineCount: afterResult.lineCount,
98
+ preview: afterResult.preview,
99
+ };
67
100
  }
101
+ // Still pending
102
+ return {
103
+ handled: true,
104
+ result: beforeStart,
105
+ isPending: this.inPaste,
106
+ lineCount: this.pasteBuffer.length,
107
+ preview: this.getPreview(this.pasteBuffer),
108
+ };
68
109
  }
69
- return { handled: true, result: beforeStart };
110
+ return {
111
+ handled: true,
112
+ result: beforeStart,
113
+ isPending: true,
114
+ lineCount: 0,
115
+ };
70
116
  }
71
117
  // No paste markers found
72
118
  return { handled: false };
73
119
  }
120
+ /**
121
+ * Process input when bracketed paste is not enabled
122
+ * Uses timing heuristics to detect rapid multi-line input (likely paste)
123
+ */
124
+ processWithoutBracketed(input) {
125
+ const now = Date.now();
126
+ const timeSinceLastInput = now - this.lastInputTime;
127
+ this.lastInputTime = now;
128
+ // Check if this looks like part of a rapid paste
129
+ if (timeSinceLastInput < this.PASTE_THRESHOLD_MS && this.multiLineBuffer.length > 0) {
130
+ // Continue accumulating
131
+ this.multiLineBuffer.push(input);
132
+ this.multiLineMode = true;
133
+ return {
134
+ handled: true,
135
+ isPending: true,
136
+ lineCount: this.multiLineBuffer.length,
137
+ preview: this.getPreview(this.multiLineBuffer),
138
+ };
139
+ }
140
+ // If we were in multi-line mode and there's a pause, finalize
141
+ if (this.multiLineMode && this.multiLineBuffer.length > 0) {
142
+ this.multiLineBuffer.push(input);
143
+ const result = this.multiLineBuffer.join('\n');
144
+ const lineCount = this.multiLineBuffer.length;
145
+ const preview = this.getPreview(this.multiLineBuffer);
146
+ this.multiLineBuffer = [];
147
+ this.multiLineMode = false;
148
+ return {
149
+ handled: true,
150
+ result,
151
+ lineCount,
152
+ preview,
153
+ };
154
+ }
155
+ // Check for embedded newlines in a single input (indicates paste)
156
+ if (input.includes('\n')) {
157
+ const lines = input.split('\n');
158
+ return {
159
+ handled: true,
160
+ result: input,
161
+ lineCount: lines.length,
162
+ preview: this.getPreview(lines),
163
+ };
164
+ }
165
+ // Start tracking for potential multi-line paste
166
+ this.multiLineBuffer = [input];
167
+ return { handled: false };
168
+ }
169
+ /**
170
+ * Generate a preview string for multi-line content
171
+ */
172
+ getPreview(lines) {
173
+ if (lines.length === 0) {
174
+ return '';
175
+ }
176
+ const firstLine = lines[0] || '';
177
+ const truncatedFirst = firstLine.length > 50
178
+ ? firstLine.slice(0, 47) + '...'
179
+ : firstLine;
180
+ if (lines.length === 1) {
181
+ return truncatedFirst;
182
+ }
183
+ return `${truncatedFirst} [+${lines.length - 1} more lines]`;
184
+ }
185
+ /**
186
+ * Get current multi-line state for display purposes
187
+ */
188
+ getMultiLineState() {
189
+ const buffer = this.inPaste ? this.pasteBuffer :
190
+ this.multiLineMode ? this.multiLineBuffer : null;
191
+ if (!buffer || buffer.length === 0) {
192
+ return null;
193
+ }
194
+ const firstLine = buffer[0] || '';
195
+ const lastLine = buffer[buffer.length - 1] || '';
196
+ return {
197
+ content: buffer.join('\n'),
198
+ lineCount: buffer.length,
199
+ firstLinePreview: firstLine.length > 40 ? firstLine.slice(0, 37) + '...' : firstLine,
200
+ lastLinePreview: lastLine.length > 40 ? lastLine.slice(0, 37) + '...' : lastLine,
201
+ };
202
+ }
203
+ /**
204
+ * Format a multi-line paste as a collapsed block for display
205
+ */
206
+ static formatCollapsedBlock(content, maxPreviewLength = 60) {
207
+ const lines = content.split('\n');
208
+ if (lines.length <= 1) {
209
+ return content;
210
+ }
211
+ const firstLine = (lines[0] || '').trim();
212
+ const truncatedFirst = firstLine.length > maxPreviewLength
213
+ ? firstLine.slice(0, maxPreviewLength - 3) + '...'
214
+ : firstLine;
215
+ return `📋 ${truncatedFirst} [${lines.length} lines]`;
216
+ }
74
217
  /**
75
218
  * Check if currently processing a paste
76
219
  */
77
220
  isInPaste() {
78
- return this.inPaste;
221
+ return this.inPaste || this.multiLineMode;
79
222
  }
80
223
  /**
81
224
  * Get the current paste buffer
82
225
  */
83
226
  getPasteBuffer() {
84
- return [...this.pasteBuffer];
227
+ return this.inPaste ? [...this.pasteBuffer] : [...this.multiLineBuffer];
228
+ }
229
+ /**
230
+ * Finalize any pending multi-line input
231
+ */
232
+ finalize() {
233
+ if (this.multiLineMode && this.multiLineBuffer.length > 1) {
234
+ const result = this.multiLineBuffer.join('\n');
235
+ this.multiLineBuffer = [];
236
+ this.multiLineMode = false;
237
+ return result;
238
+ }
239
+ return null;
85
240
  }
86
241
  /**
87
242
  * Reset the paste state
@@ -89,6 +244,8 @@ export class BracketedPasteManager {
89
244
  reset() {
90
245
  this.inPaste = false;
91
246
  this.pasteBuffer = [];
247
+ this.multiLineMode = false;
248
+ this.multiLineBuffer = [];
92
249
  }
93
250
  }
94
251
  //# sourceMappingURL=bracketedPasteManager.js.map