agentix-cli 0.96.1 → 0.98.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.
Files changed (109) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/Character.swift +4 -1
  2. package/apps/mac-voice/Sources/AgentXVoice/CharacterSim.swift +50 -4
  3. package/apps/mac-voice/Sources/AgentXVoice/PlayActs.swift +164 -0
  4. package/apps/mac-voice/Sources/AgentXVoice/PlayMath.swift +94 -46
  5. package/apps/mac-voice/Sources/AgentXVoice/PlayMotion.swift +110 -0
  6. package/apps/mac-voice/Sources/AgentXVoice/PlayStage.swift +56 -3
  7. package/apps/mac-voice/Sources/AgentXVoice/SettingsLook.swift +6 -0
  8. package/apps/mac-voice/Sources/AgentXVoice/SettingsWindow.swift +4 -1
  9. package/apps/mac-voice/Sources/AgentXVoice/VoiceSettings.swift +18 -1
  10. package/apps/mac-voice/Sources/AgentXVoice/main.swift +24 -10
  11. package/dist/{App-UHSIO3UE.js → App-XLQDP26J.js} +2 -2
  12. package/dist/{ChatApp-LLTFBLJY.js → ChatApp-DRDUXZ66.js} +2 -2
  13. package/dist/{agent-6RJ633MQ.js → agent-QHM3J2XS.js} +2 -2
  14. package/dist/{board-dashboard-A3ZEI4F6.js → board-dashboard-AIT26JTK.js} +4 -4
  15. package/dist/{chunk-ZZSNM2RI.js → chunk-4BCAH7XI.js} +2 -2
  16. package/dist/{chunk-ALWMYA2B.js → chunk-B32A6OOY.js} +2 -2
  17. package/dist/{chunk-VO2GNAKB.js → chunk-BERHVF3T.js} +2 -2
  18. package/dist/{chunk-6DCY2JCB.js → chunk-BHKWXFJD.js} +5 -5
  19. package/dist/{chunk-4XHKJZLJ.js → chunk-BTLW2RML.js} +2 -2
  20. package/dist/{chunk-DU6536CC.js → chunk-DRUEPGLP.js} +2 -2
  21. package/dist/{chunk-KIGFWUKP.js → chunk-DXJRMPGH.js} +2 -2
  22. package/dist/{chunk-IPDEWVVT.js → chunk-GJ5EJVMZ.js} +2 -2
  23. package/dist/{chunk-EBVB727L.js → chunk-IQJ7UZVV.js} +2 -2
  24. package/dist/{chunk-ZVW645NU.js → chunk-J4JVKVEK.js} +2 -2
  25. package/dist/{chunk-TE44E733.js → chunk-J64VIHL5.js} +2 -2
  26. package/dist/{chunk-XEKZKH3W.js → chunk-JREA25GJ.js} +4 -4
  27. package/dist/chunk-JREA25GJ.js.map +1 -0
  28. package/dist/{chunk-KEKO4S45.js → chunk-JZJ7AZJD.js} +2 -2
  29. package/dist/{chunk-MKF6HSBA.js → chunk-LXJGLNVG.js} +2 -2
  30. package/dist/{chunk-QZIEYDIY.js → chunk-OFVMUBIP.js} +2 -2
  31. package/dist/{chunk-GHXSBJZS.js → chunk-QUU5RJ7D.js} +2 -2
  32. package/dist/{chunk-ZYJDAT3E.js → chunk-S2GPUSBU.js} +2 -2
  33. package/dist/{chunk-J2MHITWR.js → chunk-SJMOZY7Y.js} +2 -2
  34. package/dist/{chunk-MNS4SBRR.js → chunk-WWCVQHV3.js} +149 -149
  35. package/dist/chunk-WWCVQHV3.js.map +1 -0
  36. package/dist/{chunk-44UGVUN7.js → chunk-YYCFI4VP.js} +2 -2
  37. package/dist/{chunk-6NECC6YS.js → chunk-Z4FY64BS.js} +2 -2
  38. package/dist/cli.js +1 -1
  39. package/dist/{client-ARS6ZFT2.js → client-BLUCLNIS.js} +2 -2
  40. package/dist/{config-XO5Z3BO5.js → config-ZUMI4IY4.js} +2 -2
  41. package/dist/config-mutator-S3CD2IWQ.js +2 -0
  42. package/dist/{doctor-VUK3JE6Z.js → doctor-XGQW5SMD.js} +2 -2
  43. package/dist/index.d.ts +7 -1
  44. package/dist/index.js +1 -1
  45. package/dist/{program-HUQB4IIO.js → program-FK7REU2M.js} +117 -117
  46. package/dist/program-FK7REU2M.js.map +1 -0
  47. package/dist/{promote-UGQXA4KV.js → promote-K5LP5Q6Z.js} +2 -2
  48. package/dist/{query-DL7RHPMA.js → query-LHXSINM2.js} +2 -2
  49. package/dist/{registry-YIPKBRBH.js → registry-OQUO6NCW.js} +2 -2
  50. package/dist/{request-planner-L2FAVNKP.js → request-planner-TW5OCKTF.js} +2 -2
  51. package/dist/{review-candidates-RPUP4XBU.js → review-candidates-EFELFOSY.js} +2 -2
  52. package/dist/{routing-G66SVTRO.js → routing-TSRZLD7B.js} +2 -2
  53. package/dist/schedule-tool-JUHRVU5D.js +2 -0
  54. package/dist/scheduler-EHJPTULN.js +2 -0
  55. package/dist/{seat-ZPH7DA5L.js → seat-NIPWHLKC.js} +2 -2
  56. package/dist/{select-2WTV2BI2.js → select-UAKDLN76.js} +2 -2
  57. package/dist/{set-enabled-KI2FINQD.js → set-enabled-74DLXMSM.js} +2 -2
  58. package/dist/{tool-ZFQ46KU3.js → tool-CEBL57UW.js} +2 -2
  59. package/dist/{tool-2P4LRWN4.js → tool-TEGHFORD.js} +2 -2
  60. package/dist/wiki-WOK4SCB7.js +2 -0
  61. package/package.json +1 -1
  62. package/dist/chunk-MNS4SBRR.js.map +0 -1
  63. package/dist/chunk-XEKZKH3W.js.map +0 -1
  64. package/dist/config-mutator-MJX4EIYV.js +0 -2
  65. package/dist/program-HUQB4IIO.js.map +0 -1
  66. package/dist/schedule-tool-FOWPIWKP.js +0 -2
  67. package/dist/scheduler-GFVUPAD6.js +0 -2
  68. package/dist/wiki-XATGT3DI.js +0 -2
  69. /package/dist/{App-UHSIO3UE.js.map → App-XLQDP26J.js.map} +0 -0
  70. /package/dist/{ChatApp-LLTFBLJY.js.map → ChatApp-DRDUXZ66.js.map} +0 -0
  71. /package/dist/{agent-6RJ633MQ.js.map → agent-QHM3J2XS.js.map} +0 -0
  72. /package/dist/{board-dashboard-A3ZEI4F6.js.map → board-dashboard-AIT26JTK.js.map} +0 -0
  73. /package/dist/{chunk-ZZSNM2RI.js.map → chunk-4BCAH7XI.js.map} +0 -0
  74. /package/dist/{chunk-ALWMYA2B.js.map → chunk-B32A6OOY.js.map} +0 -0
  75. /package/dist/{chunk-VO2GNAKB.js.map → chunk-BERHVF3T.js.map} +0 -0
  76. /package/dist/{chunk-6DCY2JCB.js.map → chunk-BHKWXFJD.js.map} +0 -0
  77. /package/dist/{chunk-4XHKJZLJ.js.map → chunk-BTLW2RML.js.map} +0 -0
  78. /package/dist/{chunk-DU6536CC.js.map → chunk-DRUEPGLP.js.map} +0 -0
  79. /package/dist/{chunk-KIGFWUKP.js.map → chunk-DXJRMPGH.js.map} +0 -0
  80. /package/dist/{chunk-IPDEWVVT.js.map → chunk-GJ5EJVMZ.js.map} +0 -0
  81. /package/dist/{chunk-EBVB727L.js.map → chunk-IQJ7UZVV.js.map} +0 -0
  82. /package/dist/{chunk-ZVW645NU.js.map → chunk-J4JVKVEK.js.map} +0 -0
  83. /package/dist/{chunk-TE44E733.js.map → chunk-J64VIHL5.js.map} +0 -0
  84. /package/dist/{chunk-KEKO4S45.js.map → chunk-JZJ7AZJD.js.map} +0 -0
  85. /package/dist/{chunk-MKF6HSBA.js.map → chunk-LXJGLNVG.js.map} +0 -0
  86. /package/dist/{chunk-QZIEYDIY.js.map → chunk-OFVMUBIP.js.map} +0 -0
  87. /package/dist/{chunk-GHXSBJZS.js.map → chunk-QUU5RJ7D.js.map} +0 -0
  88. /package/dist/{chunk-ZYJDAT3E.js.map → chunk-S2GPUSBU.js.map} +0 -0
  89. /package/dist/{chunk-J2MHITWR.js.map → chunk-SJMOZY7Y.js.map} +0 -0
  90. /package/dist/{chunk-44UGVUN7.js.map → chunk-YYCFI4VP.js.map} +0 -0
  91. /package/dist/{chunk-6NECC6YS.js.map → chunk-Z4FY64BS.js.map} +0 -0
  92. /package/dist/{client-ARS6ZFT2.js.map → client-BLUCLNIS.js.map} +0 -0
  93. /package/dist/{config-XO5Z3BO5.js.map → config-ZUMI4IY4.js.map} +0 -0
  94. /package/dist/{config-mutator-MJX4EIYV.js.map → config-mutator-S3CD2IWQ.js.map} +0 -0
  95. /package/dist/{doctor-VUK3JE6Z.js.map → doctor-XGQW5SMD.js.map} +0 -0
  96. /package/dist/{promote-UGQXA4KV.js.map → promote-K5LP5Q6Z.js.map} +0 -0
  97. /package/dist/{query-DL7RHPMA.js.map → query-LHXSINM2.js.map} +0 -0
  98. /package/dist/{registry-YIPKBRBH.js.map → registry-OQUO6NCW.js.map} +0 -0
  99. /package/dist/{request-planner-L2FAVNKP.js.map → request-planner-TW5OCKTF.js.map} +0 -0
  100. /package/dist/{review-candidates-RPUP4XBU.js.map → review-candidates-EFELFOSY.js.map} +0 -0
  101. /package/dist/{routing-G66SVTRO.js.map → routing-TSRZLD7B.js.map} +0 -0
  102. /package/dist/{schedule-tool-FOWPIWKP.js.map → schedule-tool-JUHRVU5D.js.map} +0 -0
  103. /package/dist/{scheduler-GFVUPAD6.js.map → scheduler-EHJPTULN.js.map} +0 -0
  104. /package/dist/{seat-ZPH7DA5L.js.map → seat-NIPWHLKC.js.map} +0 -0
  105. /package/dist/{select-2WTV2BI2.js.map → select-UAKDLN76.js.map} +0 -0
  106. /package/dist/{set-enabled-KI2FINQD.js.map → set-enabled-74DLXMSM.js.map} +0 -0
  107. /package/dist/{tool-ZFQ46KU3.js.map → tool-CEBL57UW.js.map} +0 -0
  108. /package/dist/{tool-2P4LRWN4.js.map → tool-TEGHFORD.js.map} +0 -0
  109. /package/dist/{wiki-XATGT3DI.js.map → wiki-WOK4SCB7.js.map} +0 -0
