coding-tool-x 3.4.10 → 3.4.12
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/web/assets/{Analytics-0PgPv5qO.js → Analytics-Q_QFMM2p.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-pBGoYbCP.js → ConfigTemplates-Ca8C7VtV.js} +1 -1
- package/dist/web/assets/{Home-BRN882om.js → Home-ChIIT4Ew.js} +1 -1
- package/dist/web/assets/{PluginManager-am97Huts.js → PluginManager-C3w7p-sj.js} +1 -1
- package/dist/web/assets/{ProjectList-CXS9KJN1.js → ProjectList-BfJTDXDw.js} +1 -1
- package/dist/web/assets/{SessionList-BZyrzH7J.js → SessionList-a3EoL0hZ.js} +1 -1
- package/dist/web/assets/{SkillManager-p1CI0tYa.js → SkillManager-CohW5iqS.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CUPvLoba.js → WorkspaceManager-DxaKsaJK.js} +1 -1
- package/dist/web/assets/index-B02wDWNC.css +1 -0
- package/dist/web/assets/index-EMrm1wk-.js +2 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/commands/toggle-proxy.js +1 -1
- package/src/server/api/claude-hooks.js +23 -536
- package/src/server/api/codex-proxy.js +1 -1
- package/src/server/api/opencode-proxy.js +92 -7
- package/src/server/index.js +2 -1
- package/src/server/services/codex-channels.js +1 -1
- package/src/server/services/gemini-channels.js +52 -31
- package/src/server/services/native-oauth-adapters.js +152 -5
- package/src/server/services/notification-hooks.js +579 -5
- package/src/server/services/opencode-channels.js +11 -2
- package/dist/web/assets/index-B4Wl3JfR.js +0 -2
- package/dist/web/assets/index-Bgt_oqoE.css +0 -1
|
@@ -238,7 +238,191 @@ function escapeForXml(value) {
|
|
|
238
238
|
}
|
|
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 {',
|
|
367
|
+
'Add-Type -AssemblyName System.Windows.Forms',
|
|
368
|
+
'Add-Type -AssemblyName System.Drawing',
|
|
369
|
+
'$form = New-Object System.Windows.Forms.Form',
|
|
370
|
+
'$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None',
|
|
371
|
+
'$form.BackColor = [System.Drawing.Color]::FromArgb(247, 247, 250)',
|
|
372
|
+
'$form.Width = 360',
|
|
373
|
+
'$form.Height = 118',
|
|
374
|
+
'$form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual',
|
|
375
|
+
'$form.ShowInTaskbar = $false',
|
|
376
|
+
'$form.TopMost = $true',
|
|
377
|
+
'$form.MaximizeBox = $false',
|
|
378
|
+
'$form.MinimizeBox = $false',
|
|
379
|
+
'$workingArea = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',
|
|
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)',
|
|
393
|
+
'$titleLabel = New-Object System.Windows.Forms.Label',
|
|
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)',
|
|
397
|
+
'$titleLabel.AutoSize = $true',
|
|
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)',
|
|
415
|
+
'$form.Controls.Add($titleLabel)',
|
|
416
|
+
'$form.Controls.Add($headlineLabel)',
|
|
417
|
+
'$form.Controls.Add($detailLabel)',
|
|
418
|
+
'$timer = New-Object System.Windows.Forms.Timer',
|
|
419
|
+
'$timer.Interval = 4800',
|
|
420
|
+
'$timer.Add_Tick({ $timer.Stop(); $form.Close() })',
|
|
421
|
+
'$timer.Start()',
|
|
422
|
+
'[void]$form.ShowDialog()',
|
|
423
|
+
'}'
|
|
424
|
+
].join('; ');
|
|
425
|
+
return `powershell -NoProfile -STA -Command ${JSON.stringify(script)}`;
|
|
242
426
|
}
|
|
243
427
|
|
|
244
428
|
function generateNotifyScript(feishu = {}) {
|
|
@@ -345,7 +529,7 @@ function notify(mode, message) {
|
|
|
345
529
|
const ps = "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('" +
|
|
346
530
|
escapeForPowerShellSingleQuote(message) + "', '" +
|
|
347
531
|
escapeForPowerShellSingleQuote(title) + "', 'OK', 'Information')"
|
|
348
|
-
const command = 'powershell -NoProfile -Command ' + JSON.stringify(ps) + ' || ' + popupCommand
|
|
532
|
+
const command = 'powershell -NoProfile -STA -Command ' + JSON.stringify(ps) + ' || ' + popupCommand
|
|
349
533
|
execSync(command, { stdio: 'ignore', windowsHide: true })
|
|
350
534
|
} else {
|
|
351
535
|
execSync(popupCommand, { stdio: 'ignore', windowsHide: true })
|
|
@@ -464,7 +648,191 @@ function escapeForXml(value) {
|
|
|
464
648
|
}
|
|
465
649
|
|
|
466
650
|
function buildWindowsPopupCommand(title, message) {
|
|
467
|
-
|
|
651
|
+
const script = [
|
|
652
|
+
"$ErrorActionPreference = 'Stop'",
|
|
653
|
+
\`$titleText = '\${escapeForPowerShellSingleQuote(title)}'\`,
|
|
654
|
+
\`$messageText = '\${escapeForPowerShellSingleQuote(message)}'\`,
|
|
655
|
+
"$segments = $messageText -split '\\\\s*\\\\|\\\\s*', 2",
|
|
656
|
+
"$headlineText = if ($segments.Length -ge 1) { $segments[0] } else { $messageText }",
|
|
657
|
+
"$detailText = if ($segments.Length -ge 2) { $segments[1] } else { '' }",
|
|
658
|
+
'try {',
|
|
659
|
+
'Add-Type -AssemblyName PresentationFramework',
|
|
660
|
+
'Add-Type -AssemblyName PresentationCore',
|
|
661
|
+
'Add-Type -AssemblyName WindowsBase',
|
|
662
|
+
'$brushConverter = New-Object System.Windows.Media.BrushConverter',
|
|
663
|
+
'$window = New-Object System.Windows.Window',
|
|
664
|
+
'$window.Width = 372',
|
|
665
|
+
'$window.Height = 118',
|
|
666
|
+
'$window.WindowStyle = [System.Windows.WindowStyle]::None',
|
|
667
|
+
'$window.ResizeMode = [System.Windows.ResizeMode]::NoResize',
|
|
668
|
+
'$window.AllowsTransparency = $true',
|
|
669
|
+
'$window.Background = [System.Windows.Media.Brushes]::Transparent',
|
|
670
|
+
'$window.ShowInTaskbar = $false',
|
|
671
|
+
'$window.Topmost = $true',
|
|
672
|
+
'$window.ShowActivated = $false',
|
|
673
|
+
'$window.Opacity = 0',
|
|
674
|
+
'$window.WindowStartupLocation = [System.Windows.WindowStartupLocation]::Manual',
|
|
675
|
+
'$root = New-Object System.Windows.Controls.Border',
|
|
676
|
+
'$root.CornerRadius = New-Object System.Windows.CornerRadius -ArgumentList 20',
|
|
677
|
+
'$root.Padding = New-Object System.Windows.Thickness -ArgumentList 16',
|
|
678
|
+
"$root.Background = $brushConverter.ConvertFromString('#F3F4F7')",
|
|
679
|
+
"$root.BorderBrush = $brushConverter.ConvertFromString('#D9DBE3')",
|
|
680
|
+
'$root.BorderThickness = New-Object System.Windows.Thickness -ArgumentList 1',
|
|
681
|
+
'$shadow = New-Object System.Windows.Media.Effects.DropShadowEffect',
|
|
682
|
+
"$shadow.Color = [System.Windows.Media.ColorConverter]::ConvertFromString('#22000000')",
|
|
683
|
+
'$shadow.BlurRadius = 26',
|
|
684
|
+
'$shadow.ShadowDepth = 0',
|
|
685
|
+
'$shadow.Opacity = 0.85',
|
|
686
|
+
'$root.Effect = $shadow',
|
|
687
|
+
'$grid = New-Object System.Windows.Controls.Grid',
|
|
688
|
+
'$iconColumn = New-Object System.Windows.Controls.ColumnDefinition',
|
|
689
|
+
'$iconColumn.Width = New-Object System.Windows.GridLength -ArgumentList 44',
|
|
690
|
+
'$contentColumn = New-Object System.Windows.Controls.ColumnDefinition',
|
|
691
|
+
'$grid.ColumnDefinitions.Add($iconColumn) | Out-Null',
|
|
692
|
+
'$grid.ColumnDefinitions.Add($contentColumn) | Out-Null',
|
|
693
|
+
'$iconHolder = New-Object System.Windows.Controls.Border',
|
|
694
|
+
'$iconHolder.Width = 34',
|
|
695
|
+
'$iconHolder.Height = 34',
|
|
696
|
+
'$iconHolder.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Left',
|
|
697
|
+
'$iconHolder.VerticalAlignment = [System.Windows.VerticalAlignment]::Top',
|
|
698
|
+
'$iconHolder.CornerRadius = New-Object System.Windows.CornerRadius -ArgumentList 17',
|
|
699
|
+
"$iconHolder.Background = $brushConverter.ConvertFromString('#DDEBFF')",
|
|
700
|
+
'$iconGlyph = New-Object System.Windows.Controls.TextBlock',
|
|
701
|
+
'$iconGlyph.Text = [char]0x2713',
|
|
702
|
+
'$iconGlyph.FontSize = 18',
|
|
703
|
+
'$iconGlyph.FontWeight = [System.Windows.FontWeights]::Bold',
|
|
704
|
+
"$iconGlyph.Foreground = $brushConverter.ConvertFromString('#0A84FF')",
|
|
705
|
+
'$iconGlyph.HorizontalAlignment = [System.Windows.HorizontalAlignment]::Center',
|
|
706
|
+
'$iconGlyph.VerticalAlignment = [System.Windows.VerticalAlignment]::Center',
|
|
707
|
+
'$iconHolder.Child = $iconGlyph',
|
|
708
|
+
'$contentStack = New-Object System.Windows.Controls.StackPanel',
|
|
709
|
+
'$contentStack.Orientation = [System.Windows.Controls.Orientation]::Vertical',
|
|
710
|
+
'$contentStack.Margin = New-Object System.Windows.Thickness -ArgumentList 4,0,0,0',
|
|
711
|
+
'$metaGrid = New-Object System.Windows.Controls.Grid',
|
|
712
|
+
'$metaGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition)) | Out-Null',
|
|
713
|
+
'$timeColumn = New-Object System.Windows.Controls.ColumnDefinition',
|
|
714
|
+
'$timeColumn.Width = [System.Windows.GridLength]::Auto',
|
|
715
|
+
'$metaGrid.ColumnDefinitions.Add($timeColumn) | Out-Null',
|
|
716
|
+
'$appLabel = New-Object System.Windows.Controls.TextBlock',
|
|
717
|
+
'$appLabel.Text = $titleText',
|
|
718
|
+
'$appLabel.FontSize = 11.5',
|
|
719
|
+
'$appLabel.FontWeight = [System.Windows.FontWeights]::SemiBold',
|
|
720
|
+
"$appLabel.Foreground = $brushConverter.ConvertFromString('#6B6C73')",
|
|
721
|
+
'$appLabel.TextTrimming = [System.Windows.TextTrimming]::CharacterEllipsis',
|
|
722
|
+
'$stampLabel = New-Object System.Windows.Controls.TextBlock',
|
|
723
|
+
"$stampLabel.Text = '刚刚'",
|
|
724
|
+
'$stampLabel.FontSize = 11',
|
|
725
|
+
"$stampLabel.Foreground = $brushConverter.ConvertFromString('#8D8E95')",
|
|
726
|
+
'$stampLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 12,0,0,0',
|
|
727
|
+
'[System.Windows.Controls.Grid]::SetColumn($stampLabel, 1)',
|
|
728
|
+
'$metaGrid.Children.Add($appLabel) | Out-Null',
|
|
729
|
+
'$metaGrid.Children.Add($stampLabel) | Out-Null',
|
|
730
|
+
'$headlineLabel = New-Object System.Windows.Controls.TextBlock',
|
|
731
|
+
'$headlineLabel.Text = $headlineText',
|
|
732
|
+
'$headlineLabel.FontSize = 14',
|
|
733
|
+
'$headlineLabel.FontWeight = [System.Windows.FontWeights]::SemiBold',
|
|
734
|
+
"$headlineLabel.Foreground = $brushConverter.ConvertFromString('#1F2024')",
|
|
735
|
+
'$headlineLabel.TextWrapping = [System.Windows.TextWrapping]::Wrap',
|
|
736
|
+
'$headlineLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 0,6,0,0',
|
|
737
|
+
'$detailLabel = New-Object System.Windows.Controls.TextBlock',
|
|
738
|
+
'$detailLabel.Text = $detailText',
|
|
739
|
+
'$detailLabel.FontSize = 12',
|
|
740
|
+
"$detailLabel.Foreground = $brushConverter.ConvertFromString('#5F6168')",
|
|
741
|
+
'$detailLabel.TextWrapping = [System.Windows.TextWrapping]::Wrap',
|
|
742
|
+
'$detailLabel.Margin = New-Object System.Windows.Thickness -ArgumentList 0,4,0,0',
|
|
743
|
+
'$detailLabel.Visibility = if ([string]::IsNullOrWhiteSpace($detailText)) { [System.Windows.Visibility]::Collapsed } else { [System.Windows.Visibility]::Visible }',
|
|
744
|
+
'$contentStack.Children.Add($metaGrid) | Out-Null',
|
|
745
|
+
'$contentStack.Children.Add($headlineLabel) | Out-Null',
|
|
746
|
+
'$contentStack.Children.Add($detailLabel) | Out-Null',
|
|
747
|
+
'[System.Windows.Controls.Grid]::SetColumn($contentStack, 1)',
|
|
748
|
+
'$grid.Children.Add($iconHolder) | Out-Null',
|
|
749
|
+
'$grid.Children.Add($contentStack) | Out-Null',
|
|
750
|
+
'$root.Child = $grid',
|
|
751
|
+
'$window.Content = $root',
|
|
752
|
+
'$workArea = [System.Windows.SystemParameters]::WorkArea',
|
|
753
|
+
'$window.Left = $workArea.Right - $window.Width - 18',
|
|
754
|
+
'$window.Top = $workArea.Top + 18',
|
|
755
|
+
'$frame = New-Object System.Windows.Threading.DispatcherFrame',
|
|
756
|
+
'$window.Add_Closed({ $frame.Continue = $false })',
|
|
757
|
+
'$closeTimer = New-Object System.Windows.Threading.DispatcherTimer',
|
|
758
|
+
'$closeTimer.Interval = [TimeSpan]::FromMilliseconds(4600)',
|
|
759
|
+
'$closeTimer.Add_Tick({',
|
|
760
|
+
' $closeTimer.Stop()',
|
|
761
|
+
' $fadeOut = New-Object System.Windows.Media.Animation.DoubleAnimation',
|
|
762
|
+
' $fadeOut.From = $window.Opacity',
|
|
763
|
+
' $fadeOut.To = 0',
|
|
764
|
+
' $fadeOut.Duration = [TimeSpan]::FromMilliseconds(220)',
|
|
765
|
+
' $fadeOut.Add_Completed({ $window.Close() })',
|
|
766
|
+
' $window.BeginAnimation([System.Windows.Window]::OpacityProperty, $fadeOut)',
|
|
767
|
+
'})',
|
|
768
|
+
'$window.Show()',
|
|
769
|
+
'$fadeIn = New-Object System.Windows.Media.Animation.DoubleAnimation',
|
|
770
|
+
'$fadeIn.From = 0',
|
|
771
|
+
'$fadeIn.To = 1',
|
|
772
|
+
'$fadeIn.Duration = [TimeSpan]::FromMilliseconds(180)',
|
|
773
|
+
'$window.BeginAnimation([System.Windows.Window]::OpacityProperty, $fadeIn)',
|
|
774
|
+
'$closeTimer.Start()',
|
|
775
|
+
'[System.Windows.Threading.Dispatcher]::PushFrame($frame)',
|
|
776
|
+
'} catch {',
|
|
777
|
+
'Add-Type -AssemblyName System.Windows.Forms',
|
|
778
|
+
'Add-Type -AssemblyName System.Drawing',
|
|
779
|
+
'$form = New-Object System.Windows.Forms.Form',
|
|
780
|
+
'$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None',
|
|
781
|
+
'$form.BackColor = [System.Drawing.Color]::FromArgb(247, 247, 250)',
|
|
782
|
+
'$form.Width = 360',
|
|
783
|
+
'$form.Height = 118',
|
|
784
|
+
'$form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual',
|
|
785
|
+
'$form.ShowInTaskbar = $false',
|
|
786
|
+
'$form.TopMost = $true',
|
|
787
|
+
'$form.MaximizeBox = $false',
|
|
788
|
+
'$form.MinimizeBox = $false',
|
|
789
|
+
'$workingArea = [System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea',
|
|
790
|
+
'$form.Location = New-Object System.Drawing.Point(($workingArea.Right - $form.Width - 18), ($workingArea.Top + 18))',
|
|
791
|
+
'$iconPanel = New-Object System.Windows.Forms.Panel',
|
|
792
|
+
'$iconPanel.Width = 34',
|
|
793
|
+
'$iconPanel.Height = 34',
|
|
794
|
+
'$iconPanel.BackColor = [System.Drawing.Color]::FromArgb(221, 235, 255)',
|
|
795
|
+
'$iconPanel.Location = New-Object System.Drawing.Point(16, 18)',
|
|
796
|
+
'$iconLabel = New-Object System.Windows.Forms.Label',
|
|
797
|
+
'$iconLabel.Text = [char]0x2713',
|
|
798
|
+
"$iconLabel.Font = New-Object System.Drawing.Font('Segoe UI', 14, [System.Drawing.FontStyle]::Bold)",
|
|
799
|
+
'$iconLabel.ForeColor = [System.Drawing.Color]::FromArgb(10, 132, 255)',
|
|
800
|
+
'$iconLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter',
|
|
801
|
+
'$iconLabel.Dock = [System.Windows.Forms.DockStyle]::Fill',
|
|
802
|
+
'$iconPanel.Controls.Add($iconLabel)',
|
|
803
|
+
'$titleLabel = New-Object System.Windows.Forms.Label',
|
|
804
|
+
'$titleLabel.Text = $titleText',
|
|
805
|
+
"$titleLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9, [System.Drawing.FontStyle]::Bold)",
|
|
806
|
+
'$titleLabel.ForeColor = [System.Drawing.Color]::FromArgb(109, 110, 115)',
|
|
807
|
+
'$titleLabel.AutoSize = $true',
|
|
808
|
+
'$titleLabel.Location = New-Object System.Drawing.Point(60, 16)',
|
|
809
|
+
'$headlineLabel = New-Object System.Windows.Forms.Label',
|
|
810
|
+
'$headlineLabel.Text = $headlineText',
|
|
811
|
+
"$headlineLabel.Font = New-Object System.Drawing.Font('Segoe UI', 10.5, [System.Drawing.FontStyle]::Bold)",
|
|
812
|
+
'$headlineLabel.ForeColor = [System.Drawing.Color]::FromArgb(31, 32, 36)',
|
|
813
|
+
'$headlineLabel.MaximumSize = New-Object System.Drawing.Size(272, 0)',
|
|
814
|
+
'$headlineLabel.AutoSize = $true',
|
|
815
|
+
'$headlineLabel.Location = New-Object System.Drawing.Point(60, 36)',
|
|
816
|
+
'$detailLabel = New-Object System.Windows.Forms.Label',
|
|
817
|
+
'$detailLabel.Text = $detailText',
|
|
818
|
+
"$detailLabel.Font = New-Object System.Drawing.Font('Segoe UI', 9)",
|
|
819
|
+
'$detailLabel.ForeColor = [System.Drawing.Color]::FromArgb(95, 97, 104)',
|
|
820
|
+
'$detailLabel.MaximumSize = New-Object System.Drawing.Size(272, 0)',
|
|
821
|
+
'$detailLabel.AutoSize = $true',
|
|
822
|
+
'$detailLabel.Location = New-Object System.Drawing.Point(60, 60)',
|
|
823
|
+
'$detailLabel.Visible = -not [string]::IsNullOrWhiteSpace($detailText)',
|
|
824
|
+
'$form.Controls.Add($iconPanel)',
|
|
825
|
+
'$form.Controls.Add($titleLabel)',
|
|
826
|
+
'$form.Controls.Add($headlineLabel)',
|
|
827
|
+
'$form.Controls.Add($detailLabel)',
|
|
828
|
+
'$timer = New-Object System.Windows.Forms.Timer',
|
|
829
|
+
'$timer.Interval = 4800',
|
|
830
|
+
'$timer.Add_Tick({ $timer.Stop(); $form.Close() })',
|
|
831
|
+
'$timer.Start()',
|
|
832
|
+
'[void]$form.ShowDialog()',
|
|
833
|
+
'}'
|
|
834
|
+
].join('; ')
|
|
835
|
+
return 'powershell -NoProfile -STA -Command ' + JSON.stringify(script)
|
|
468
836
|
}
|
|
469
837
|
`;
|
|
470
838
|
}
|
|
@@ -832,6 +1200,205 @@ function saveNotificationSettings(input = {}) {
|
|
|
832
1200
|
return getNotificationSettings();
|
|
833
1201
|
}
|
|
834
1202
|
|
|
1203
|
+
function parseNotifyTypeMarker(command) {
|
|
1204
|
+
const marker = String(command || '').match(/--cc-notify-type=(['"])?(dialog|notification)\1/i);
|
|
1205
|
+
return marker?.[2] ? normalizeType(marker[2].toLowerCase()) : null;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
function getStopHookCommand(settings = {}) {
|
|
1209
|
+
const hooks = settings?.hooks?.Stop;
|
|
1210
|
+
if (!Array.isArray(hooks) || hooks.length === 0) {
|
|
1211
|
+
return '';
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
let fallbackCommand = '';
|
|
1215
|
+
for (const group of hooks) {
|
|
1216
|
+
const groupHooks = Array.isArray(group?.hooks) ? group.hooks : [];
|
|
1217
|
+
for (const hook of groupHooks) {
|
|
1218
|
+
const command = String(hook?.command || '');
|
|
1219
|
+
if (!command) continue;
|
|
1220
|
+
if (!fallbackCommand) {
|
|
1221
|
+
fallbackCommand = command;
|
|
1222
|
+
}
|
|
1223
|
+
if (command.includes('notify-hook.js')) {
|
|
1224
|
+
return command;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
return fallbackCommand;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
function normalizePathForCompare(rawPath) {
|
|
1233
|
+
return String(rawPath || '').replace(/\\/g, '/');
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
function shouldRepairStopHook(settings, expectedScriptPath = PATHS.notifyHook, fileExists = fs.existsSync) {
|
|
1237
|
+
const command = getStopHookCommand(settings);
|
|
1238
|
+
if (!command || !command.includes('notify-hook.js')) {
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
const normalizedCommand = normalizePathForCompare(command);
|
|
1243
|
+
const normalizedExpected = normalizePathForCompare(expectedScriptPath);
|
|
1244
|
+
if (!normalizedCommand.includes(normalizedExpected)) {
|
|
1245
|
+
return true;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
const markerType = parseNotifyTypeMarker(command);
|
|
1249
|
+
if (!markerType) {
|
|
1250
|
+
return true;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
return !fileExists(expectedScriptPath);
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
function buildStopHookCommand(type) {
|
|
1257
|
+
return buildClaudeCommand(type);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
function parseStopHookStatus(settings = {}) {
|
|
1261
|
+
const stopGroups = Array.isArray(settings?.hooks?.Stop) ? settings.hooks.Stop : [];
|
|
1262
|
+
if (stopGroups.length === 0) {
|
|
1263
|
+
return { enabled: false, type: 'notification' };
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
let sawNotificationLikeCommand = false;
|
|
1267
|
+
for (const group of stopGroups) {
|
|
1268
|
+
const groupHooks = Array.isArray(group?.hooks) ? group.hooks : [];
|
|
1269
|
+
for (const hook of groupHooks) {
|
|
1270
|
+
const command = String(hook?.command || '');
|
|
1271
|
+
if (!command) continue;
|
|
1272
|
+
|
|
1273
|
+
const markerType = parseNotifyTypeMarker(command) || parseManagedType(command);
|
|
1274
|
+
if (markerType) {
|
|
1275
|
+
return { enabled: true, type: markerType };
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
const isDialog = command.includes('display dialog') ||
|
|
1279
|
+
command.includes('MessageBox') ||
|
|
1280
|
+
command.includes('zenity --info');
|
|
1281
|
+
if (isDialog) {
|
|
1282
|
+
return { enabled: true, type: 'dialog' };
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
const isNotification = command.includes('display notification') ||
|
|
1286
|
+
command.includes('Popup') ||
|
|
1287
|
+
command.includes('GraphicsPath') ||
|
|
1288
|
+
command.includes('TransparencyKey') ||
|
|
1289
|
+
command.includes('FormBorderStyle]::None') ||
|
|
1290
|
+
command.includes('AllowsTransparency') ||
|
|
1291
|
+
command.includes('notify-send') ||
|
|
1292
|
+
command.includes('ToastNotificationManager') ||
|
|
1293
|
+
command.includes('CreateToastNotifier') ||
|
|
1294
|
+
command.includes('notify-hook.js');
|
|
1295
|
+
if (isNotification) {
|
|
1296
|
+
sawNotificationLikeCommand = true;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
return sawNotificationLikeCommand
|
|
1302
|
+
? { enabled: true, type: 'notification' }
|
|
1303
|
+
: { enabled: false, type: 'notification' };
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
function normalizeSavedPlatformStatus(platform = {}) {
|
|
1307
|
+
return {
|
|
1308
|
+
enabled: platform?.enabled === true,
|
|
1309
|
+
type: normalizeType(platform?.type)
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
function buildLegacyClaudeSaveInput(input = {}, currentSettings = getNotificationSettings()) {
|
|
1314
|
+
return {
|
|
1315
|
+
platforms: {
|
|
1316
|
+
claude: input.stopHook !== undefined
|
|
1317
|
+
? normalizePlatformInput(input.stopHook)
|
|
1318
|
+
: { enabled: false, type: 'notification' },
|
|
1319
|
+
codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
|
|
1320
|
+
gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
|
|
1321
|
+
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
|
|
1322
|
+
},
|
|
1323
|
+
feishu: input.feishu !== undefined
|
|
1324
|
+
? {
|
|
1325
|
+
enabled: input.feishu?.enabled === true,
|
|
1326
|
+
webhookUrl: input.feishu?.webhookUrl || ''
|
|
1327
|
+
}
|
|
1328
|
+
: {
|
|
1329
|
+
enabled: currentSettings?.feishu?.enabled === true,
|
|
1330
|
+
webhookUrl: currentSettings?.feishu?.webhookUrl || ''
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
function getLegacyClaudeHookSettings() {
|
|
1336
|
+
return {
|
|
1337
|
+
success: true,
|
|
1338
|
+
stopHook: parseStopHookStatus(readClaudeSettings()),
|
|
1339
|
+
feishu: getFeishuConfig(),
|
|
1340
|
+
platform: os.platform()
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
function saveLegacyClaudeHookSettings(input = {}) {
|
|
1345
|
+
const currentSettings = getNotificationSettings();
|
|
1346
|
+
saveNotificationSettings(buildLegacyClaudeSaveInput(input, currentSettings));
|
|
1347
|
+
return getLegacyClaudeHookSettings();
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
function initDefaultHooks() {
|
|
1351
|
+
try {
|
|
1352
|
+
const uiConfig = loadUIConfig();
|
|
1353
|
+
if (uiConfig.claudeNotificationDisabledByUser === true) {
|
|
1354
|
+
console.log('[Claude Hooks] 用户已主动关闭通知,跳过自动初始化');
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
const currentClaudeSettings = readClaudeSettings();
|
|
1359
|
+
const currentStatus = parseStopHookStatus(currentClaudeSettings);
|
|
1360
|
+
|
|
1361
|
+
if (currentStatus.enabled) {
|
|
1362
|
+
if (shouldRepairStopHook(currentClaudeSettings)) {
|
|
1363
|
+
const currentSettings = getNotificationSettings();
|
|
1364
|
+
saveNotificationSettings({
|
|
1365
|
+
platforms: {
|
|
1366
|
+
claude: { enabled: true, type: currentStatus.type || 'notification' },
|
|
1367
|
+
codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
|
|
1368
|
+
gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
|
|
1369
|
+
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
|
|
1370
|
+
},
|
|
1371
|
+
feishu: {
|
|
1372
|
+
enabled: currentSettings?.feishu?.enabled === true,
|
|
1373
|
+
webhookUrl: currentSettings?.feishu?.webhookUrl || ''
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
console.log('[Claude Hooks] 检测到旧版 Stop hook 路径,已自动修复');
|
|
1377
|
+
} else {
|
|
1378
|
+
console.log('[Claude Hooks] 已存在 Stop hook 配置,跳过初始化');
|
|
1379
|
+
}
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
const currentSettings = getNotificationSettings();
|
|
1384
|
+
saveNotificationSettings({
|
|
1385
|
+
platforms: {
|
|
1386
|
+
claude: { enabled: true, type: 'notification' },
|
|
1387
|
+
codex: normalizeSavedPlatformStatus(currentSettings?.platforms?.codex),
|
|
1388
|
+
gemini: normalizeSavedPlatformStatus(currentSettings?.platforms?.gemini),
|
|
1389
|
+
opencode: normalizeSavedPlatformStatus(currentSettings?.platforms?.opencode)
|
|
1390
|
+
},
|
|
1391
|
+
feishu: {
|
|
1392
|
+
enabled: currentSettings?.feishu?.enabled === true,
|
|
1393
|
+
webhookUrl: currentSettings?.feishu?.webhookUrl || ''
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
console.log('[Claude Hooks] 已自动开启任务完成通知(右上角卡片)');
|
|
1397
|
+
} catch (error) {
|
|
1398
|
+
console.error('[Claude Hooks] 初始化默认配置失败:', error);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
835
1402
|
function sendFeishuTest(webhookUrl) {
|
|
836
1403
|
return new Promise((resolve, reject) => {
|
|
837
1404
|
try {
|
|
@@ -897,7 +1464,7 @@ function generateSystemNotificationCommand(type, message, platformOverride = os.
|
|
|
897
1464
|
if (platform === 'win32') {
|
|
898
1465
|
const popupCommand = buildWindowsPopupCommand(title, message);
|
|
899
1466
|
if (normalizedType === 'dialog') {
|
|
900
|
-
return `powershell -NoProfile -Command "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('${escapeForPowerShellSingleQuote(message)}', '${escapeForPowerShellSingleQuote(title)}', 'OK', 'Information')" || ${popupCommand}`;
|
|
1467
|
+
return `powershell -NoProfile -STA -Command "Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show('${escapeForPowerShellSingleQuote(message)}', '${escapeForPowerShellSingleQuote(title)}', 'OK', 'Information')" || ${popupCommand}`;
|
|
901
1468
|
}
|
|
902
1469
|
return popupCommand;
|
|
903
1470
|
}
|
|
@@ -920,8 +1487,11 @@ function testNotification({ type, testFeishu, webhookUrl } = {}) {
|
|
|
920
1487
|
module.exports = {
|
|
921
1488
|
MANAGED_HOOK_NAME,
|
|
922
1489
|
getNotificationSettings,
|
|
1490
|
+
getLegacyClaudeHookSettings,
|
|
923
1491
|
saveNotificationSettings,
|
|
1492
|
+
saveLegacyClaudeHookSettings,
|
|
924
1493
|
testNotification,
|
|
1494
|
+
initDefaultHooks,
|
|
925
1495
|
getOpenCodeManagedPluginPath,
|
|
926
1496
|
buildOpenCodePluginContent,
|
|
927
1497
|
buildCodexNotifyCommand,
|
|
@@ -931,6 +1501,7 @@ module.exports = {
|
|
|
931
1501
|
applyClaudeDisablePreference,
|
|
932
1502
|
getManagedCommandType,
|
|
933
1503
|
parseManagedType,
|
|
1504
|
+
parseNotifyTypeMarker,
|
|
934
1505
|
getClaudeHookStatus,
|
|
935
1506
|
getCodexHookStatus,
|
|
936
1507
|
getGeminiHookStatus,
|
|
@@ -941,10 +1512,13 @@ module.exports = {
|
|
|
941
1512
|
validateFeishuWebhookUrl,
|
|
942
1513
|
buildCodexNotifyCommand,
|
|
943
1514
|
buildGeminiCommand,
|
|
1515
|
+
buildStopHookCommand,
|
|
944
1516
|
buildClaudeCommand,
|
|
945
1517
|
buildOpenCodePluginContent,
|
|
946
1518
|
getOpenCodeManagedPluginPath,
|
|
947
1519
|
generateNotifyScript,
|
|
948
|
-
generateSystemNotificationCommand
|
|
1520
|
+
generateSystemNotificationCommand,
|
|
1521
|
+
parseStopHookStatus,
|
|
1522
|
+
shouldRepairStopHook
|
|
949
1523
|
}
|
|
950
1524
|
};
|
|
@@ -117,7 +117,7 @@ function syncManagedChannelConfig(channels = [], preferredChannel = null) {
|
|
|
117
117
|
: resolveCurrentManagedChannel(channels);
|
|
118
118
|
|
|
119
119
|
if (targetChannel) {
|
|
120
|
-
setChannelConfig(targetChannel);
|
|
120
|
+
setChannelConfig(buildNativeConfigChannel(targetChannel));
|
|
121
121
|
return targetChannel;
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -305,11 +305,20 @@ function applyChannelToSettings(channelId) {
|
|
|
305
305
|
});
|
|
306
306
|
saveChannels(data);
|
|
307
307
|
|
|
308
|
-
setChannelConfig(channel);
|
|
308
|
+
setChannelConfig(buildNativeConfigChannel(channel));
|
|
309
309
|
|
|
310
310
|
return channel;
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
+
function buildNativeConfigChannel(channel = {}) {
|
|
314
|
+
const candidates = getEffectiveApiKeyCandidates(channel);
|
|
315
|
+
const effectiveApiKey = candidates[0] || normalizeApiKey(channel.apiKey || channel.key || '');
|
|
316
|
+
return {
|
|
317
|
+
...channel,
|
|
318
|
+
apiKey: effectiveApiKey
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
313
322
|
function loadCodexChannels() {
|
|
314
323
|
const filePath = getCodexChannelsFilePath();
|
|
315
324
|
if (!fs.existsSync(filePath)) {
|