coding-tool-x 3.4.11 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ const path = require('path');
3
3
  const os = require('os');
4
4
  const http = require('http');
5
5
  const https = require('https');
6
- const { execSync } = require('child_process');
6
+ const { execSync, execFileSync } = require('child_process');
7
7
  const { PATHS, NATIVE_PATHS } = require('../../config/paths');
8
8
  const { loadUIConfig, saveUIConfig } = require('./ui-config');
9
9
  const codexSettingsManager = require('./codex-settings-manager');
@@ -239,40 +239,198 @@ function escapeForXml(value) {
239
239
 
240
240
  function buildWindowsPopupCommand(title, message) {
241
241
  const script = [
242
+ "$ErrorActionPreference = 'Stop'",
243
+ `$titleText = '${escapeForPowerShellSingleQuote(title)}'`,
244
+ `$messageText = '${escapeForPowerShellSingleQuote(message)}'`,
245
+ "$segments = $messageText -split '\\s*\\|\\s*', 2",
246
+ "$headlineText = if ($segments.Length -ge 1) { $segments[0] } else { $messageText }",
247
+ "$detailText = if ($segments.Length -ge 2) { $segments[1] } else { '' }",
248
+ 'try {',
249
+ 'Add-Type -AssemblyName PresentationFramework',
250
+ 'Add-Type -AssemblyName PresentationCore',
251
+ 'Add-Type -AssemblyName WindowsBase',
252
+ '$brushConverter = New-Object System.Windows.Media.BrushConverter',
253
+ '$window = New-Object System.Windows.Window',
254
+ '$window.Width = 372',
255
+ '$window.Height = 118',
256
+ '$window.WindowStyle = [System.Windows.WindowStyle]::None',
257
+ '$window.ResizeMode = [System.Windows.ResizeMode]::NoResize',
258
+ '$window.AllowsTransparency = $true',
259
+ '$window.Background = [System.Windows.Media.Brushes]::Transparent',
260
+ '$window.ShowInTaskbar = $false',
261
+ '$window.Topmost = $true',
262
+ '$window.ShowActivated = $false',
263
+ '$window.Opacity = 0',
264
+ '$window.WindowStartupLocation = [System.Windows.WindowStartupLocation]::Manual',
265
+ '$root = New-Object System.Windows.Controls.Border',
266
+ '$root.CornerRadius = New-Object System.Windows.CornerRadius -ArgumentList 20',
267
+ '$root.Padding = New-Object System.Windows.Thickness -ArgumentList 16',
268
+ "$root.Background = $brushConverter.ConvertFromString('#F3F4F7')",
269
+ "$root.BorderBrush = $brushConverter.ConvertFromString('#D9DBE3')",
270
+ '$root.BorderThickness = New-Object System.Windows.Thickness -ArgumentList 1',
271
+ '$shadow = New-Object System.Windows.Media.Effects.DropShadowEffect',
272
+ "$shadow.Color = [System.Windows.Media.ColorConverter]::ConvertFromString('#22000000')",
273
+ '$shadow.BlurRadius = 26',
274
+ '$shadow.ShadowDepth = 0',
275
+ '$shadow.Opacity = 0.85',
276
+ '$root.Effect = $shadow',
277
+ '$grid = New-Object System.Windows.Controls.Grid',
278
+ '$iconColumn = New-Object System.Windows.Controls.ColumnDefinition',
279
+ '$iconColumn.Width = New-Object System.Windows.GridLength -ArgumentList 44',
280
+ '$contentColumn = New-Object System.Windows.Controls.ColumnDefinition',
281
+ '$grid.ColumnDefinitions.Add($iconColumn) | Out-Null',
282
+ '$grid.ColumnDefinitions.Add($contentColumn) | Out-Null',
283
+ '$iconHolder = New-Object System.Windows.Controls.Border',
284
+ '$iconHolder.Width = 34',
285
+ '$iconHolder.Height = 34',
286
+ '$iconHolder.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Left',
287
+ '$iconHolder.VerticalAlignment = [System.Windows.VerticalAlignment]::Top',
288
+ '$iconHolder.CornerRadius = New-Object System.Windows.CornerRadius -ArgumentList 17',
289
+ "$iconHolder.Background = $brushConverter.ConvertFromString('#DDEBFF')",
290
+ '$iconGlyph = New-Object System.Windows.Controls.TextBlock',
291
+ '$iconGlyph.Text = [char]0x2713',
292
+ '$iconGlyph.FontSize = 18',
293
+ '$iconGlyph.FontWeight = [System.Windows.FontWeights]::Bold',
294
+ "$iconGlyph.Foreground = $brushConverter.ConvertFromString('#0A84FF')",
295
+ '$iconGlyph.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Center',
296
+ '$iconGlyph.VerticalAlignment = [System.Windows.VerticalAlignment]::Center',
297
+ '$iconHolder.Child = $iconGlyph',
298
+ '$contentStack = New-Object System.Windows.Controls.StackPanel',
299
+ '$contentStack.Orientation = [System.Windows.Controls.Orientation]::Vertical',
300
+ '$contentStack.Margin = New-Object System.Windows.Thickness -ArgumentList 4,0,0,0',
301
+ '$metaGrid = New-Object System.Windows.Controls.Grid',
302
+ '$metaGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition)) | Out-Null',
303
+ '$timeColumn = New-Object System.Windows.Controls.ColumnDefinition',
304
+ '$timeColumn.Width = [System.Windows.GridLength]::Auto',
305
+ '$metaGrid.ColumnDefinitions.Add($timeColumn) | Out-Null',
306
+ '$appLabel = New-Object System.Windows.Controls.TextBlock',
307
+ '$appLabel.Text = $titleText',
308
+ '$appLabel.FontSize = 11.5',
309
+ '$appLabel.FontWeight = [System.Windows.FontWeights]::SemiBold',
310
+ "$appLabel.Foreground = $brushConverter.ConvertFromString('#6B6C73')",
311
+ '$appLabel.TextTrimming = [System.Windows.TextTrimming]::CharacterEllipsis',
312
+ '$stampLabel = New-Object System.Windows.Controls.TextBlock',
313
+ "$stampLabel.Text = '刚刚'",
314
+ '$stampLabel.FontSize = 11',
315
+ "$stampLabel.Foreground = $brushConverter.ConvertFromString('#8D8E95')",
316
+ '$stampLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 12,0,0,0',
317
+ '[System.Windows.Controls.Grid]::SetColumn($stampLabel, 1)',
318
+ '$metaGrid.Children.Add($appLabel) | Out-Null',
319
+ '$metaGrid.Children.Add($stampLabel) | Out-Null',
320
+ '$headlineLabel = New-Object System.Windows.Controls.TextBlock',
321
+ '$headlineLabel.Text = $headlineText',
322
+ '$headlineLabel.FontSize = 14',
323
+ '$headlineLabel.FontWeight = [System.Windows.FontWeights]::SemiBold',
324
+ "$headlineLabel.Foreground = $brushConverter.ConvertFromString('#1F2024')",
325
+ '$headlineLabel.TextWrapping = [System.Windows.TextWrapping]::Wrap',
326
+ '$headlineLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 0,6,0,0',
327
+ '$detailLabel = New-Object System.Windows.Controls.TextBlock',
328
+ '$detailLabel.Text = $detailText',
329
+ '$detailLabel.FontSize = 12',
330
+ "$detailLabel.Foreground = $brushConverter.ConvertFromString('#5F6168')",
331
+ '$detailLabel.TextWrapping = [System.Windows.TextWrapping]::Wrap',
332
+ '$detailLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 0,4,0,0',
333
+ '$detailLabel.Visibility = if ([string]::IsNullOrWhiteSpace($detailText)) { [System.Windows.Visibility]::Collapsed } else { [System.Windows.Visibility]::Visible }',
334
+ '$contentStack.Children.Add($metaGrid) | Out-Null',
335
+ '$contentStack.Children.Add($headlineLabel) | Out-Null',
336
+ '$contentStack.Children.Add($detailLabel) | Out-Null',
337
+ '[System.Windows.Controls.Grid]::SetColumn($contentStack, 1)',
338
+ '$grid.Children.Add($iconHolder) | Out-Null',
339
+ '$grid.Children.Add($contentStack) | Out-Null',
340
+ '$root.Child = $grid',
341
+ '$window.Content = $root',
342
+ '$workArea = [System.Windows.SystemParameters]::WorkArea',
343
+ '$window.Left = $workArea.Right - $window.Width - 18',
344
+ '$window.Top = $workArea.Top + 18',
345
+ '$frame = New-Object System.Windows.Threading.DispatcherFrame',
346
+ '$window.Add_Closed({ $frame.Continue = $false })',
347
+ '$closeTimer = New-Object System.Windows.Threading.DispatcherTimer',
348
+ '$closeTimer.Interval = [TimeSpan]::FromMilliseconds(4600)',
349
+ '$closeTimer.Add_Tick({',
350
+ ' $closeTimer.Stop()',
351
+ ' $fadeOut = New-Object System.Windows.Media.Animation.DoubleAnimation',
352
+ ' $fadeOut.From = $window.Opacity',
353
+ ' $fadeOut.To = 0',
354
+ ' $fadeOut.Duration = [TimeSpan]::FromMilliseconds(220)',
355
+ ' $fadeOut.Add_Completed({ $window.Close() })',
356
+ ' $window.BeginAnimation([System.Windows.Window]::OpacityProperty, $fadeOut)',
357
+ '})',
358
+ '$window.Show()',
359
+ '$fadeIn = New-Object System.Windows.Media.Animation.DoubleAnimation',
360
+ '$fadeIn.From = 0',
361
+ '$fadeIn.To = 1',
362
+ '$fadeIn.Duration = [TimeSpan]::FromMilliseconds(180)',
363
+ '$window.BeginAnimation([System.Windows.Window]::OpacityProperty, $fadeIn)',
364
+ '$closeTimer.Start()',
365
+ '[System.Windows.Threading.Dispatcher]::PushFrame($frame)',
366
+ '} catch {',
242
367
  'Add-Type -AssemblyName System.Windows.Forms',
243
368
  'Add-Type -AssemblyName System.Drawing',
244
369
  '$form = New-Object System.Windows.Forms.Form',
245
- `$form.Text = '${escapeForPowerShellSingleQuote(title)}'`,
370
+ '$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None',
371
+ '$form.BackColor = [System.Drawing.Color]::FromArgb(247, 247, 250)',
246
372
  '$form.Width = 360',
247
- '$form.Height = 120',
373
+ '$form.Height = 118',
248
374
  '$form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual',
249
- '$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedToolWindow',
250
375
  '$form.ShowInTaskbar = $false',
251
376
  '$form.TopMost = $true',
252
377
  '$form.MaximizeBox = $false',
253
378
  '$form.MinimizeBox = $false',
254
379
  '$workingArea = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',
255
- '$form.Location = New-Object System.Drawing.Point(($workingArea.Right - $form.Width - 16), ($workingArea.Top + 16))',
380
+ '$form.Location = New-Object System.Drawing.Point(($workingArea.Right - $form.Width - 18), ($workingArea.Top + 18))',
381
+ '$iconPanel = New-Object System.Windows.Forms.Panel',
382
+ '$iconPanel.Width = 34',
383
+ '$iconPanel.Height = 34',
384
+ '$iconPanel.BackColor = [System.Drawing.Color]::FromArgb(221, 235, 255)',
385
+ '$iconPanel.Location = New-Object System.Drawing.Point(16, 18)',
386
+ '$iconLabel = New-Object System.Windows.Forms.Label',
387
+ '$iconLabel.Text = [char]0x2713',
388
+ "$iconLabel.Font = New-Object System.Drawing.Font('Segoe UI', 14, [System.Drawing.FontStyle]::Bold)",
389
+ '$iconLabel.ForeColor = [System.Drawing.Color]::FromArgb(10, 132, 255)',
390
+ '$iconLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter',
391
+ '$iconLabel.Dock = [System.Windows.Forms.DockStyle]::Fill',
392
+ '$iconPanel.Controls.Add($iconLabel)',
256
393
  '$titleLabel = New-Object System.Windows.Forms.Label',
257
- `$titleLabel.Text = '${escapeForPowerShellSingleQuote(title)}'`,
258
- "$titleLabel.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)",
394
+ '$titleLabel.Text = $titleText',
395
+ "$titleLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9, [System.Drawing.FontStyle]::Bold)",
396
+ '$titleLabel.ForeColor = [System.Drawing.Color]::FromArgb(109, 110, 115)',
259
397
  '$titleLabel.AutoSize = $true',
260
- '$titleLabel.Location = New-Object System.Drawing.Point(14, 12)',
261
- '$messageLabel = New-Object System.Windows.Forms.Label',
262
- `$messageLabel.Text = '${escapeForPowerShellSingleQuote(message)}'`,
263
- "$messageLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9)",
264
- '$messageLabel.MaximumSize = New-Object System.Drawing.Size(332, 0)',
265
- '$messageLabel.AutoSize = $true',
266
- '$messageLabel.Location = New-Object System.Drawing.Point(14, 40)',
398
+ '$titleLabel.Location = New-Object System.Drawing.Point(60, 16)',
399
+ '$headlineLabel = New-Object System.Windows.Forms.Label',
400
+ '$headlineLabel.Text = $headlineText',
401
+ "$headlineLabel.Font = New-Object System.Drawing.Font('Segoe UI', 10.5, [System.Drawing.FontStyle]::Bold)",
402
+ '$headlineLabel.ForeColor = [System.Drawing.Color]::FromArgb(31, 32, 36)',
403
+ '$headlineLabel.MaximumSize = New-Object System.Drawing.Size(272, 0)',
404
+ '$headlineLabel.AutoSize = $true',
405
+ '$headlineLabel.Location = New-Object System.Drawing.Point(60, 36)',
406
+ '$detailLabel = New-Object System.Windows.Forms.Label',
407
+ '$detailLabel.Text = $detailText',
408
+ "$detailLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9)",
409
+ '$detailLabel.ForeColor = [System.Drawing.Color]::FromArgb(95, 97, 104)',
410
+ '$detailLabel.MaximumSize = New-Object System.Drawing.Size(272, 0)',
411
+ '$detailLabel.AutoSize = $true',
412
+ '$detailLabel.Location = New-Object System.Drawing.Point(60, 60)',
413
+ '$detailLabel.Visible = -not [string]::IsNullOrWhiteSpace($detailText)',
414
+ '$form.Controls.Add($iconPanel)',
267
415
  '$form.Controls.Add($titleLabel)',
268
- '$form.Controls.Add($messageLabel)',
416
+ '$form.Controls.Add($headlineLabel)',
417
+ '$form.Controls.Add($detailLabel)',
269
418
  '$timer = New-Object System.Windows.Forms.Timer',
270
- '$timer.Interval = 5000',
419
+ '$timer.Interval = 4800',
271
420
  '$timer.Add_Tick({ $timer.Stop(); $form.Close() })',
272
421
  '$timer.Start()',
273
- '[void]$form.ShowDialog()'
422
+ '[void]$form.ShowDialog()',
423
+ '}'
274
424
  ].join('; ');
275
- return `powershell -NoProfile -Command ${JSON.stringify(script)}`;
425
+ return script;
426
+ }
427
+
428
+ function runWindowsPowerShellCommand(command) {
429
+ // Invoke PowerShell directly so the styled popup script doesn't hit cmd.exe's 8191-char limit.
430
+ execFileSync('powershell', ['-NoProfile', '-STA', '-Command', command], {
431
+ stdio: 'ignore',
432
+ windowsHide: true
433
+ });
276
434
  }
277
435
 
278
436
  function generateNotifyScript(feishu = {}) {
@@ -284,7 +442,7 @@ const fs = require('fs')
284
442
  const os = require('os')
285
443
  const http = require('http')
286
444
  const https = require('https')
287
- const { execSync } = require('child_process')
445
+ const { execSync, execFileSync } = require('child_process')
288
446
 
289
447
  const FEISHU_ENABLED = ${feishuEnabled ? 'true' : 'false'}
290
448
  const FEISHU_WEBHOOK_URL = ${JSON.stringify(feishuEnabled ? feishu.webhookUrl : '')}
@@ -379,10 +537,13 @@ function notify(mode, message) {
379
537
  const ps = "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('" +
380
538
  escapeForPowerShellSingleQuote(message) + "', '" +
381
539
  escapeForPowerShellSingleQuote(title) + "', 'OK', 'Information')"
382
- const command = 'powershell -NoProfile -Command ' + JSON.stringify(ps) + ' || ' + popupCommand
383
- execSync(command, { stdio: 'ignore', windowsHide: true })
540
+ try {
541
+ runWindowsPowerShellCommand(ps)
542
+ } catch (dialogError) {
543
+ runWindowsPowerShellCommand(popupCommand)
544
+ }
384
545
  } else {
385
- execSync(popupCommand, { stdio: 'ignore', windowsHide: true })
546
+ runWindowsPowerShellCommand(popupCommand)
386
547
  }
387
548
  return
388
549
  }
@@ -499,40 +660,198 @@ function escapeForXml(value) {
499
660
 
500
661
  function buildWindowsPopupCommand(title, message) {
501
662
  const script = [
663
+ "$ErrorActionPreference = 'Stop'",
664
+ \`$titleText = '\${escapeForPowerShellSingleQuote(title)}'\`,
665
+ \`$messageText = '\${escapeForPowerShellSingleQuote(message)}'\`,
666
+ "$segments = $messageText -split '\\\\s*\\\\|\\\\s*', 2",
667
+ "$headlineText = if ($segments.Length -ge 1) { $segments[0] } else { $messageText }",
668
+ "$detailText = if ($segments.Length -ge 2) { $segments[1] } else { '' }",
669
+ 'try {',
670
+ 'Add-Type -AssemblyName PresentationFramework',
671
+ 'Add-Type -AssemblyName PresentationCore',
672
+ 'Add-Type -AssemblyName WindowsBase',
673
+ '$brushConverter = New-Object System.Windows.Media.BrushConverter',
674
+ '$window = New-Object System.Windows.Window',
675
+ '$window.Width = 372',
676
+ '$window.Height = 118',
677
+ '$window.WindowStyle = [System.Windows.WindowStyle]::None',
678
+ '$window.ResizeMode = [System.Windows.ResizeMode]::NoResize',
679
+ '$window.AllowsTransparency = $true',
680
+ '$window.Background = [System.Windows.Media.Brushes]::Transparent',
681
+ '$window.ShowInTaskbar = $false',
682
+ '$window.Topmost = $true',
683
+ '$window.ShowActivated = $false',
684
+ '$window.Opacity = 0',
685
+ '$window.WindowStartupLocation = [System.Windows.WindowStartupLocation]::Manual',
686
+ '$root = New-Object System.Windows.Controls.Border',
687
+ '$root.CornerRadius = New-Object System.Windows.CornerRadius -ArgumentList 20',
688
+ '$root.Padding = New-Object System.Windows.Thickness -ArgumentList 16',
689
+ "$root.Background = $brushConverter.ConvertFromString('#F3F4F7')",
690
+ "$root.BorderBrush = $brushConverter.ConvertFromString('#D9DBE3')",
691
+ '$root.BorderThickness = New-Object System.Windows.Thickness -ArgumentList 1',
692
+ '$shadow = New-Object System.Windows.Media.Effects.DropShadowEffect',
693
+ "$shadow.Color = [System.Windows.Media.ColorConverter]::ConvertFromString('#22000000')",
694
+ '$shadow.BlurRadius = 26',
695
+ '$shadow.ShadowDepth = 0',
696
+ '$shadow.Opacity = 0.85',
697
+ '$root.Effect = $shadow',
698
+ '$grid = New-Object System.Windows.Controls.Grid',
699
+ '$iconColumn = New-Object System.Windows.Controls.ColumnDefinition',
700
+ '$iconColumn.Width = New-Object System.Windows.GridLength -ArgumentList 44',
701
+ '$contentColumn = New-Object System.Windows.Controls.ColumnDefinition',
702
+ '$grid.ColumnDefinitions.Add($iconColumn) | Out-Null',
703
+ '$grid.ColumnDefinitions.Add($contentColumn) | Out-Null',
704
+ '$iconHolder = New-Object System.Windows.Controls.Border',
705
+ '$iconHolder.Width = 34',
706
+ '$iconHolder.Height = 34',
707
+ '$iconHolder.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Left',
708
+ '$iconHolder.VerticalAlignment = [System.Windows.VerticalAlignment]::Top',
709
+ '$iconHolder.CornerRadius = New-Object System.Windows.CornerRadius -ArgumentList 17',
710
+ "$iconHolder.Background = $brushConverter.ConvertFromString('#DDEBFF')",
711
+ '$iconGlyph = New-Object System.Windows.Controls.TextBlock',
712
+ '$iconGlyph.Text = [char]0x2713',
713
+ '$iconGlyph.FontSize = 18',
714
+ '$iconGlyph.FontWeight = [System.Windows.FontWeights]::Bold',
715
+ "$iconGlyph.Foreground = $brushConverter.ConvertFromString('#0A84FF')",
716
+ '$iconGlyph.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Center',
717
+ '$iconGlyph.VerticalAlignment = [System.Windows.VerticalAlignment]::Center',
718
+ '$iconHolder.Child = $iconGlyph',
719
+ '$contentStack = New-Object System.Windows.Controls.StackPanel',
720
+ '$contentStack.Orientation = [System.Windows.Controls.Orientation]::Vertical',
721
+ '$contentStack.Margin = New-Object System.Windows.Thickness -ArgumentList 4,0,0,0',
722
+ '$metaGrid = New-Object System.Windows.Controls.Grid',
723
+ '$metaGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition)) | Out-Null',
724
+ '$timeColumn = New-Object System.Windows.Controls.ColumnDefinition',
725
+ '$timeColumn.Width = [System.Windows.GridLength]::Auto',
726
+ '$metaGrid.ColumnDefinitions.Add($timeColumn) | Out-Null',
727
+ '$appLabel = New-Object System.Windows.Controls.TextBlock',
728
+ '$appLabel.Text = $titleText',
729
+ '$appLabel.FontSize = 11.5',
730
+ '$appLabel.FontWeight = [System.Windows.FontWeights]::SemiBold',
731
+ "$appLabel.Foreground = $brushConverter.ConvertFromString('#6B6C73')",
732
+ '$appLabel.TextTrimming = [System.Windows.TextTrimming]::CharacterEllipsis',
733
+ '$stampLabel = New-Object System.Windows.Controls.TextBlock',
734
+ "$stampLabel.Text = '刚刚'",
735
+ '$stampLabel.FontSize = 11',
736
+ "$stampLabel.Foreground = $brushConverter.ConvertFromString('#8D8E95')",
737
+ '$stampLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 12,0,0,0',
738
+ '[System.Windows.Controls.Grid]::SetColumn($stampLabel, 1)',
739
+ '$metaGrid.Children.Add($appLabel) | Out-Null',
740
+ '$metaGrid.Children.Add($stampLabel) | Out-Null',
741
+ '$headlineLabel = New-Object System.Windows.Controls.TextBlock',
742
+ '$headlineLabel.Text = $headlineText',
743
+ '$headlineLabel.FontSize = 14',
744
+ '$headlineLabel.FontWeight = [System.Windows.FontWeights]::SemiBold',
745
+ "$headlineLabel.Foreground = $brushConverter.ConvertFromString('#1F2024')",
746
+ '$headlineLabel.TextWrapping = [System.Windows.TextWrapping]::Wrap',
747
+ '$headlineLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 0,6,0,0',
748
+ '$detailLabel = New-Object System.Windows.Controls.TextBlock',
749
+ '$detailLabel.Text = $detailText',
750
+ '$detailLabel.FontSize = 12',
751
+ "$detailLabel.Foreground = $brushConverter.ConvertFromString('#5F6168')",
752
+ '$detailLabel.TextWrapping = [System.Windows.TextWrapping]::Wrap',
753
+ '$detailLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 0,4,0,0',
754
+ '$detailLabel.Visibility = if ([string]::IsNullOrWhiteSpace($detailText)) { [System.Windows.Visibility]::Collapsed } else { [System.Windows.Visibility]::Visible }',
755
+ '$contentStack.Children.Add($metaGrid) | Out-Null',
756
+ '$contentStack.Children.Add($headlineLabel) | Out-Null',
757
+ '$contentStack.Children.Add($detailLabel) | Out-Null',
758
+ '[System.Windows.Controls.Grid]::SetColumn($contentStack, 1)',
759
+ '$grid.Children.Add($iconHolder) | Out-Null',
760
+ '$grid.Children.Add($contentStack) | Out-Null',
761
+ '$root.Child = $grid',
762
+ '$window.Content = $root',
763
+ '$workArea = [System.Windows.SystemParameters]::WorkArea',
764
+ '$window.Left = $workArea.Right - $window.Width - 18',
765
+ '$window.Top = $workArea.Top + 18',
766
+ '$frame = New-Object System.Windows.Threading.DispatcherFrame',
767
+ '$window.Add_Closed({ $frame.Continue = $false })',
768
+ '$closeTimer = New-Object System.Windows.Threading.DispatcherTimer',
769
+ '$closeTimer.Interval = [TimeSpan]::FromMilliseconds(4600)',
770
+ '$closeTimer.Add_Tick({',
771
+ ' $closeTimer.Stop()',
772
+ ' $fadeOut = New-Object System.Windows.Media.Animation.DoubleAnimation',
773
+ ' $fadeOut.From = $window.Opacity',
774
+ ' $fadeOut.To = 0',
775
+ ' $fadeOut.Duration = [TimeSpan]::FromMilliseconds(220)',
776
+ ' $fadeOut.Add_Completed({ $window.Close() })',
777
+ ' $window.BeginAnimation([System.Windows.Window]::OpacityProperty, $fadeOut)',
778
+ '})',
779
+ '$window.Show()',
780
+ '$fadeIn = New-Object System.Windows.Media.Animation.DoubleAnimation',
781
+ '$fadeIn.From = 0',
782
+ '$fadeIn.To = 1',
783
+ '$fadeIn.Duration = [TimeSpan]::FromMilliseconds(180)',
784
+ '$window.BeginAnimation([System.Windows.Window]::OpacityProperty, $fadeIn)',
785
+ '$closeTimer.Start()',
786
+ '[System.Windows.Threading.Dispatcher]::PushFrame($frame)',
787
+ '} catch {',
502
788
  'Add-Type -AssemblyName System.Windows.Forms',
503
789
  'Add-Type -AssemblyName System.Drawing',
504
790
  '$form = New-Object System.Windows.Forms.Form',
505
- \`$form.Text = '\${escapeForPowerShellSingleQuote(title)}'\`,
791
+ '$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None',
792
+ '$form.BackColor = [System.Drawing.Color]::FromArgb(247, 247, 250)',
506
793
  '$form.Width = 360',
507
- '$form.Height = 120',
794
+ '$form.Height = 118',
508
795
  '$form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual',
509
- '$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedToolWindow',
510
796
  '$form.ShowInTaskbar = $false',
511
797
  '$form.TopMost = $true',
512
798
  '$form.MaximizeBox = $false',
513
799
  '$form.MinimizeBox = $false',
514
800
  '$workingArea = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',
515
- '$form.Location = New-Object System.Drawing.Point(($workingArea.Right - $form.Width - 16), ($workingArea.Top + 16))',
801
+ '$form.Location = New-Object System.Drawing.Point(($workingArea.Right - $form.Width - 18), ($workingArea.Top + 18))',
802
+ '$iconPanel = New-Object System.Windows.Forms.Panel',
803
+ '$iconPanel.Width = 34',
804
+ '$iconPanel.Height = 34',
805
+ '$iconPanel.BackColor = [System.Drawing.Color]::FromArgb(221, 235, 255)',
806
+ '$iconPanel.Location = New-Object System.Drawing.Point(16, 18)',
807
+ '$iconLabel = New-Object System.Windows.Forms.Label',
808
+ '$iconLabel.Text = [char]0x2713',
809
+ "$iconLabel.Font = New-Object System.Drawing.Font('Segoe UI', 14, [System.Drawing.FontStyle]::Bold)",
810
+ '$iconLabel.ForeColor = [System.Drawing.Color]::FromArgb(10, 132, 255)',
811
+ '$iconLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter',
812
+ '$iconLabel.Dock = [System.Windows.Forms.DockStyle]::Fill',
813
+ '$iconPanel.Controls.Add($iconLabel)',
516
814
  '$titleLabel = New-Object System.Windows.Forms.Label',
517
- \`$titleLabel.Text = '\${escapeForPowerShellSingleQuote(title)}'\`,
518
- " $titleLabel.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)".trim(),
815
+ '$titleLabel.Text = $titleText',
816
+ "$titleLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9, [System.Drawing.FontStyle]::Bold)",
817
+ '$titleLabel.ForeColor = [System.Drawing.Color]::FromArgb(109, 110, 115)',
519
818
  '$titleLabel.AutoSize = $true',
520
- '$titleLabel.Location = New-Object System.Drawing.Point(14, 12)',
521
- '$messageLabel = New-Object System.Windows.Forms.Label',
522
- \`$messageLabel.Text = '\${escapeForPowerShellSingleQuote(message)}'\`,
523
- " $messageLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9)".trim(),
524
- '$messageLabel.MaximumSize = New-Object System.Drawing.Size(332, 0)',
525
- '$messageLabel.AutoSize = $true',
526
- '$messageLabel.Location = New-Object System.Drawing.Point(14, 40)',
819
+ '$titleLabel.Location = New-Object System.Drawing.Point(60, 16)',
820
+ '$headlineLabel = New-Object System.Windows.Forms.Label',
821
+ '$headlineLabel.Text = $headlineText',
822
+ "$headlineLabel.Font = New-Object System.Drawing.Font('Segoe UI', 10.5, [System.Drawing.FontStyle]::Bold)",
823
+ '$headlineLabel.ForeColor = [System.Drawing.Color]::FromArgb(31, 32, 36)',
824
+ '$headlineLabel.MaximumSize = New-Object System.Drawing.Size(272, 0)',
825
+ '$headlineLabel.AutoSize = $true',
826
+ '$headlineLabel.Location = New-Object System.Drawing.Point(60, 36)',
827
+ '$detailLabel = New-Object System.Windows.Forms.Label',
828
+ '$detailLabel.Text = $detailText',
829
+ "$detailLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9)",
830
+ '$detailLabel.ForeColor = [System.Drawing.Color]::FromArgb(95, 97, 104)',
831
+ '$detailLabel.MaximumSize = New-Object System.Drawing.Size(272, 0)',
832
+ '$detailLabel.AutoSize = $true',
833
+ '$detailLabel.Location = New-Object System.Drawing.Point(60, 60)',
834
+ '$detailLabel.Visible = -not [string]::IsNullOrWhiteSpace($detailText)',
835
+ '$form.Controls.Add($iconPanel)',
527
836
  '$form.Controls.Add($titleLabel)',
528
- '$form.Controls.Add($messageLabel)',
837
+ '$form.Controls.Add($headlineLabel)',
838
+ '$form.Controls.Add($detailLabel)',
529
839
  '$timer = New-Object System.Windows.Forms.Timer',
530
- '$timer.Interval = 5000',
840
+ '$timer.Interval = 4800',
531
841
  '$timer.Add_Tick({ $timer.Stop(); $form.Close() })',
532
842
  '$timer.Start()',
533
- '[void]$form.ShowDialog()'
843
+ '[void]$form.ShowDialog()',
844
+ '}'
534
845
  ].join('; ')
535
- return 'powershell -NoProfile -Command ' + JSON.stringify(script)
846
+ return script
847
+ }
848
+
849
+ function runWindowsPowerShellCommand(command) {
850
+ // Invoke PowerShell directly so the styled popup script doesn't hit cmd.exe's 8191-char limit.
851
+ execFileSync('powershell', ['-NoProfile', '-STA', '-Command', command], {
852
+ stdio: 'ignore',
853
+ windowsHide: true
854
+ })
536
855
  }
537
856
  `;
538
857
  }
@@ -900,6 +1219,205 @@ function saveNotificationSettings(input = {}) {
900
1219
  return getNotificationSettings();
901
1220
  }
902
1221
 
1222
+ function parseNotifyTypeMarker(command) {
1223
+ const marker = String(command || '').match(/--cc-notify-type=(['"])?(dialog|notification)\1/i);
1224
+ return marker?.[2] ? normalizeType(marker[2].toLowerCase()) : null;
1225
+ }
1226
+
1227
+ function getStopHookCommand(settings = {}) {
1228
+ const hooks = settings?.hooks?.Stop;
1229
+ if (!Array.isArray(hooks) || hooks.length === 0) {
1230
+ return '';
1231
+ }
1232
+
1233
+ let fallbackCommand = '';
1234
+ for (const group of hooks) {
1235
+ const groupHooks = Array.isArray(group?.hooks) ? group.hooks : [];
1236
+ for (const hook of groupHooks) {
1237
+ const command = String(hook?.command || '');
1238
+ if (!command) continue;
1239
+ if (!fallbackCommand) {
1240
+ fallbackCommand = command;
1241
+ }
1242
+ if (command.includes('notify-hook.js')) {
1243
+ return command;
1244
+ }
1245
+ }
1246
+ }
1247
+
1248
+ return fallbackCommand;
1249
+ }
1250
+
1251
+ function normalizePathForCompare(rawPath) {
1252
+ return String(rawPath || '').replace(/\\/g, '/');
1253
+ }
1254
+
1255
+ function shouldRepairStopHook(settings, expectedScriptPath = PATHS.notifyHook, fileExists = fs.existsSync) {
1256
+ const command = getStopHookCommand(settings);
1257
+ if (!command || !command.includes('notify-hook.js')) {
1258
+ return false;
1259
+ }
1260
+
1261
+ const normalizedCommand = normalizePathForCompare(command);
1262
+ const normalizedExpected = normalizePathForCompare(expectedScriptPath);
1263
+ if (!normalizedCommand.includes(normalizedExpected)) {
1264
+ return true;
1265
+ }
1266
+
1267
+ const markerType = parseNotifyTypeMarker(command);
1268
+ if (!markerType) {
1269
+ return true;
1270
+ }
1271
+
1272
+ return !fileExists(expectedScriptPath);
1273
+ }
1274
+
1275
+ function buildStopHookCommand(type) {
1276
+ return buildClaudeCommand(type);
1277
+ }
1278
+
1279
+ function parseStopHookStatus(settings = {}) {
1280
+ const stopGroups = Array.isArray(settings?.hooks?.Stop) ? settings.hooks.Stop : [];
1281
+ if (stopGroups.length === 0) {
1282
+ return { enabled: false, type: 'notification' };
1283
+ }
1284
+
1285
+ let sawNotificationLikeCommand = false;
1286
+ for (const group of stopGroups) {
1287
+ const groupHooks = Array.isArray(group?.hooks) ? group.hooks : [];
1288
+ for (const hook of groupHooks) {
1289
+ const command = String(hook?.command || '');
1290
+ if (!command) continue;
1291
+
1292
+ const markerType = parseNotifyTypeMarker(command) || parseManagedType(command);
1293
+ if (markerType) {
1294
+ return { enabled: true, type: markerType };
1295
+ }
1296
+
1297
+ const isDialog = command.includes('display dialog') ||
1298
+ command.includes('MessageBox') ||
1299
+ command.includes('zenity --info');
1300
+ if (isDialog) {
1301
+ return { enabled: true, type: 'dialog' };
1302
+ }
1303
+
1304
+ const isNotification = command.includes('display notification') ||
1305
+ command.includes('Popup') ||
1306
+ command.includes('GraphicsPath') ||
1307
+ command.includes('TransparencyKey') ||
1308
+ command.includes('FormBorderStyle]::None') ||
1309
+ command.includes('AllowsTransparency') ||
1310
+ command.includes('notify-send') ||
1311
+ command.includes('ToastNotificationManager') ||
1312
+ command.includes('CreateToastNotifier') ||
1313
+ command.includes('notify-hook.js');
1314
+ if (isNotification) {
1315
+ sawNotificationLikeCommand = true;
1316
+ }
1317
+ }
1318
+ }
1319
+
1320
+ return sawNotificationLikeCommand
1321
+ ? { enabled: true, type: 'notification' }
1322
+ : { enabled: false, type: 'notification' };
1323
+ }
1324
+
1325
+ function normalizeSavedPlatformStatus(platform = {}) {
1326
+ return {
1327
+ enabled: platform?.enabled === true,
1328
+ type: normalizeType(platform?.type)
1329
+ };
1330
+ }
1331
+
1332
+ function buildLegacyClaudeSaveInput(input = {}, currentSettings = getNotificationSettings()) {
1333
+ return {
1334
+ platforms: {
1335
+ claude: input.stopHook !== undefined
1336
+ ? normalizePlatformInput(input.stopHook)
1337
+ : { enabled: false, type: 'notification' },
1338
+ codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
1339
+ gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
1340
+ opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
1341
+ },
1342
+ feishu: input.feishu !== undefined
1343
+ ? {
1344
+ enabled: input.feishu?.enabled === true,
1345
+ webhookUrl: input.feishu?.webhookUrl || ''
1346
+ }
1347
+ : {
1348
+ enabled: currentSettings?.feishu?.enabled === true,
1349
+ webhookUrl: currentSettings?.feishu?.webhookUrl || ''
1350
+ }
1351
+ };
1352
+ }
1353
+
1354
+ function getLegacyClaudeHookSettings() {
1355
+ return {
1356
+ success: true,
1357
+ stopHook: parseStopHookStatus(readClaudeSettings()),
1358
+ feishu: getFeishuConfig(),
1359
+ platform: os.platform()
1360
+ };
1361
+ }
1362
+
1363
+ function saveLegacyClaudeHookSettings(input = {}) {
1364
+ const currentSettings = getNotificationSettings();
1365
+ saveNotificationSettings(buildLegacyClaudeSaveInput(input, currentSettings));
1366
+ return getLegacyClaudeHookSettings();
1367
+ }
1368
+
1369
+ function initDefaultHooks() {
1370
+ try {
1371
+ const uiConfig = loadUIConfig();
1372
+ if (uiConfig.claudeNotificationDisabledByUser === true) {
1373
+ console.log('[Claude Hooks] 用户已主动关闭通知,跳过自动初始化');
1374
+ return;
1375
+ }
1376
+
1377
+ const currentClaudeSettings = readClaudeSettings();
1378
+ const currentStatus = parseStopHookStatus(currentClaudeSettings);
1379
+
1380
+ if (currentStatus.enabled) {
1381
+ if (shouldRepairStopHook(currentClaudeSettings)) {
1382
+ const currentSettings = getNotificationSettings();
1383
+ saveNotificationSettings({
1384
+ platforms: {
1385
+ claude: { enabled: true, type: currentStatus.type || 'notification' },
1386
+ codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
1387
+ gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
1388
+ opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
1389
+ },
1390
+ feishu: {
1391
+ enabled: currentSettings?.feishu?.enabled === true,
1392
+ webhookUrl: currentSettings?.feishu?.webhookUrl || ''
1393
+ }
1394
+ });
1395
+ console.log('[Claude Hooks] 检测到旧版 Stop hook 路径,已自动修复');
1396
+ } else {
1397
+ console.log('[Claude Hooks] 已存在 Stop hook 配置,跳过初始化');
1398
+ }
1399
+ return;
1400
+ }
1401
+
1402
+ const currentSettings = getNotificationSettings();
1403
+ saveNotificationSettings({
1404
+ platforms: {
1405
+ claude: { enabled: true, type: 'notification' },
1406
+ codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
1407
+ gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
1408
+ opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
1409
+ },
1410
+ feishu: {
1411
+ enabled: currentSettings?.feishu?.enabled === true,
1412
+ webhookUrl: currentSettings?.feishu?.webhookUrl || ''
1413
+ }
1414
+ });
1415
+ console.log('[Claude Hooks] 已自动开启任务完成通知(右上角卡片)');
1416
+ } catch (error) {
1417
+ console.error('[Claude Hooks] 初始化默认配置失败:', error);
1418
+ }
1419
+ }
1420
+
903
1421
  function sendFeishuTest(webhookUrl) {
904
1422
  return new Promise((resolve, reject) => {
905
1423
  try {
@@ -965,7 +1483,7 @@ function generateSystemNotificationCommand(type, message, platformOverride = os.
965
1483
  if (platform === 'win32') {
966
1484
  const popupCommand = buildWindowsPopupCommand(title, message);
967
1485
  if (normalizedType === 'dialog') {
968
- return `powershell -NoProfile -Command "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('${escapeForPowerShellSingleQuote(message)}', '${escapeForPowerShellSingleQuote(title)}', 'OK', 'Information')" || ${popupCommand}`;
1486
+ return `powershell -NoProfile -STA -Command "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('${escapeForPowerShellSingleQuote(message)}', '${escapeForPowerShellSingleQuote(title)}', 'OK', 'Information')" || ${popupCommand}`;
969
1487
  }
970
1488
  return popupCommand;
971
1489
  }
@@ -977,19 +1495,89 @@ function generateSystemNotificationCommand(type, message, platformOverride = os.
977
1495
  return `notify-send "Coding Tool" "${String(message || '').replace(/"/g, '\\"')}"`;
978
1496
  }
979
1497
 
1498
+ function runSystemNotification(type, message, platformOverride = os.platform()) {
1499
+ const normalizedType = normalizeType(type);
1500
+ const title = 'Coding Tool';
1501
+ const platform = platformOverride;
1502
+
1503
+ if (platform === 'darwin') {
1504
+ if (normalizedType === 'dialog') {
1505
+ const appleScript = 'display dialog "' + escapeForAppleScript(message) +
1506
+ '" with title "' + escapeForAppleScript(title) +
1507
+ '" buttons {"好的"} default button 1 with icon note';
1508
+ execSync('osascript -e ' + JSON.stringify(appleScript), { stdio: 'ignore', windowsHide: true });
1509
+ } else {
1510
+ const fallbackScript = 'display notification "' + escapeForAppleScript(message) +
1511
+ '" with title "' + escapeForAppleScript(title) + '" sound name "Glass"';
1512
+ const command = 'if command -v terminal-notifier >/dev/null 2>&1; then ' +
1513
+ 'terminal-notifier -title ' + JSON.stringify(title) +
1514
+ ' -message ' + JSON.stringify(message) +
1515
+ ' -sound Glass -activate com.apple.Terminal; ' +
1516
+ 'else osascript -e ' + JSON.stringify(fallbackScript) + '; fi';
1517
+ execSync(command, { stdio: 'ignore', windowsHide: true });
1518
+ }
1519
+ return;
1520
+ }
1521
+
1522
+ if (platform === 'win32') {
1523
+ const popupCommand = buildWindowsPopupCommand(title, message);
1524
+ if (normalizedType === 'dialog') {
1525
+ const dialogScript = "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('" +
1526
+ escapeForPowerShellSingleQuote(message) + "', '" +
1527
+ escapeForPowerShellSingleQuote(title) + "', 'OK', 'Information')";
1528
+ try {
1529
+ runWindowsPowerShellCommand(dialogScript);
1530
+ } catch (dialogError) {
1531
+ runWindowsPowerShellCommand(popupCommand);
1532
+ }
1533
+ } else {
1534
+ runWindowsPowerShellCommand(popupCommand);
1535
+ }
1536
+ return;
1537
+ }
1538
+
1539
+ const escapedMessage = String(message || '').replace(/"/g, '\\"');
1540
+ if (normalizedType === 'dialog') {
1541
+ execSync(
1542
+ `zenity --info --title="Coding Tool" --text="${escapedMessage}" 2>/dev/null || notify-send "Coding Tool" "${escapedMessage}"`,
1543
+ { stdio: 'ignore', windowsHide: true }
1544
+ );
1545
+ return;
1546
+ }
1547
+
1548
+ execSync(`notify-send "Coding Tool" "${escapedMessage}"`, { stdio: 'ignore', windowsHide: true });
1549
+ }
1550
+
1551
+ function syncManagedNotificationAssets() {
1552
+ const settings = getNotificationSettings();
1553
+ const hasManagedPlatform = Object.values(settings?.platforms || {}).some((platform) => platform?.enabled === true);
1554
+
1555
+ if (hasManagedPlatform) {
1556
+ writeNotifyScript(settings.feishu || {});
1557
+ } else {
1558
+ removeNotifyScript();
1559
+ }
1560
+
1561
+ return settings;
1562
+ }
1563
+
980
1564
  function testNotification({ type, testFeishu, webhookUrl } = {}) {
981
1565
  if (testFeishu && webhookUrl) {
982
1566
  return sendFeishuTest(webhookUrl);
983
1567
  }
984
1568
 
985
- execSync(generateSystemNotificationCommand(type || 'notification', '这是一条测试通知'), { stdio: 'ignore', windowsHide: true });
1569
+ runSystemNotification(type || 'notification', '这是一条测试通知');
986
1570
  }
987
1571
 
988
1572
  module.exports = {
989
1573
  MANAGED_HOOK_NAME,
990
1574
  getNotificationSettings,
1575
+ getLegacyClaudeHookSettings,
991
1576
  saveNotificationSettings,
1577
+ saveLegacyClaudeHookSettings,
992
1578
  testNotification,
1579
+ initDefaultHooks,
1580
+ syncManagedNotificationAssets,
993
1581
  getOpenCodeManagedPluginPath,
994
1582
  buildOpenCodePluginContent,
995
1583
  buildCodexNotifyCommand,
@@ -999,6 +1587,7 @@ module.exports = {
999
1587
  applyClaudeDisablePreference,
1000
1588
  getManagedCommandType,
1001
1589
  parseManagedType,
1590
+ parseNotifyTypeMarker,
1002
1591
  getClaudeHookStatus,
1003
1592
  getCodexHookStatus,
1004
1593
  getGeminiHookStatus,
@@ -1009,10 +1598,13 @@ module.exports = {
1009
1598
  validateFeishuWebhookUrl,
1010
1599
  buildCodexNotifyCommand,
1011
1600
  buildGeminiCommand,
1601
+ buildStopHookCommand,
1012
1602
  buildClaudeCommand,
1013
1603
  buildOpenCodePluginContent,
1014
1604
  getOpenCodeManagedPluginPath,
1015
1605
  generateNotifyScript,
1016
- generateSystemNotificationCommand
1606
+ generateSystemNotificationCommand,
1607
+ parseStopHookStatus,
1608
+ shouldRepairStopHook
1017
1609
  }
1018
1610
  };