ai-notify 0.9.0 → 0.9.1

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.
@@ -401,7 +401,7 @@ final class SettingsWindowController: NSObject {
401
401
  SettingsRow(title: "ツンデレ", asCheckbox: true, on: (tsun?["enabled"] as? Bool) ?? false, lo: 0, hi: 1, value: (tsun?["level"] as? Double) ?? 0.5, fill: pink,
402
402
  onToggle: { State.cli(["tsundere", "toggle"]) },
403
403
  onChange: { State.cli(["tsundere", "level", String(format: "%.2f", $0)]) }),
404
- SettingsRow(title: "戦争", asCheckbox: true, on: (warj?["enabled"] as? Bool) ?? false, lo: 0, hi: 1, value: (warj?["level"] as? Double) ?? 0.5, fill: red,
404
+ SettingsRow(title: "アドレナリン", asCheckbox: true, on: (warj?["enabled"] as? Bool) ?? false, lo: 0, hi: 1, value: (warj?["level"] as? Double) ?? 0.5, fill: red,
405
405
  onToggle: { State.cli(["war", "toggle"]) },
406
406
  onChange: { State.cli(["war", "level", String(format: "%.2f", $0)]) }),
407
407
  SettingsRow(title: "速さ", asCheckbox: false, on: false, lo: slo, hi: shi, value: (pr["speed"] as? Double) ?? 1, fill: blue,
@@ -412,7 +412,7 @@ final class SettingsWindowController: NSObject {
412
412
  onChange: { State.cli(["voice-prosody", "intonation", String(format: "%.3f", $0)]) }),
413
413
  ]
414
414
  var y = 264
415
- let header = NSTextField(labelWithString: "ツンデレ/戦争は 0=デレ・平時 〜 1=ツン・危機")
415
+ let header = NSTextField(labelWithString: "ツンデレ/アドレナリンは 0=デレ・平時 〜 1=ツン・危機")
416
416
  header.frame = NSRect(x: 16, y: 286, width: 440, height: 16)
417
417
  header.font = .systemFont(ofSize: 11); header.textColor = .secondaryLabelColor
418
418
  content.addSubview(header)
@@ -736,7 +736,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
736
736
  // the menu height never jumps.
737
737
  private func tsundereToggleRow(on: Bool) -> NSMenuItem {
738
738
  let row = NSView(frame: NSRect(x: 0, y: 0, width: 220, height: 24))
739
- let btn = NSButton(checkboxWithTitle: "ツンデレモード", target: self, action: #selector(tsundereToggled(_:)))
739
+ let btn = NSButton(checkboxWithTitle: "ツンデレ", target: self, action: #selector(tsundereToggled(_:)))
740
740
  btn.frame = NSRect(x: 12, y: 2, width: 196, height: 20)
741
741
  btn.state = on ? .on : .off
742
742
  row.addSubview(btn)
@@ -748,7 +748,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
748
748
  // tsundere; the tsundere level flavors it.
749
749
  private func warToggleRow(on: Bool) -> NSMenuItem {
750
750
  let row = NSView(frame: NSRect(x: 0, y: 0, width: 220, height: 24))
751
- let btn = NSButton(checkboxWithTitle: "戦争モード", target: self, action: #selector(warToggled(_:)))
751
+ let btn = NSButton(checkboxWithTitle: "アドレナリン", target: self, action: #selector(warToggled(_:)))
752
752
  btn.frame = NSRect(x: 12, y: 2, width: 196, height: 20)
753
753
  btn.state = on ? .on : .off
754
754
  row.addSubview(btn)
@@ -756,25 +756,26 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
756
756
  return item
757
757
  }
758
758
 
759
- private func warRow(value: Double) -> NSMenuItem {
760
- let row = NSView(frame: NSRect(x: 0, y: 0, width: 220, height: 26))
761
- let left = NSTextField(labelWithString: "平時")
762
- left.frame = NSRect(x: 12, y: 5, width: 30, height: 16)
763
- left.font = .systemFont(ofSize: 10); left.textColor = .secondaryLabelColor
764
- let slider = NSSlider(value: value, minValue: 0, maxValue: 1, target: self, action: #selector(warLevelChanged(_:)))
765
- slider.frame = NSRect(x: 46, y: 3, width: 128, height: 20)
759
+ // A labeled blue level slider (0–1), laid out like the 速さ/高さ/抑揚 rows so
760
+ // ツンデレ / アドレナリン sit with them, aligned and in the same blue.
761
+ private func levelRow(label: String, value: Double, action: Selector) -> NSMenuItem {
762
+ let row = NSView(frame: NSRect(x: 0, y: 0, width: 240, height: 24))
763
+ let cap = NSTextField(labelWithString: label)
764
+ cap.frame = NSRect(x: 12, y: 4, width: 64, height: 16)
765
+ cap.font = .systemFont(ofSize: 11); cap.textColor = .secondaryLabelColor
766
+ let slider = NSSlider(frame: NSRect(x: 78, y: 3, width: 146, height: 20))
767
+ slider.cell = FilledSliderCell() // guaranteed blue fill
768
+ slider.minValue = 0; slider.maxValue = 1; slider.doubleValue = value
769
+ slider.target = self; slider.action = action
766
770
  slider.isContinuous = false
767
- slider.trackFillColor = NSColor(srgbRed: 0.85, green: 0.2, blue: 0.15, alpha: 1) // war red
768
- let right = NSTextField(labelWithString: "危機")
769
- right.frame = NSRect(x: 178, y: 5, width: 30, height: 16)
770
- right.font = .systemFont(ofSize: 10); right.textColor = .secondaryLabelColor
771
- row.addSubview(left); row.addSubview(slider); row.addSubview(right)
771
+ row.addSubview(cap); row.addSubview(slider)
772
772
  let item = NSMenuItem(); item.view = row
773
773
  return item
774
774
  }
775
775
 
776
776
  @objc private func warToggled(_ b: NSButton) { State.cli(["war", "toggle"]) }
777
777
  @objc private func warLevelChanged(_ s: NSSlider) { State.cli(["war", "level", String(format: "%.2f", s.doubleValue)]) }
778
+ @objc private func tsundereLevelDirect(_ s: NSSlider) { State.cli(["tsundere", "level", String(format: "%.2f", s.doubleValue)]) }
778
779
 
779
780
  // representedObject is the full CLI arg array to run.
780
781
  @objc private func runItem(_ item: NSMenuItem) {
@@ -802,16 +803,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
802
803
  // Tsundere mode: checkbox toggle + ツン⇄デレ baseline slider. Both live in
803
804
  // view rows and are always mounted, so toggling never closes the menu nor
804
805
  // shifts its height.
806
+ // Mode toggles (checkboxes only). Their level sliders live below, with the
807
+ // 速さ/高さ/抑揚 sliders, so all the blue adjustment sliders are grouped.
805
808
  let tsun = json?["tsundere"] as? [String: Any]
806
- let tsunOn = (tsun?["enabled"] as? Bool) ?? false
807
809
  let tsunLevel = (tsun?["level"] as? Double) ?? 0.5
808
- menu.addItem(tsundereToggleRow(on: tsunOn))
809
- menu.addItem(tsundereRow(value: tsunLevel))
810
-
811
- // War mode: checkbox + 平時⇄危機 slider (a separate read-out skin).
812
810
  let warJson = json?["war"] as? [String: Any]
811
+ let warLevel = (warJson?["level"] as? Double) ?? 0.5
812
+ menu.addItem(tsundereToggleRow(on: (tsun?["enabled"] as? Bool) ?? false))
813
813
  menu.addItem(warToggleRow(on: (warJson?["enabled"] as? Bool) ?? false))
814
- menu.addItem(warRow(value: (warJson?["level"] as? Double) ?? 0.5))
815
814
  menu.addItem(.separator())
816
815
 
817
816
  // VOICEVOX base prosody (speed / pitch / intonation) — only when VOICEVOX
@@ -835,8 +834,11 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
835
834
  let v = (pr[key] as? Double) ?? dflt
836
835
  menu.addItem(prosodyRow(label: label, value: v, lo: lo, hi: hi, key: key))
837
836
  }
838
- menu.addItem(.separator())
839
837
  }
838
+ // ツンデレ (好感度) and アドレナリン (強度) levels, below 速さ/高さ/抑揚, in blue.
839
+ menu.addItem(levelRow(label: "ツンデレ", value: tsunLevel, action: #selector(tsundereLevelDirect(_:))))
840
+ menu.addItem(levelRow(label: "アドレナリン", value: warLevel, action: #selector(warLevelChanged(_:))))
841
+ menu.addItem(.separator())
840
842
 
841
843
  if voices.isEmpty {
842
844
  menu.addItem(disabledHeader("(声の一覧を取得できません)"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-notify",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Desktop, sound, and spoken notifications for terminal AI coding agents (Claude Code, Codex, Gemini, ...) — with one mute switch that covers all of them, across every terminal.",
5
5
  "type": "module",
6
6
  "bin": {