@@ -1,16 +1,27 @@
1
1
  import AppKit
2
2
 
3
3
  /// What play mode (#505) draws over the picture: the page's colour where
4
- /// words are gone, the cloth, and the character. The context is flipped,
4
+ /// words are gone, the pieces that moved, the cloth, and the character. The context is flipped,
5
5
  /// in the picture's points.
6
6
  enum PlayDraw {
7
- static func draw(_ frame: Play.Frame, in ctx: CGContext, stops: [NSColor]) {
7
+ static func draw(_ frame: Play.Frame, in ctx: CGContext, stops: [NSColor], cutouts: PlayCutouts?) {
8
8
  for gone in frame.gone {
9
9
  let c = gone.paper
10
10
  ctx.setFillColor(CGColor(srgbRed: CGFloat(c >> 16 & 0xFF) / 255, green: CGFloat(c >> 8 & 0xFF) / 255,
11
11
  blue: CGFloat(c & 0xFF) / 255, alpha: 1))
12
12
  ctx.fill(cg(gone.rect))
13
13
  }
14
+ for piece in frame.pieces {
15
+ let from = cg(piece.from)
16
+ guard let part = cutouts?.image(from, paper: piece.paper) else { continue }
17
+ ctx.saveGState()
18
+ ctx.translateBy(x: piece.at.x + from.width / 2, y: piece.at.y + from.height / 2)
19
+ ctx.rotate(by: piece.turn)
20
+ // The context is flipped; a picture is not.
21
+ ctx.scaleBy(x: 1, y: -1)
22
+ ctx.draw(part, in: CGRect(x: -from.width / 2, y: -from.height / 2, width: from.width, height: from.height))
23
+ ctx.restoreGState()
24
+ }
14
25
  if let cloth = frame.cloth {
15
26
  let path = CGPath(roundedRect: cg(cloth), cornerWidth: 4, cornerHeight: 4, transform: nil)
16
27
  ctx.addPath(path)
@@ -29,6 +40,41 @@ enum PlayDraw {
29
40
  private static func cg(_ r: PlayMath.Rect) -> CGRect { CGRect(x: r.x, y: r.y, width: r.w, height: r.h) }
30
41
  }
31
42
 
43
+ /// The pieces of the picture that move, each cut out once: the ink alone,
44
+ /// the page's colour around it left out (`PlayMath.ink`).
45
+ final class PlayCutouts {
46
+ private let picture: CGImage
47
+ /// Pixels of the picture per point.
48
+ private let scale: CGFloat
49
+ private var made: [[CGFloat]: CGImage] = [:]
50
+
51
+ init(picture: CGImage, scale: CGFloat) {
52
+ self.picture = picture
53
+ self.scale = scale
54
+ }
55
+
56
+ /// The part of the picture at `from` (points), without its paper.
57
+ func image(_ from: CGRect, paper: UInt32) -> CGImage? {
58
+ let key = [from.minX, from.minY, from.width, from.height]
59
+ if let done = made[key] { return done }
60
+ guard let part = picture.cropping(to: from.applying(CGAffineTransform(scaleX: scale, y: scale))),
61
+ let ctx = CGContext(data: nil, width: part.width, height: part.height, bitsPerComponent: 8, bytesPerRow: part.width * 4,
62
+ space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue),
63
+ let data = ctx.data else { return nil }
64
+ ctx.draw(part, in: CGRect(x: 0, y: 0, width: part.width, height: part.height))
65
+ let px = data.bindMemory(to: UInt8.self, capacity: part.width * part.height * 4)
66
+ for i in stride(from: 0, to: part.width * part.height * 4, by: 4) {
67
+ let a = PlayMath.ink(r: px[i], g: px[i + 1], b: px[i + 2], paper: paper)
68
+ // Premultiplied: the colour fades with it.
69
+ for k in 0..<3 { px[i + k] = UInt8(Double(px[i + k]) * a) }
70
+ px[i + 3] = UInt8(255 * a)
71
+ }
72
+ let image = ctx.makeImage()
73
+ made[key] = image
74
+ return image
75
+ }
76
+ }
77
+
32
78
  /// The stage: a frozen picture of the screen laid over everything, with
33
79
  /// the character playing on it. The real page is never touched: nothing
34
80
  /// is clicked, typed or changed, and what looks eaten or wiped is only
@@ -73,6 +119,7 @@ final class PlayHost {
73
119
  backdrop.layer?.contents = picture
74
120
  let view = PlayView(frame: bounds)
75
121
  view.stops = stops
122
+ view.picture = picture
76
123
  view.shown = Play.Frame(at: foot, pose: CharacterMath.pose(.working))
77
124
  view.onInput = { [weak self] in self?.end("a key or a click") }
78
125
  backdrop.addSubview(view)
@@ -144,6 +191,9 @@ private final class PlayWindow: NSPanel {
144
191
  private final class PlayView: NSView {
145
192
  var shown = Play.Frame()
146
193
  var stops = CharacterDraw.stops(tint: Brand.accent, colors: nil)
194
+ /// The picture under it: moved pieces are cut from it.
195
+ var picture: CGImage? { didSet { cutouts = nil } }
196
+ private var cutouts: PlayCutouts?
147
197
  var onInput: (() -> Void)?
148
198
 
149
199
  override var isFlipped: Bool { true }
@@ -152,7 +202,10 @@ private final class PlayView: NSView {
152
202
 
153
203
  override func draw(_ dirtyRect: NSRect) {
154
204
  guard let ctx = NSGraphicsContext.current?.cgContext else { return }
155
- PlayDraw.draw(shown, in: ctx, stops: stops)
205
+ if cutouts == nil, let picture {
206
+ cutouts = PlayCutouts(picture: picture, scale: CGFloat(picture.width) / max(bounds.width, 1))
207
+ }
208
+ PlayDraw.draw(shown, in: ctx, stops: stops, cutouts: cutouts)
156
209
  }
157
210
 
158
211
  override func keyDown(with event: NSEvent) { onInput?() }
@@ -57,6 +57,8 @@ struct LookSection: View {
57
57
  @Binding var look: String
58
58
  /// Nil hides the control: the daemon is older than the reduced pill.
59
59
  var startReduced: Binding<Bool>?
60
+ /// Nil hides the control: the daemon is older than the stroll.
61
+ var stroll: Binding<Bool>?
60
62
 
61
63
  var body: some View {
62
64
  Section {
@@ -68,6 +70,10 @@ struct LookSection: View {
68
70
  Toggle("Start reduced to the orb", isOn: startReduced)
69
71
  .disabled(look == "character")
70
72
  }
73
+ if let stroll {
74
+ Toggle("Character strolls when idle", isOn: stroll)
75
+ .disabled(look != "character")
76
+ }
71
77
  } header: {
72
78
  Text("Assistant")
73
79
  } footer: {
@@ -378,7 +378,10 @@ private struct GeneralTab: View {
378
378
  set: { model.draft?.general.look = $0 }),
379
379
  startReduced: draft.general.startReduced == nil ? nil
380
380
  : Binding(get: { model.draft?.general.startReduced ?? false },
381
- set: { model.draft?.general.startReduced = $0 }))
381
+ set: { model.draft?.general.startReduced = $0 }),
382
+ stroll: draft.general.stroll == nil ? nil
383
+ : Binding(get: { model.draft?.general.stroll ?? false },
384
+ set: { model.draft?.general.stroll = $0 }))
382
385
  }
383
386
  if draft.general.card != nil {
384
387
  AnswerCardSection(card: Binding(get: { model.draft?.general.card ?? .standard },
@@ -32,13 +32,17 @@ struct VoiceSettings: Codable, Equatable {
32
32
  /// The pill starts reduced to its orb. Nil from a daemon older
33
33
  /// than the reduced pill.
34
34
  var startReduced: Bool?
35
+ /// The character takes a stroll when it has nothing to do. Nil
36
+ /// from a daemon older than the stroll.
37
+ var stroll: Bool?
35
38
 
36
39
  init(provider: String, fallback: String, stt: String, localStt: String = "mlx-whisper",
37
40
  endOfTurn: String = "vad", hotkeys: Hotkeys, card: Card? = nil, look: String? = nil,
38
- startReduced: Bool? = nil) {
41
+ startReduced: Bool? = nil, stroll: Bool? = nil) {
39
42
  self.provider = provider; self.fallback = fallback; self.stt = stt
40
43
  self.localStt = localStt; self.endOfTurn = endOfTurn; self.hotkeys = hotkeys
41
44
  self.card = card; self.look = look; self.startReduced = startReduced
45
+ self.stroll = stroll
42
46
  }
43
47
 
44
48
  /// A daemon from before these fields leaves them out: the defaults.
@@ -53,6 +57,7 @@ struct VoiceSettings: Codable, Equatable {
53
57
  card = try c.decodeIfPresent(Card.self, forKey: .card)
54
58
  look = try c.decodeIfPresent(String.self, forKey: .look)
55
59
  startReduced = try c.decodeIfPresent(Bool.self, forKey: .startReduced)
60
+ stroll = try c.decodeIfPresent(Bool.self, forKey: .stroll)
56
61
  }
57
62
  }
58
63
  struct Voice: Codable, Equatable {
@@ -113,6 +118,7 @@ struct VoiceSettings: Codable, Equatable {
113
118
  if self.general.endOfTurn != old.general.endOfTurn { general["endOfTurn"] = self.general.endOfTurn }
114
119
  if let look = self.general.look, look != old.general.look { general["look"] = look }
115
120
  if let start = self.general.startReduced, start != old.general.startReduced { general["startReduced"] = start }
121
+ if let stroll = self.general.stroll, stroll != old.general.stroll { general["stroll"] = stroll }
116
122
  var keys: [String: Any] = [:]
117
123
  if self.general.hotkeys.talk != old.general.hotkeys.talk { keys["talk"] = self.general.hotkeys.talk }
118
124
  if self.general.hotkeys.stop != old.general.hotkeys.stop { keys["stop"] = self.general.hotkeys.stop }
@@ -157,6 +163,17 @@ struct VoiceSettings: Codable, Equatable {
157
163
  min(30, pow(2, Double(max(1, failures))))
158
164
  }
159
165
 
166
+ /// Seconds between reads once the daemon has answered, so a change
167
+ /// made outside the app shows without a restart.
168
+ static let rereadDelay: Double = 5
169
+
170
+ /// Whether a read from the daemon replaces what the app holds: it
171
+ /// differs, and nothing was saved here while it was on its way. A read
172
+ /// that started before a save in the window carries the old settings.
173
+ static func replaces(_ read: VoiceSettings, held: VoiceSettings?, heldWhenAsked: VoiceSettings?) -> Bool {
174
+ held == heldWhenAsked && read != held
175
+ }
176
+
160
177
  /// The fields a preview speaks with: the draft's voice for one agent.
161
178
  func previewVoice(for id: String) -> [String: Any] {
162
179
  guard let v = agents.first(where: { $0.id == id })?.voice else { return [:] }
@@ -35,7 +35,8 @@ final class App: NSObject, NSApplicationDelegate {
35
35
  private var agentHotkeys: [Hotkey] = []
36
36
  private let settingsWindow = SettingsWindow()
37
37
  /// The saved settings: shortcuts and the speech-to-text engine. Read
38
- /// from the daemon at launch and after every save; defaults until then.
38
+ /// from the daemon at launch, every few seconds after that, and after
39
+ /// every save; defaults until then.
39
40
  private var settings: VoiceSettings?
40
41
  /// The agent a per-agent shortcut is asking; nil for the talk key.
41
42
  private var forcedAgent: String?
@@ -213,6 +214,7 @@ final class App: NSObject, NSApplicationDelegate {
213
214
  let asCharacter = saved.general.look == "character"
214
215
  panel.setShowsOrb(!asCharacter)
215
216
  character.setShown(asCharacter)
217
+ character.strolls = saved.general.stroll == true
216
218
  if !asCharacter { panel.detach() }
217
219
  // voice.startReduced is how the assistant starts: read once.
218
220
  if !startApplied {
@@ -234,8 +236,8 @@ final class App: NSObject, NSApplicationDelegate {
234
236
  }
235
237
 
236
238
  /// "Play on this page" (#505): one picture of the character's screen, the
237
- /// lines of text read on it, and the character plays the built-in
238
- /// script on the picture. The page itself is never touched.
239
+ /// lines of text read on it, and the character plays on the picture,
240
+ /// differently each time. The page itself is never touched.
239
241
  private func startPlay() {
240
242
  let foot = character.foot
241
243
  guard canPlay, let screen = NSScreen.screens.first(where: { $0.frame.contains(foot) }) ?? NSScreen.screens.first
@@ -265,9 +267,9 @@ final class App: NSObject, NSApplicationDelegate {
265
267
  // Ended while its text was read, and maybe started again since:
266
268
  // these lines belong to a picture that is gone.
267
269
  guard play.running, play.number == number else { return }
268
- let steps = PlayMath.demo(lines, width: size.width, height: size.height)
270
+ let steps = PlayMath.script(lines, width: size.width, height: size.height, seed: .random(in: 0 ... .max))
269
271
  if steps.isEmpty { play.end("no line of text to play on") }
270
- else { play.play(Play(lines: lines, steps: steps, start: start)) }
272
+ else { play.play(Play(lines: lines, steps: steps, start: start, size: PlayMath.Point(x: size.width, y: size.height))) }
271
273
  }
272
274
  }
273
275
 
@@ -459,14 +461,26 @@ final class App: NSObject, NSApplicationDelegate {
459
461
  }
460
462
  // At login the app can start before the daemon answers. Keep
461
463
  // asking: one missed read left the orb and the built-in
462
- // shortcuts until the app was restarted.
464
+ // shortcuts until the app was restarted. And keep reading once it
465
+ // has answered (#482): a change made in the Terminal or in
466
+ // agentx.json shows without a restart. Not during a play, which
467
+ // has put the character away, and not while the microphone is
468
+ // open: applying registers the shortcuts again, and the release
469
+ // of a held talk key would be lost. The next read applies it.
463
470
  Task { @MainActor in
464
471
  var failures = 0
465
472
  while true {
466
- if let saved = await AgentClient.settings() { apply(saved); break }
467
- failures += 1
468
- if failures == 1 { Log.warn("settings: the daemon did not answer, asking again") }
469
- try? await Task.sleep(for: .seconds(VoiceSettings.retryDelay(after: failures)))
473
+ let asked = settings
474
+ guard let saved = await AgentClient.settings() else {
475
+ failures += 1
476
+ if failures == 1 { Log.warn("settings: the daemon did not answer, asking again") }
477
+ try? await Task.sleep(for: .seconds(VoiceSettings.retryDelay(after: failures)))
478
+ continue
479
+ }
480
+ failures = 0
481
+ if !play.running, !recorder.isRecording,
482
+ VoiceSettings.replaces(saved, held: settings, heldWhenAsked: asked) { apply(saved) }
483
+ try? await Task.sleep(for: .seconds(VoiceSettings.rereadDelay))
470
484
  }
471
485
  }
472
486
 
@@ -1,8 +1,8 @@
1
- import{a as F,b as L,c as U,d as N,e as O,f as H,g as j}from"./chunk-U2CKL755.js";import{b as B,c as D,d as A,e as P,g as M}from"./chunk-IPDEWVVT.js";import"./chunk-XEKZKH3W.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useEffect as R,useReducer as V,useRef as G}from"react";import{Box as i,Text as o,useApp as W,useInput as J}from"ink";import{randomUUID as z}from"crypto";async function*q(e){let r=[];e.type&&r.push(`type=${encodeURIComponent(e.type)}`);let t=`${e.baseUrl.replace(/\/+$/,"")}/events${r.length?`?${r.join("&")}`:""}`,n={Accept:"text/event-stream"};e.token&&(n.Authorization=`Bearer ${e.token}`);let s=await fetch(t,{headers:n,signal:e.signal});if(!s.ok||!s.body)throw new Error(`SSE connect failed: HTTP ${s.status}`);let u=s.body.getReader(),p=new TextDecoder,y="";try{for(;;){let{done:f,value:l}=await u.read();if(f)return;y+=p.decode(l,{stream:!0});let d;for(;(d=y.indexOf(`
1
+ import{a as F,b as L,c as U,d as N,e as O,f as H,g as j}from"./chunk-U2CKL755.js";import{b as B,c as D,d as A,e as P,g as M}from"./chunk-GJ5EJVMZ.js";import"./chunk-JREA25GJ.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useEffect as R,useReducer as V,useRef as G}from"react";import{Box as i,Text as o,useApp as W,useInput as J}from"ink";import{randomUUID as z}from"crypto";async function*q(e){let r=[];e.type&&r.push(`type=${encodeURIComponent(e.type)}`);let t=`${e.baseUrl.replace(/\/+$/,"")}/events${r.length?`?${r.join("&")}`:""}`,n={Accept:"text/event-stream"};e.token&&(n.Authorization=`Bearer ${e.token}`);let s=await fetch(t,{headers:n,signal:e.signal});if(!s.ok||!s.body)throw new Error(`SSE connect failed: HTTP ${s.status}`);let u=s.body.getReader(),p=new TextDecoder,y="";try{for(;;){let{done:f,value:l}=await u.read();if(f)return;y+=p.decode(l,{stream:!0});let d;for(;(d=y.indexOf(`
2
2
 
3
3
  `))>=0;){let h=y.slice(0,d);y=y.slice(d+2);let m=X(h);m&&(yield m)}}}finally{try{u.releaseLock()}catch{}}}function X(e){let r="message",t="";for(let s of e.split(`
4
4
  `))s.startsWith("event: ")?r=s.slice(7):s.startsWith("data: ")&&(t=s.slice(6));if(!t)return null;let n;try{n=JSON.parse(t)}catch{n=t}return{event:r,data:n}}import{jsx as a,jsxs as c}from"react/jsx-runtime";function $(e,r){return r<=0||e<0?0:e>=r?r-1:e}function E(){return`tui:${z().slice(0,12)}`}function k(e,r){let t=[...e,r];return t.length>50&&t.splice(0,t.length-50),t}function Y(e,r){switch(r.type){case"agents":return{...e,agents:r.data,cursor:{...e.cursor,agents:$(e.cursor.agents,r.data.length)}};case"processes":return{...e,processes:r.data,cursor:{...e.cursor,processes:$(e.cursor.processes,r.data.length)}};case"crons":return{...e,crons:r.data};case"event":{let t=[r.row,...e.events];t.length>200&&(t.length=200);let n=e.channels;return r.channelTally&&(n=new Map(e.channels),n.set(r.channelTally.channel,r.channelTally)),{...e,events:t,channels:n}}case"connError":return{...e,connError:r.error};case"tick":return{...e,lastTick:Date.now()};case"focus":return{...e,focus:r.pane};case"cursor":{let t=r.pane==="agents"?e.agents.length:r.pane==="processes"?e.processes.length:e.events.length;return{...e,cursor:{...e.cursor,[r.pane]:$(e.cursor[r.pane]+r.delta,t)}}}case"bottomRight":return{...e,bottomRight:r.pane};case"chatStart":return{...e,chat:{active:!0,agentId:r.agentId,chatId:E(),history:[],text:"",status:"idle",error:null}};case"chatExit":return{...e,chat:{...e.chat,active:!1}};case"chatClear":return{...e,chat:{...e.chat,chatId:E(),history:[],text:"",status:"idle",error:null}};case"chatText":return{...e,chat:{...e.chat,text:r.text}};case"chatSubmitStart":return{...e,chat:{...e.chat,history:k(e.chat.history,r.you),text:"",status:"sending",error:null}};case"chatSubmitDone":return{...e,chat:{...e.chat,history:k(e.chat.history,r.reply),status:"idle",error:null}};case"chatSubmitError":return{...e,chat:{...e.chat,history:k(e.chat.history,{role:"error",text:r.error,at:Date.now()}),status:"idle",error:r.error}};case"chatStreamStart":{let t=k(e.chat.history,r.you),n=k(t,{role:"agent",text:"",at:Date.now(),streaming:!0,tools:[]});return{...e,chat:{...e.chat,history:n,text:"",status:"sending",error:null}}}case"chatStreamDelta":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]={...n,text:n.text+r.text}),{...e,chat:{...e.chat,history:t}}}case"chatStreamThinking":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]={...n,thinking:(n.thinking??"")+r.text}),{...e,chat:{...e.chat,history:t}}}case"chatStreamTool":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]={...n,tools:[...n.tools??[],{name:r.name,arg:r.arg,error:r.error}]}),{...e,chat:{...e.chat,history:t}}}case"chatStreamEnd":{let t=e.chat.history.slice(),n=t[t.length-1];return n?.role==="agent"&&n.streaming&&(t[t.length-1]=r.error?{...n,streaming:!1,role:"error",text:r.error}:{...n,streaming:!1,elapsedMs:r.elapsedMs,outTokens:r.outTokens}),{...e,chat:{...e.chat,history:t,status:"idle",error:r.error??null}}}case"toast":return{...e,toast:{text:r.text,color:r.color,at:Date.now()}};case"clearToast":return{...e,toast:null}}}var _={agents:[],processes:[],crons:[],events:[],channels:new Map,connError:null,lastTick:0,focus:"agents",cursor:{agents:0,processes:0,events:0},bottomRight:"crons",chat:{active:!1,agentId:null,chatId:E(),history:[],text:"",status:"idle",error:null},toast:null};function be({conn:e,pollMs:r=3e3}){let[t,n]=V(Y,_),{exit:s}=W(),u=G(null),p=G(null),y=t.agents.map(l=>l.id),f=t.chat.active?L(t.chat.text,y,process.cwd()):null;return R(()=>{if(!t.toast)return;let l=setTimeout(()=>n({type:"clearToast"}),3500);return()=>clearTimeout(l)},[t.toast]),J((l,d)=>{if(t.chat.active){if(d.escape){n({type:"chatExit"});return}if(d.ctrl&&l==="l"){n({type:"chatClear"});return}if(d.tab){let m=U(t.chat.text,p,y,process.cwd());m!==null&&n({type:"chatText",text:m});return}if(d.backspace||d.delete){p.current=null,n({type:"chatText",text:t.chat.text.slice(0,-1)});return}if(d.ctrl||d.meta)return;let h=N(l??"",d.return,t.chat.text);if(h.kind==="paste"||h.kind==="type"){p.current=null,n({type:"chatText",text:t.chat.text+h.text});return}if(h.kind==="continue"){n({type:"chatText",text:h.buffer});return}if(h.kind==="submit"){let m=h.text.trim(),g=t.chat.agentId;if(!m||!g||t.chat.status==="sending"){n({type:"chatText",text:""});return}p.current=null;let b=Date.now(),w=t.chat.chatId;n({type:"chatStreamStart",you:{role:"you",text:m,at:b}}),(async()=>{try{let C=await M(e,g,m,{channel:"tui",chatId:w,onText:x=>n({type:"chatStreamDelta",text:x}),onThinking:x=>n({type:"chatStreamThinking",text:x}),onTool:x=>{x.status==="start"&&x.name?n({type:"chatStreamTool",name:x.name,arg:x.arg}):x.status==="result"&&x.error&&n({type:"chatStreamTool",name:x.name??"tool",error:!0})}});n({type:"chatStreamEnd",elapsedMs:Date.now()-b,outTokens:C.usage?.outputTokens,error:C.error})}catch(C){n({type:"chatStreamEnd",elapsedMs:Date.now()-b,error:C?.message||String(C)})}})();return}return}if(l==="q"||d.ctrl&&l==="c"){u.current?.abort(),s();return}if(d.tab){let h=["agents","processes","events"],m=h.indexOf(t.focus);n({type:"focus",pane:h[(m+1)%h.length]});return}if(l==="a"){n({type:"focus",pane:"agents"});return}if(l==="p"){n({type:"focus",pane:"processes"});return}if(l==="e"){n({type:"focus",pane:"events"});return}if(l==="c"){n({type:"bottomRight",pane:t.bottomRight==="crons"?"channels":"crons"});return}if(d.upArrow){n({type:"cursor",pane:t.focus,delta:-1});return}if(d.downArrow){n({type:"cursor",pane:t.focus,delta:1});return}if(d.return&&t.focus==="agents"){let h=t.agents[t.cursor.agents];if(!h){n({type:"toast",text:"no agent selected",color:"yellow"});return}n({type:"chatStart",agentId:h.id});return}if(l==="k"&&t.focus==="processes"){let h=t.processes[t.cursor.processes];if(!h){n({type:"toast",text:"no process selected",color:"yellow"});return}(async()=>{try{await P(e,h.key,"tui"),n({type:"toast",text:`killed ${h.key.agentId}/${h.key.channel}/${h.key.chatId}`,color:"green"})}catch(m){n({type:"toast",text:`kill failed: ${m?.message||m}`,color:"red"})}})();return}}),R(()=>{let l=new AbortController;u.current=l;let d=!1,h=async()=>{try{let[g,b,w]=await Promise.all([B(e,l.signal).catch(()=>[]),D(e,l.signal).catch(()=>[]),A(e,l.signal).catch(()=>[])]);if(d)return;n({type:"agents",data:g}),n({type:"processes",data:b}),n({type:"crons",data:w}),n({type:"tick"}),n({type:"connError",error:null})}catch(g){d||n({type:"connError",error:g?.message||String(g)})}};h();let m=setInterval(h,r);return()=>{d=!0,clearInterval(m),l.abort()}},[e.baseUrl,e.token,r]),R(()=>{let l=!1,d=new AbortController,h=new Map;return(async()=>{let m=500;for(;!l;){try{for await(let g of q({baseUrl:e.baseUrl,token:e.token,signal:d.signal})){let b=ae(g),w;if(g.event==="channel"&&typeof g.data?.channel=="string"){let S=h.get(g.data.channel)??{channel:g.data.channel,inbound:0,outbound:0,lastAt:0,lastPreview:""},C=S.inbound+(g.data.direction==="in"?1:0),x=S.outbound+(g.data.direction==="out"?1:0);w={channel:g.data.channel,inbound:C,outbound:x,lastAt:b.at,lastPreview:(g.data.textPreview||"").slice(0,60)},h.set(g.data.channel,w)}n({type:"event",row:b,channelTally:w}),m=500}}catch(g){if(l)return;n({type:"connError",error:`events: ${g?.message||g}`})}await new Promise(g=>setTimeout(g,m)),m=Math.min(m*2,1e4)}})(),()=>{l=!0,d.abort()}},[e.baseUrl,e.token]),c(i,{flexDirection:"column",width:"100%",children:[a(K,{conn:e,lastTick:t.lastTick,connError:t.connError,chat:t.chat}),c(i,{flexDirection:"row",flexGrow:1,children:[c(i,{flexDirection:"column",width:"50%",children:[a(v,{title:"AGENTS",focused:!t.chat.active&&t.focus==="agents",children:a(Z,{rows:t.agents,cursor:t.cursor.agents,focused:!t.chat.active&&t.focus==="agents",talkingTo:t.chat.active?t.chat.agentId:null})}),a(v,{title:"PROCESSES",focused:!t.chat.active&&t.focus==="processes",children:a(ee,{rows:t.processes,cursor:t.cursor.processes,focused:!t.chat.active&&t.focus==="processes"})})]}),t.chat.active?a(oe,{chat:t.chat,suggest:f,agents:t.agents}):c(i,{flexDirection:"column",width:"50%",children:[a(v,{title:"LIVE EVENTS",focused:t.focus==="events",children:a(ne,{rows:t.events,cursor:t.cursor.events,focused:t.focus==="events"})}),a(v,{title:t.bottomRight==="crons"?"CRONS / SCHEDULES":"CHANNELS",focused:!1,children:t.bottomRight==="crons"?a(te,{rows:t.crons}):a(re,{rows:Array.from(t.channels.values())})})]})]}),a(Q,{focus:t.focus,bottomRight:t.bottomRight,chat:t.chat,toast:t.toast})]})}function K({conn:e,lastTick:r,connError:t,chat:n}){let s=t?c(o,{color:"red",children:["\u25CF ",t]}):r===0?a(o,{color:"yellow",children:"\u25CF connecting\u2026"}):a(o,{color:"green",children:"\u25CF live"}),u=n.active?c(o,{color:"green",bold:!0,children:["CHAT @",n.agentId]}):a(o,{bold:!0,children:"agentx tui"});return c(i,{paddingX:1,justifyContent:"space-between",children:[a(i,{children:u}),a(o,{dimColor:!0,children:e.baseUrl}),a(i,{children:s})]})}function Q({focus:e,bottomRight:r,chat:t,toast:n}){let s=t.active?["[Enter] send","[Esc] exit chat","[Ctrl-L] new session"]:[`[Tab/a/p/e] focus (now: ${e})`,e==="agents"?"[Enter] chat":null,e==="processes"?"[k] kill":null,`[c] ${r==="crons"?"\u2192channels":"\u2192crons"}`,"[\u2191/\u2193] move","[q] quit"].filter(Boolean);return c(i,{paddingX:1,borderStyle:"single",borderTop:!0,borderBottom:!1,borderLeft:!1,borderRight:!1,justifyContent:"space-between",children:[a(o,{dimColor:!0,children:s.join(" \xB7 ")}),n?a(o,{color:n.color,children:n.text}):a(o,{children:" "})]})}function v({title:e,focused:r,children:t}){return c(i,{flexDirection:"column",width:"100%",borderStyle:r?"double":"single",borderColor:r?"cyan":void 0,paddingX:1,children:[c(o,{bold:!0,color:r?"cyan":"white",children:[e,r?" \u25CF":""]}),a(i,{flexDirection:"column",marginTop:1,children:t})]})}function I(e,r){return e&&r?{inverse:!0}:{}}function Z({rows:e,cursor:r,focused:t,talkingTo:n}){return e.length===0?a(o,{dimColor:!0,children:"no agents"}):a(i,{flexDirection:"column",children:e.slice(0,12).map((s,u)=>{let p=I(t,u===r),y=s.errors>0?"red":s.active>0?"yellow":"green",f=s.id===n;return c(i,{children:[a(o,{...p,color:y,children:"\u25CF"}),c(o,{...p,children:[" ",T(s.name,14)]}),c(o,{...p,children:[T(s.tier,6)," "]}),c(o,{...p,children:[s.active,"/",s.total]}),s.errors>0?c(o,{...p,color:"red",children:[" err=",s.errors]}):null,f?a(o,{color:"green",children:" \u2194 chatting"}):null]},s.id)})})}function ee({rows:e,cursor:r,focused:t}){if(e.length===0)return a(o,{dimColor:!0,children:"no live processes"});let n=Date.now();return a(i,{flexDirection:"column",children:e.slice(0,12).map((s,u)=>{let p=I(t,u===r),y=Math.max(0,Math.round((n-(s.lastTurnAt||s.spawnedAt))/1e3)),f=s.state==="dead"?"red":s.state==="warm-hot"?"green":"yellow";return c(i,{children:[a(o,{...p,color:f,children:T(s.state,10)}),a(o,{...p,children:T(s.key.agentId,12)}),a(o,{...p,children:T(s.key.channel,10)}),c(o,{...p,children:[s.turnCount,"t ",y,"s"]})]},`${s.key.agentId}-${s.key.channel}-${s.key.chatId}-${u}`)})})}function te({rows:e}){return e.length===0?a(o,{dimColor:!0,children:"no crons"}):a(i,{flexDirection:"column",children:e.slice(0,12).map(r=>{let t=r.enabled?r.consecutiveErrors>0?a(o,{color:"red",children:"err"}):a(o,{color:"green",children:"ok"}):a(o,{dimColor:!0,children:"off"}),n=r.nextRun?new Date(r.nextRun).toLocaleTimeString():"\u2014";return c(i,{children:[a(o,{children:T(r.id,16)}),a(o,{dimColor:!0,children:T(r.schedule,12)}),a(o,{children:T(n,10)}),a(i,{children:t})]},r.id)})})}function re({rows:e}){if(e.length===0)return a(o,{dimColor:!0,children:"(waiting for channel events\u2026)"});let r=[...e].sort((t,n)=>n.lastAt-t.lastAt);return a(i,{flexDirection:"column",children:r.slice(0,12).map(t=>c(i,{children:[a(o,{children:T(t.channel,12)}),c(o,{color:"cyan",children:["\u2190",T(String(t.inbound),4)]}),c(o,{color:"magenta",children:["\u2192",T(String(t.outbound),4)]}),a(o,{dimColor:!0,children:t.lastPreview})]},t.channel))})}function ne({rows:e,cursor:r,focused:t}){return e.length===0?a(o,{dimColor:!0,children:"(waiting for events\u2026)"}):a(i,{flexDirection:"column",children:e.slice(0,18).map((n,s)=>{let u=I(t,s===r);return c(i,{children:[a(o,{...u,dimColor:!0,children:new Date(n.at).toLocaleTimeString().padEnd(10)}),a(o,{...u,color:ce(n.kind),children:T(n.kind,8)}),a(o,{...u,children:n.line})]},`${n.at}-${s}`)})})}function oe({chat:e,suggest:r,agents:t}){let n=e.history.slice(-14),s=t.find(f=>f.id===e.agentId),u=H(s?.tier??"",s?.model),p=e.status==="sending"?[...e.history].reverse().find(f=>f.role==="agent"&&f.streaming):void 0,y=e.status==="sending"?a(O,{startedAt:p?.at??Date.now(),phase:p?.text?"responding":"thinking",indent:""}):e.error?c(o,{color:"red",children:["\u25CF ",e.error]}):a(o,{dimColor:!0,children:"\u25CF ready"});return c(i,{flexDirection:"column",width:"50%",borderStyle:"double",borderColor:"green",paddingX:1,children:[c(i,{justifyContent:"space-between",children:[c(o,{bold:!0,color:"green",children:["CHAT \xB7 @",e.agentId]}),a(i,{children:y})]}),c(o,{children:[c(o,{color:u.color,bold:!0,children:[u.glyph," ",u.label]}),s?.model?c(o,{dimColor:!0,children:[" ",j(s.model)]}):null,c(o,{dimColor:!0,children:[" \xB7 ",e.chatId]})]}),a(i,{flexDirection:"column",flexGrow:1,marginTop:1,children:n.length===0?a(o,{dimColor:!0,children:"(type a message and press Enter \u2014 Esc exits, Ctrl-L starts fresh)"}):n.map((f,l)=>a(se,{turn:f,agentId:e.agentId},`${f.at}-${l}`))}),r?c(o,{dimColor:!0,children:[a(o,{color:"cyan",children:"\u21B9"})," ",r.items.slice(0,5).map((f,l)=>l===0?a(o,{color:"cyan",children:f},l):c(o,{children:[" ",f]},l))]}):null,c(i,{children:[a(o,{color:"cyan",children:"you \u203A "}),a(o,{children:e.text}),a(o,{inverse:!0,children:" "})]})]})}function se({turn:e,agentId:r}){if(e.role==="you")return c(i,{flexDirection:"column",marginBottom:1,children:[a(o,{color:"cyan",children:"you"}),e.text.split(`
5
5
  `).map((s,u)=>c(o,{children:[" ",s]},u))]});if(e.role==="error")return c(i,{flexDirection:"column",marginBottom:1,children:[a(o,{color:"red",children:"error"}),c(o,{color:"red",children:[" ",e.text]})]});let t=e.elapsedMs!=null?` \xB7 ${(e.elapsedMs/1e3).toFixed(1)}s${e.outTokens!=null?`, ${e.outTokens} tok`:""}`:e.streaming?" \xB7 \u2026":"",n=F(e.text,58,{balance:e.streaming});return c(i,{flexDirection:"column",marginBottom:1,children:[c(o,{color:"green",children:["@",r??"agent",a(o,{dimColor:!0,children:t})]}),e.thinking?e.thinking.split(`
6
6
  `).filter(s=>s.trim()).slice(-2).map((s,u)=>c(o,{dimColor:!0,italic:!0,children:[" ",s]},`th${u}`)):null,(e.tools??[]).map((s,u)=>c(o,{color:s.error?"red":"green",children:[" \u25CF ",c(o,{bold:!s.error,dimColor:s.error,children:[s.name,s.arg?c(o,{dimColor:!0,children:["(",s.arg,")"]}):null,s.error?" failed":""]})]},`tool${u}`)),n.split(`
7
7
  `).slice(0,14).map((s,u)=>c(o,{children:[" ",s]},u))]})}function ae(e){let r=e.data??{},t=typeof r.at=="string"||typeof r.at=="number"?new Date(r.at).getTime():Date.now(),n="";switch(e.event){case"run":n=`${r.phase??""} ${r.workflowId??""} ${(r.runId??"").slice(0,8)} ${r.nodeId??""}`.trim();break;case"task":n=`${r.phase??""} ${r.workflowId??""} ${Array.isArray(r.assignedTo)?r.assignedTo.join(","):""} ${r.title?`"${r.title}"`:""}`.trim();break;case"signal":n=`${r.name??""} (${r.scope??""}) ${r.workflowId??""}`.trim();break;case"mesh":n=`${r.peer??""} ${r.healthy?"healthy":"lost"} ${r.delta??""}`.trim();break;case"channel":{n=`${r.direction==="in"?"\u2190":"\u2192"} ${r.channel??""}:${r.chatId??""} ${r.textPreview??""}`.trim();break}case"status":n=`node=${r.node??""} agents=${r.agents??0} active=${(r.active??[]).length}`;break;default:n=typeof r=="string"?r:JSON.stringify(r).slice(0,80)}return{at:Number.isFinite(t)?t:Date.now(),kind:e.event,line:n}}function ce(e){switch(e){case"run":return"cyan";case"task":return"magenta";case"signal":return"green";case"mesh":return"blue";case"channel":return"yellow";default:return"white"}}function T(e,r){let t=(e??"").toString();return t.length>=r?t.slice(0,r-1)+" ":t+" ".repeat(r-t.length)}export{be as App};
8
- //# sourceMappingURL=App-UHSIO3UE.js.map
8
+ //# sourceMappingURL=App-XLQDP26J.js.map
@@ -1,7 +1,7 @@
1
- import{a as Y,b as Z,c as _,d as ee,e as te,f as ne,g as re}from"./chunk-U2CKL755.js";import{b as Q,g as X}from"./chunk-IPDEWVVT.js";import"./chunk-XEKZKH3W.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useCallback as oe,useMemo as H,useRef as P,useState as k}from"react";import{Box as g,Text as t,useApp as he,useInput as xe,useStdout as Te}from"ink";import{randomUUID as se}from"crypto";var m={accent:"cyan",agent:"green",working:"magenta",error:"red",muted:"gray"},q="\u25C7 agentx",F="\u258C";import{jsx as c,jsxs as o}from"react/jsx-runtime";var ie="/help /agent <id> /agents /clear /who /exit",be=[{cmd:"/agent",desc:"switch the target agent (/agent <id>)"},{cmd:"/agents",desc:"list registered agents"},{cmd:"/clear",desc:"start a fresh session"},{cmd:"/who",desc:"show agent + chat id"},{cmd:"/help",desc:"list commands"},{cmd:"/exit",desc:"quit the chat"}];function Pe({conn:n,agentId:p,channel:f,chatId:a,agents:h}){let{exit:w}=he(),{stdout:O}=Te(),V=Math.max(40,Math.min((O?.columns||80)-4,100)),[z,U]=k([]),[$,S]=k(null),[T,le]=k(p),[A,ae]=k(h),[E,ue]=k(a),[y,x]=k(""),[J,de]=k(""),W=P([]),u=P(-1),M=P(null),R=P(null),v=$?.live??!1,j=H(()=>Z(y,A.map(s=>s.id),process.cwd()),[y,A]),N=H(()=>{let s=/^\/(\w*)$/.exec(y);if(!s)return null;let e=be.filter(r=>r.cmd.slice(1).startsWith(s[1].toLowerCase()));return e.length?e:null},[y]),b=s=>de(s),K=oe(s=>{let e=se().slice(0,8),r=Date.now(),i=new AbortController;R.current=i;let d={id:e,you:s,agentId:T,segs:[],live:!0,startedAt:r};S({...d});let L=()=>S({...d,segs:d.segs.map(C=>({...C}))});(async()=>{try{let C=await X(n,T,s,{channel:f,chatId:E,signal:i.signal,onText:l=>{let I=d.segs[d.segs.length-1];I&&I.type==="text"?I.content=(I.content??"")+l:d.segs.push({type:"text",content:l}),L()},onThinking:l=>{d.thinking=(d.thinking??"")+l,L()},onTool:l=>{l.status==="start"&&l.name?(d.segs.push({type:"tool",name:l.name,arg:l.arg}),L()):l.status==="result"&&l.error&&(d.segs.push({type:"tool",name:l.name??"tool",error:!0}),L())}});U(l=>[...l,{...d,live:!1,elapsedMs:Date.now()-r,outTokens:C.usage?.outputTokens,error:C.error}]),S(null)}catch(C){let l=i.signal.aborted||C?.name==="AbortError";U(I=>[...I,{...d,live:!1,elapsedMs:Date.now()-r,interrupted:l,error:l?void 0:C?.message||String(C)}]),S(null)}finally{R.current===i&&(R.current=null)}})()},[n,T,f,E]),me=oe(s=>{let e=s.trim();if(e){if(W.current.push(e),u.current=-1,e==="/exit"||e==="/quit"){w();return}if(e==="/help"){b(ie);return}if(e==="/who"){b(`@${T} \xB7 chatId=${E} \xB7 channel=${f}`);return}if(e==="/clear"){let r=`chat-cli:${se().slice(0,12)}`;ue(r),U([]),b(`fresh chatId=${r} (warm process dropped)`);return}if(e==="/agents"){Q(n).then(r=>{ae(r),b(r.map(i=>i.id===T?`[${i.id}]`:i.id).join(" "))}).catch(r=>b(`failed to list agents: ${r?.message||r}`));return}if(e.startsWith("/agent ")){let r=e.slice(7).replace(/^@/,"").trim();if(!r){b("usage: /agent <id>");return}if(!A.find(i=>i.id===r)){b(`unknown agent: @${r}`);return}le(r),b(`now talking to @${r}`);return}if(e.startsWith("/")){b(`unknown command \xB7 ${ie}`);return}K(e)}},[n,T,A,f,E,w,K]);xe((s,e)=>{if(e.ctrl&&s==="c"){w();return}if(e.escape){if(v&&R.current){R.current.abort();return}w();return}if(e.tab){if(N){x(N[0].cmd+" ");return}let i=_(y,M,A.map(d=>d.id),process.cwd());i!==null&&(x(i),u.current=-1);return}if(e.upArrow){let i=W.current;if(!i.length)return;u.current=u.current<0?i.length-1:Math.max(0,u.current-1),x(i[u.current]??"");return}if(e.downArrow){let i=W.current;if(u.current<0)return;if(u.current=u.current+1,u.current>=i.length){u.current=-1,x("");return}x(i[u.current]??"");return}if(e.backspace||e.delete){M.current=null,x(i=>i.slice(0,-1));return}if(e.ctrl||e.meta)return;let r=ee(s??"",e.return,y);switch(r.kind){case"paste":M.current=null,x(i=>i+r.text),u.current=-1;return;case"type":M.current=null,x(i=>i+r.text),u.current=-1;return;case"continue":x(r.buffer);return;case"submit":if(v)return;M.current=null,x(""),me(r.text);return;case"none":return}});let G=v?m.working:m.accent,ge=y.length?y.split(`
1
+ import{a as Y,b as Z,c as _,d as ee,e as te,f as ne,g as re}from"./chunk-U2CKL755.js";import{b as Q,g as X}from"./chunk-GJ5EJVMZ.js";import"./chunk-JREA25GJ.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useCallback as oe,useMemo as H,useRef as P,useState as k}from"react";import{Box as g,Text as t,useApp as he,useInput as xe,useStdout as Te}from"ink";import{randomUUID as se}from"crypto";var m={accent:"cyan",agent:"green",working:"magenta",error:"red",muted:"gray"},q="\u25C7 agentx",F="\u258C";import{jsx as c,jsxs as o}from"react/jsx-runtime";var ie="/help /agent <id> /agents /clear /who /exit",be=[{cmd:"/agent",desc:"switch the target agent (/agent <id>)"},{cmd:"/agents",desc:"list registered agents"},{cmd:"/clear",desc:"start a fresh session"},{cmd:"/who",desc:"show agent + chat id"},{cmd:"/help",desc:"list commands"},{cmd:"/exit",desc:"quit the chat"}];function Pe({conn:n,agentId:p,channel:f,chatId:a,agents:h}){let{exit:w}=he(),{stdout:O}=Te(),V=Math.max(40,Math.min((O?.columns||80)-4,100)),[z,U]=k([]),[$,S]=k(null),[T,le]=k(p),[A,ae]=k(h),[E,ue]=k(a),[y,x]=k(""),[J,de]=k(""),W=P([]),u=P(-1),M=P(null),R=P(null),v=$?.live??!1,j=H(()=>Z(y,A.map(s=>s.id),process.cwd()),[y,A]),N=H(()=>{let s=/^\/(\w*)$/.exec(y);if(!s)return null;let e=be.filter(r=>r.cmd.slice(1).startsWith(s[1].toLowerCase()));return e.length?e:null},[y]),b=s=>de(s),K=oe(s=>{let e=se().slice(0,8),r=Date.now(),i=new AbortController;R.current=i;let d={id:e,you:s,agentId:T,segs:[],live:!0,startedAt:r};S({...d});let L=()=>S({...d,segs:d.segs.map(C=>({...C}))});(async()=>{try{let C=await X(n,T,s,{channel:f,chatId:E,signal:i.signal,onText:l=>{let I=d.segs[d.segs.length-1];I&&I.type==="text"?I.content=(I.content??"")+l:d.segs.push({type:"text",content:l}),L()},onThinking:l=>{d.thinking=(d.thinking??"")+l,L()},onTool:l=>{l.status==="start"&&l.name?(d.segs.push({type:"tool",name:l.name,arg:l.arg}),L()):l.status==="result"&&l.error&&(d.segs.push({type:"tool",name:l.name??"tool",error:!0}),L())}});U(l=>[...l,{...d,live:!1,elapsedMs:Date.now()-r,outTokens:C.usage?.outputTokens,error:C.error}]),S(null)}catch(C){let l=i.signal.aborted||C?.name==="AbortError";U(I=>[...I,{...d,live:!1,elapsedMs:Date.now()-r,interrupted:l,error:l?void 0:C?.message||String(C)}]),S(null)}finally{R.current===i&&(R.current=null)}})()},[n,T,f,E]),me=oe(s=>{let e=s.trim();if(e){if(W.current.push(e),u.current=-1,e==="/exit"||e==="/quit"){w();return}if(e==="/help"){b(ie);return}if(e==="/who"){b(`@${T} \xB7 chatId=${E} \xB7 channel=${f}`);return}if(e==="/clear"){let r=`chat-cli:${se().slice(0,12)}`;ue(r),U([]),b(`fresh chatId=${r} (warm process dropped)`);return}if(e==="/agents"){Q(n).then(r=>{ae(r),b(r.map(i=>i.id===T?`[${i.id}]`:i.id).join(" "))}).catch(r=>b(`failed to list agents: ${r?.message||r}`));return}if(e.startsWith("/agent ")){let r=e.slice(7).replace(/^@/,"").trim();if(!r){b("usage: /agent <id>");return}if(!A.find(i=>i.id===r)){b(`unknown agent: @${r}`);return}le(r),b(`now talking to @${r}`);return}if(e.startsWith("/")){b(`unknown command \xB7 ${ie}`);return}K(e)}},[n,T,A,f,E,w,K]);xe((s,e)=>{if(e.ctrl&&s==="c"){w();return}if(e.escape){if(v&&R.current){R.current.abort();return}w();return}if(e.tab){if(N){x(N[0].cmd+" ");return}let i=_(y,M,A.map(d=>d.id),process.cwd());i!==null&&(x(i),u.current=-1);return}if(e.upArrow){let i=W.current;if(!i.length)return;u.current=u.current<0?i.length-1:Math.max(0,u.current-1),x(i[u.current]??"");return}if(e.downArrow){let i=W.current;if(u.current<0)return;if(u.current=u.current+1,u.current>=i.length){u.current=-1,x("");return}x(i[u.current]??"");return}if(e.backspace||e.delete){M.current=null,x(i=>i.slice(0,-1));return}if(e.ctrl||e.meta)return;let r=ee(s??"",e.return,y);switch(r.kind){case"paste":M.current=null,x(i=>i+r.text),u.current=-1;return;case"type":M.current=null,x(i=>i+r.text),u.current=-1;return;case"continue":x(r.buffer);return;case"submit":if(v)return;M.current=null,x(""),me(r.text);return;case"none":return}});let G=v?m.working:m.accent,ge=y.length?y.split(`
2
2
  `):[""],B=A.find(s=>s.id===T),D=ne(B?.tier??"",B?.model),pe=O?.rows||24,fe=z.slice(-40);return o(g,{flexDirection:"column",height:pe,children:[o(g,{flexDirection:"column",flexGrow:1,justifyContent:"flex-end",overflow:"hidden",children:[z.length===0&&!$?o(g,{flexDirection:"column",children:[o(t,{children:[c(t,{color:m.accent,bold:!0,children:q}),c(t,{dimColor:!0,children:" \u2014 chat with "}),o(t,{color:m.accent,children:["@",T]}),c(t,{dimColor:!0,children:" via "}),o(t,{color:D.color,bold:!0,children:[D.glyph," ",D.label]}),B?.model?o(t,{dimColor:!0,children:[" (",B.model,")"]}):null]}),c(t,{dimColor:!0,children:"streaming \xB7 markdown \xB7 tools \xB7 type a message, or / for commands"})]}):null,fe.map(s=>c(ce,{turn:s,width:V},s.id)),$?c(ce,{turn:$,width:V}):null]}),N?c(g,{flexDirection:"column",marginTop:1,children:N.map((s,e)=>o(g,{children:[c(t,{color:e===0?m.accent:m.muted,bold:e===0,children:s.cmd.padEnd(10)}),c(t,{dimColor:!0,children:s.desc})]},s.cmd))}):j?o(g,{marginTop:1,children:[c(t,{color:m.accent,children:"\u21B9 "}),j.items.map((s,e)=>o(t,{color:e===0?m.accent:m.muted,children:[s,e<j.items.length-1?" ":""]},e))]}):J?c(g,{marginTop:1,children:c(t,{dimColor:!0,children:J})}):null,c(g,{borderStyle:"single",borderColor:G,borderLeft:!1,borderRight:!1,borderDimColor:!v,width:"100%",children:c(g,{flexDirection:"column",width:"100%",children:ge.map((s,e,r)=>o(g,{children:[c(t,{color:G,bold:!0,children:e===0?"\u203A ":" "}),c(t,{children:s}),e===r.length-1&&!v?c(t,{color:G,children:"\u258F"}):null]},e))})}),o(g,{justifyContent:"space-between",children:[o(t,{children:[c(t,{color:m.accent,bold:!0,children:q}),o(t,{dimColor:!0,children:[" \xB7 @",T," \xB7 "]}),o(t,{color:D.color,bold:!0,children:[D.glyph," ",D.label]}),B?.model?o(t,{dimColor:!0,children:[" ",re(B.model)]}):null]}),o(t,{dimColor:!0,children:["\u21B5 send / cmds @ mention esc ",v?"stop":"exit"]})]})]})}function ce({turn:n,width:p}){let f=H(()=>ye(n,p),[n,p]),a=n.segs.some(h=>h.type==="text"&&h.content);return o(g,{flexDirection:"column",marginBottom:1,children:[o(t,{color:m.accent,bold:!0,children:[F," you"]}),n.you.split(`
3
3
  `).map((h,w)=>o(t,{color:"white",children:[" ",h]},`u${w}`)),o(t,{color:m.agent,bold:!0,children:[F," ",n.agentId??"agent"]}),n.thinking?c(g,{flexDirection:"column",children:we(n.thinking,n.live?3:2).map((h,w)=>o(t,{dimColor:!0,italic:!0,children:[" ",h]},`th${w}`))}):null,f,n.live?c(te,{startedAt:n.startedAt,phase:a?"responding":"thinking",hint:"esc to interrupt"}):n.interrupted?o(t,{dimColor:!0,children:[" \u2298 interrupted \xB7 ",(n.elapsedMs/1e3).toFixed(1),"s"]}):n.error?o(t,{color:"red",children:[" \u2717 ",n.error]}):n.elapsedMs!=null?o(t,{dimColor:!0,children:[" \xB7 ",(n.elapsedMs/1e3).toFixed(1),"s",n.outTokens!=null?`, ${n.outTokens} tok`:""]}):null]})}function we(n,p){return n.split(`
4
4
  `).filter(a=>a.trim()).slice(-p)}function ye(n,p){let f=[];return n.segs.forEach((a,h)=>{a.type==="tool"?f.push(o(t,{color:a.error?"red":"green",children:[" ","\u25CF ",o(t,{bold:!a.error,dimColor:a.error,children:[a.name,a.arg?o(t,{dimColor:!0,children:["(",a.arg,")"]}):null,a.error?" failed":""]})]},h)):a.content&&f.push(c(t,{children:Ce(Y(a.content,p,{balance:n.live}))},h))}),f}function Ce(n){return n.split(`
5
5
  `).map(p=>p.length?" "+p:p).join(`
6
6
  `)}export{Pe as ChatApp};
7
- //# sourceMappingURL=ChatApp-LLTFBLJY.js.map
7
+ //# sourceMappingURL=ChatApp-DRDUXZ66.js.map
@@ -1,2 +1,2 @@
1
- import{A as a,B as b,C as c}from"./chunk-QZIEYDIY.js";import"./chunk-SFQUP3BP.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import"./chunk-QIJLFPWE.js";export{a as createAgentContext,b as generate,c as generateStream};
2
- //# sourceMappingURL=agent-6RJ633MQ.js.map
1
+ import{A as a,B as b,C as c}from"./chunk-OFVMUBIP.js";import"./chunk-SFQUP3BP.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import"./chunk-QIJLFPWE.js";export{a as createAgentContext,b as generate,c as generateStream};
2
+ //# sourceMappingURL=agent-QHM3J2XS.js.map