agentix-cli 0.34.0 → 0.35.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 (88) hide show
  1. package/apps/mac-helper/Sources/AgentXHelper/Presence.swift +266 -0
  2. package/apps/mac-helper/Sources/AgentXHelper/main.swift +7 -1
  3. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +6 -1
  4. package/apps/mac-voice/Sources/AgentXVoice/main.swift +3 -0
  5. package/dist/{App-QHPZXA42.js → App-K5J52F7O.js} +2 -2
  6. package/dist/{ChatApp-EAHHH365.js → ChatApp-LRRAPZH7.js} +2 -2
  7. package/dist/{agent-KBBO7OZS.js → agent-XEXAYH5J.js} +2 -2
  8. package/dist/{board-dashboard-74OLMLAD.js → board-dashboard-CBOESBMD.js} +4 -4
  9. package/dist/{chunk-X6HLI6XB.js → chunk-3PL3WLIR.js} +2 -2
  10. package/dist/{chunk-JDC35PWM.js → chunk-3TNK7VGH.js} +2 -2
  11. package/dist/{chunk-ZMFUBIEQ.js → chunk-4QNZI4WE.js} +5 -5
  12. package/dist/{chunk-33G4TIZT.js → chunk-DXXWYYZI.js} +204 -187
  13. package/dist/chunk-DXXWYYZI.js.map +1 -0
  14. package/dist/{chunk-5H5L75RN.js → chunk-FLNN3KSX.js} +2 -2
  15. package/dist/{chunk-PG7BAZIZ.js → chunk-GYBYKREN.js} +2 -2
  16. package/dist/{chunk-6WGTLDME.js → chunk-HPY6OOFO.js} +137 -146
  17. package/dist/chunk-HPY6OOFO.js.map +1 -0
  18. package/dist/{chunk-IUNCX6BG.js → chunk-JSZRGMSA.js} +2 -2
  19. package/dist/chunk-LA6AKS4N.js +13 -0
  20. package/dist/chunk-LA6AKS4N.js.map +1 -0
  21. package/dist/{chunk-UJF5JUFJ.js → chunk-LLKILWWO.js} +2 -2
  22. package/dist/{chunk-QXAUKNMW.js → chunk-LQFEH3SA.js} +2 -2
  23. package/dist/{chunk-MJYE5ADH.js → chunk-PBVEYPZB.js} +2 -2
  24. package/dist/{chunk-U5P7XGCB.js → chunk-SYJUZ3F2.js} +2 -2
  25. package/dist/{chunk-QKNAGTJK.js → chunk-WEN2P4RS.js} +2 -2
  26. package/dist/{chunk-CY24RXE4.js → chunk-WRBW4A2U.js} +2 -2
  27. package/dist/{chunk-IVAGDL5M.js → chunk-ZSNTLADV.js} +2 -2
  28. package/dist/cli.js +1 -1
  29. package/dist/client-APAWETTA.js +2 -0
  30. package/dist/config-S3VHHVYW.js +2 -0
  31. package/dist/config-mutator-5B2YWZMK.js +2 -0
  32. package/dist/doctor-SCECRUJ7.js +2 -0
  33. package/dist/index.d.ts +84 -0
  34. package/dist/index.js +1 -1
  35. package/dist/program-XJEQAWN3.js +2 -0
  36. package/dist/query-EDW72Q4O.js +2 -0
  37. package/dist/{registry-3RN7I6YW.js → registry-GWN34G4J.js} +2 -2
  38. package/dist/{request-planner-JX7M3PTD.js → request-planner-V7T6BQU7.js} +2 -2
  39. package/dist/{review-candidates-UTS4RX4U.js → review-candidates-7QKNMRGU.js} +2 -2
  40. package/dist/{routing-D7APOAP6.js → routing-BHQXFUSH.js} +2 -2
  41. package/dist/scheduler-LY4RBPB6.js +2 -0
  42. package/dist/{seat-UA2ROH3V.js → seat-U57NWHKC.js} +2 -2
  43. package/dist/{select-WQXHYEPD.js → select-JL3JJJP4.js} +2 -2
  44. package/dist/wiki-AQ4K3F7V.js +2 -0
  45. package/package.json +1 -1
  46. package/dist/chunk-33G4TIZT.js.map +0 -1
  47. package/dist/chunk-6WGTLDME.js.map +0 -1
  48. package/dist/chunk-SPJWXIAV.js +0 -13
  49. package/dist/chunk-SPJWXIAV.js.map +0 -1
  50. package/dist/client-CAGQYJML.js +0 -2
  51. package/dist/config-NPLE42XY.js +0 -2
  52. package/dist/config-mutator-FFTODESU.js +0 -2
  53. package/dist/doctor-X4KHQFRF.js +0 -2
  54. package/dist/program-ISXECD4J.js +0 -2
  55. package/dist/query-XLJ6I34S.js +0 -2
  56. package/dist/scheduler-EGR5AJAQ.js +0 -2
  57. package/dist/wiki-RNANPNUX.js +0 -2
  58. /package/dist/{App-QHPZXA42.js.map → App-K5J52F7O.js.map} +0 -0
  59. /package/dist/{ChatApp-EAHHH365.js.map → ChatApp-LRRAPZH7.js.map} +0 -0
  60. /package/dist/{agent-KBBO7OZS.js.map → agent-XEXAYH5J.js.map} +0 -0
  61. /package/dist/{board-dashboard-74OLMLAD.js.map → board-dashboard-CBOESBMD.js.map} +0 -0
  62. /package/dist/{chunk-X6HLI6XB.js.map → chunk-3PL3WLIR.js.map} +0 -0
  63. /package/dist/{chunk-JDC35PWM.js.map → chunk-3TNK7VGH.js.map} +0 -0
  64. /package/dist/{chunk-ZMFUBIEQ.js.map → chunk-4QNZI4WE.js.map} +0 -0
  65. /package/dist/{chunk-5H5L75RN.js.map → chunk-FLNN3KSX.js.map} +0 -0
  66. /package/dist/{chunk-PG7BAZIZ.js.map → chunk-GYBYKREN.js.map} +0 -0
  67. /package/dist/{chunk-IUNCX6BG.js.map → chunk-JSZRGMSA.js.map} +0 -0
  68. /package/dist/{chunk-UJF5JUFJ.js.map → chunk-LLKILWWO.js.map} +0 -0
  69. /package/dist/{chunk-QXAUKNMW.js.map → chunk-LQFEH3SA.js.map} +0 -0
  70. /package/dist/{chunk-MJYE5ADH.js.map → chunk-PBVEYPZB.js.map} +0 -0
  71. /package/dist/{chunk-U5P7XGCB.js.map → chunk-SYJUZ3F2.js.map} +0 -0
  72. /package/dist/{chunk-QKNAGTJK.js.map → chunk-WEN2P4RS.js.map} +0 -0
  73. /package/dist/{chunk-CY24RXE4.js.map → chunk-WRBW4A2U.js.map} +0 -0
  74. /package/dist/{chunk-IVAGDL5M.js.map → chunk-ZSNTLADV.js.map} +0 -0
  75. /package/dist/{client-CAGQYJML.js.map → client-APAWETTA.js.map} +0 -0
  76. /package/dist/{config-NPLE42XY.js.map → config-S3VHHVYW.js.map} +0 -0
  77. /package/dist/{config-mutator-FFTODESU.js.map → config-mutator-5B2YWZMK.js.map} +0 -0
  78. /package/dist/{doctor-X4KHQFRF.js.map → doctor-SCECRUJ7.js.map} +0 -0
  79. /package/dist/{program-ISXECD4J.js.map → program-XJEQAWN3.js.map} +0 -0
  80. /package/dist/{query-XLJ6I34S.js.map → query-EDW72Q4O.js.map} +0 -0
  81. /package/dist/{registry-3RN7I6YW.js.map → registry-GWN34G4J.js.map} +0 -0
  82. /package/dist/{request-planner-JX7M3PTD.js.map → request-planner-V7T6BQU7.js.map} +0 -0
  83. /package/dist/{review-candidates-UTS4RX4U.js.map → review-candidates-7QKNMRGU.js.map} +0 -0
  84. /package/dist/{routing-D7APOAP6.js.map → routing-BHQXFUSH.js.map} +0 -0
  85. /package/dist/{scheduler-EGR5AJAQ.js.map → scheduler-LY4RBPB6.js.map} +0 -0
  86. /package/dist/{seat-UA2ROH3V.js.map → seat-U57NWHKC.js.map} +0 -0
  87. /package/dist/{select-WQXHYEPD.js.map → select-JL3JJJP4.js.map} +0 -0
  88. /package/dist/{wiki-RNANPNUX.js.map → wiki-AQ4K3F7V.js.map} +0 -0
@@ -0,0 +1,266 @@
1
+ import AppKit
2
+
3
+ /// An agent's own cursor on screen: its colour, its initial, its name.
4
+ ///
5
+ /// Drawn, never driven. `point` moves the person's real mouse, which is
6
+ /// right for a lesson the person watches and wrong for one they take part
7
+ /// in — their hand is on that mouse. This cursor is a click-through window
8
+ /// that glides to what the agent means, highlights it, and says a line in
9
+ /// a bubble, while the real pointer stays exactly where the person left it.
10
+ ///
11
+ /// Driven over stdin, one JSON object per line, like the HUD:
12
+ ///
13
+ /// {"cmd":"move","x":120,"y":80,"w":90,"h":24,"highlight":true}
14
+ /// {"cmd":"say","text":"The export button is top right."}
15
+ /// {"cmd":"clear"} drop the highlight
16
+ /// {"cmd":"park"} rest in the bottom-right corner, no highlight
17
+ ///
18
+ /// Coordinates are accessibility coordinates (top-left origin, global),
19
+ /// the same as `read`, `ocr` and `point`. EOF fades everything out.
20
+ enum Presence {
21
+
22
+ // MARK: Geometry
23
+
24
+ /// Accessibility → AppKit. Global AX coordinates are measured from the
25
+ /// top of the PRIMARY display, whichever screen the point is on.
26
+ static func toAppKit(_ p: CGPoint) -> CGPoint {
27
+ let h = NSScreen.screens.first?.frame.maxY ?? 0
28
+ return CGPoint(x: p.x, y: h - p.y)
29
+ }
30
+
31
+ static func toAppKit(_ r: CGRect) -> CGRect {
32
+ let o = toAppKit(CGPoint(x: r.minX, y: r.maxY))
33
+ return CGRect(x: o.x, y: o.y, width: r.width, height: r.height)
34
+ }
35
+
36
+ // MARK: Windows
37
+
38
+ private static func panel(_ rect: NSRect) -> NSPanel {
39
+ let p = NSPanel(contentRect: rect, styleMask: [.borderless, .nonactivatingPanel],
40
+ backing: .buffered, defer: false)
41
+ p.level = .screenSaver
42
+ p.isOpaque = false
43
+ p.backgroundColor = .clear
44
+ p.hasShadow = false
45
+ // Click-through: the person's clicks land on the app underneath.
46
+ p.ignoresMouseEvents = true
47
+ p.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .stationary]
48
+ return p
49
+ }
50
+
51
+ /// The arrow, the initial badge, the name, and the speech bubble.
52
+ private final class AvatarView: NSView {
53
+ let color: NSColor
54
+ let initial: String
55
+ let name: String
56
+ let bubble = NSTextField(wrappingLabelWithString: "")
57
+ /// The bubble's background, so the text gets padding.
58
+ let box = NSView()
59
+ /// Wide on both sides of the tip, so the bubble can sit to the left
60
+ /// when the target is near the right edge of the screen.
61
+ static let size = NSSize(width: 720, height: 170)
62
+ /// The arrow tip, in view coordinates (bottom-left origin).
63
+ static let tip = NSPoint(x: 360, y: size.height - 6)
64
+ var bubbleLeft = false { didSet { if bubbleLeft != oldValue { layoutBubble() } } }
65
+
66
+ init(color: NSColor, initial: String, name: String) {
67
+ self.color = color; self.initial = initial; self.name = name
68
+ super.init(frame: NSRect(origin: .zero, size: AvatarView.size))
69
+ wantsLayer = true
70
+ bubble.font = Brand.body(size: 13)
71
+ bubble.textColor = Brand.ink
72
+ bubble.maximumNumberOfLines = 4
73
+ box.wantsLayer = true
74
+ box.layer?.backgroundColor = Brand.paper.cgColor
75
+ box.layer?.cornerRadius = Brand.Radius.md
76
+ box.layer?.borderWidth = 2
77
+ box.layer?.borderColor = color.cgColor
78
+ box.isHidden = true
79
+ box.addSubview(bubble)
80
+ addSubview(box)
81
+ }
82
+ required init?(coder: NSCoder) { fatalError() }
83
+
84
+ /// Under the badge and name, never over them.
85
+ func setBubble(_ text: String) {
86
+ box.isHidden = text.isEmpty
87
+ bubble.stringValue = text
88
+ let textW: CGFloat = 300
89
+ bubble.preferredMaxLayoutWidth = textW
90
+ let fit = bubble.sizeThatFits(NSSize(width: textW, height: 90))
91
+ let w = min(textW, ceil(fit.width)), h = min(90, ceil(fit.height))
92
+ bubble.frame = NSRect(x: 10, y: 6, width: w, height: h)
93
+ box.setFrameSize(NSSize(width: w + 20, height: h + 12))
94
+ layoutBubble()
95
+ }
96
+
97
+ func layoutBubble() {
98
+ let t = AvatarView.tip, s = box.frame.size
99
+ box.setFrameOrigin(NSPoint(x: bubbleLeft ? t.x - s.width - 4 : t.x + 16, y: t.y - 58 - s.height))
100
+ }
101
+
102
+ override func draw(_ dirtyRect: NSRect) {
103
+ let t = AvatarView.tip
104
+ // The arrow: the system cursor's silhouette, in the agent's colour.
105
+ let arrow = NSBezierPath()
106
+ arrow.move(to: t)
107
+ arrow.line(to: NSPoint(x: t.x, y: t.y - 26))
108
+ arrow.line(to: NSPoint(x: t.x + 7, y: t.y - 20))
109
+ arrow.line(to: NSPoint(x: t.x + 12, y: t.y - 30))
110
+ arrow.line(to: NSPoint(x: t.x + 16, y: t.y - 28))
111
+ arrow.line(to: NSPoint(x: t.x + 11, y: t.y - 18))
112
+ arrow.line(to: NSPoint(x: t.x + 20, y: t.y - 18))
113
+ arrow.close()
114
+ NSGraphicsContext.current?.saveGraphicsState()
115
+ let shadow = NSShadow()
116
+ shadow.shadowBlurRadius = 4
117
+ shadow.shadowOffset = NSSize(width: 0, height: -1)
118
+ shadow.shadowColor = NSColor.black.withAlphaComponent(0.35)
119
+ shadow.set()
120
+ color.setFill(); arrow.fill()
121
+ NSGraphicsContext.current?.restoreGraphicsState()
122
+ NSColor.white.setStroke(); arrow.lineWidth = 1.5; arrow.stroke()
123
+
124
+ // The badge with the initial, and the name pill beside it.
125
+ let badge = NSRect(x: t.x + 16, y: t.y - 50, width: 24, height: 24)
126
+ color.setFill(); NSBezierPath(ovalIn: badge).fill()
127
+ NSColor.white.setStroke()
128
+ let ring = NSBezierPath(ovalIn: badge.insetBy(dx: 0.75, dy: 0.75)); ring.lineWidth = 1.5; ring.stroke()
129
+ draw(initial, in: badge, size: 11, weight: .bold, color: .white)
130
+
131
+ let attrs: [NSAttributedString.Key: Any] = [.font: NSFont.systemFont(ofSize: 11, weight: .semibold)]
132
+ let nameW = (name as NSString).size(withAttributes: attrs).width + 14
133
+ let pill = NSRect(x: badge.maxX + 4, y: badge.minY + 3, width: nameW, height: 18)
134
+ color.setFill(); NSBezierPath(roundedRect: pill, xRadius: 9, yRadius: 9).fill()
135
+ draw(name, in: pill, size: 11, weight: .semibold, color: .white)
136
+ }
137
+
138
+ private func draw(_ s: String, in r: NSRect, size: CGFloat, weight: NSFont.Weight, color: NSColor) {
139
+ let a: [NSAttributedString.Key: Any] = [.font: NSFont.systemFont(ofSize: size, weight: weight), .foregroundColor: color]
140
+ let sz = (s as NSString).size(withAttributes: a)
141
+ (s as NSString).draw(at: NSPoint(x: r.midX - sz.width / 2, y: r.midY - sz.height / 2), withAttributes: a)
142
+ }
143
+ }
144
+
145
+ // MARK: Behaviour
146
+
147
+ private final class Controller {
148
+ let avatar: NSPanel
149
+ let view: AvatarView
150
+ let ring: NSPanel
151
+ let color: NSColor
152
+ var at: CGPoint // tip position, AppKit coordinates
153
+ var timer: Timer?
154
+
155
+ init(color: NSColor, initial: String, name: String) {
156
+ self.color = color
157
+ view = AvatarView(color: color, initial: initial, name: name)
158
+ avatar = Presence.panel(NSRect(origin: .zero, size: AvatarView.size))
159
+ avatar.contentView = view
160
+ ring = Presence.panel(.zero)
161
+ let ringView = NSView()
162
+ ringView.wantsLayer = true
163
+ ringView.layer?.borderWidth = 3
164
+ ringView.layer?.borderColor = color.cgColor
165
+ ringView.layer?.cornerRadius = 8
166
+ ringView.layer?.backgroundColor = color.withAlphaComponent(0.10).cgColor
167
+ ring.contentView = ringView
168
+ at = Controller.parking()
169
+ place(at)
170
+ avatar.alphaValue = 0
171
+ avatar.orderFrontRegardless()
172
+ NSAnimationContext.runAnimationGroup { $0.duration = 0.2; avatar.animator().alphaValue = 1 }
173
+ }
174
+
175
+ static func parking() -> CGPoint {
176
+ let v = NSScreen.main?.visibleFrame ?? NSRect(x: 0, y: 0, width: 1440, height: 900)
177
+ return CGPoint(x: v.maxX - 380, y: v.minY + 170)
178
+ }
179
+
180
+ func place(_ tip: CGPoint) {
181
+ avatar.setFrameOrigin(NSPoint(x: tip.x - AvatarView.tip.x, y: tip.y - AvatarView.tip.y))
182
+ let screen = NSScreen.screens.first(where: { $0.frame.contains(tip) }) ?? NSScreen.main
183
+ view.bubbleLeft = (screen?.visibleFrame.maxX ?? .greatestFiniteMagnitude) - tip.x < 360
184
+ }
185
+
186
+ /// Glide with minimum-jerk easing; duration follows distance, as in
187
+ /// Pointer, so a long move reads as a reach and a short one as a nudge.
188
+ func glide(to target: CGPoint) {
189
+ timer?.invalidate()
190
+ let from = at
191
+ let d = hypot(target.x - from.x, target.y - from.y)
192
+ let duration = min(0.9, max(0.2, 0.12 + d / 2200))
193
+ let start = Date()
194
+ timer = Timer.scheduledTimer(withTimeInterval: 1.0 / 60, repeats: true) { [weak self] t in
195
+ guard let self else { t.invalidate(); return }
196
+ let u = min(1, Date().timeIntervalSince(start) / duration)
197
+ let e = 10 * pow(u, 3) - 15 * pow(u, 4) + 6 * pow(u, 5)
198
+ self.at = CGPoint(x: from.x + (target.x - from.x) * e, y: from.y + (target.y - from.y) * e)
199
+ self.place(self.at)
200
+ if u >= 1 { t.invalidate() }
201
+ }
202
+ }
203
+
204
+ func highlight(_ rect: CGRect?) {
205
+ guard let rect else { ring.orderOut(nil); return }
206
+ ring.setFrame(Presence.toAppKit(rect).insetBy(dx: -6, dy: -6), display: true)
207
+ ring.orderFrontRegardless()
208
+ avatar.orderFrontRegardless()
209
+ }
210
+
211
+ func handle(_ obj: [String: Any]) {
212
+ switch obj["cmd"] as? String {
213
+ case "move":
214
+ guard let x = obj["x"] as? Double, let y = obj["y"] as? Double else { return }
215
+ let w = obj["w"] as? Double ?? 0, h = obj["h"] as? Double ?? 0
216
+ let rect = CGRect(x: x, y: y, width: w, height: h)
217
+ // Aim just inside the control's lower-left third, so the
218
+ // arrow points AT it rather than covering its label.
219
+ let aim = CGPoint(x: x + min(w * 0.5, 24), y: y + h * 0.7)
220
+ glide(to: Presence.toAppKit(aim))
221
+ highlight((obj["highlight"] as? Bool ?? false) && w > 0 && h > 0 ? rect : nil)
222
+ case "say":
223
+ view.setBubble(obj["text"] as? String ?? "")
224
+ case "clear":
225
+ highlight(nil)
226
+ case "park":
227
+ highlight(nil)
228
+ glide(to: Controller.parking())
229
+ default:
230
+ break
231
+ }
232
+ }
233
+
234
+ func fadeOut(_ done: @escaping () -> Void) {
235
+ ring.orderOut(nil)
236
+ NSAnimationContext.runAnimationGroup { ctx in
237
+ ctx.duration = 0.25
238
+ avatar.animator().alphaValue = 0
239
+ } completionHandler: { done() }
240
+ }
241
+ }
242
+
243
+ static func color(hex: String?) -> NSColor {
244
+ guard let hex, hex.count == 7, hex.hasPrefix("#"), let v = UInt32(hex.dropFirst(), radix: 16) else {
245
+ return Brand.primaryBright
246
+ }
247
+ return NSColor(srgbRed: CGFloat((v >> 16) & 0xff) / 255, green: CGFloat((v >> 8) & 0xff) / 255,
248
+ blue: CGFloat(v & 0xff) / 255, alpha: 1)
249
+ }
250
+
251
+ /// Read commands until stdin closes.
252
+ static func run(name: String, initial: String, colorHex: String?) {
253
+ let app = NSApplication.shared
254
+ app.setActivationPolicy(.accessory)
255
+ let ctl = Controller(color: color(hex: colorHex), initial: initial, name: name)
256
+ DispatchQueue(label: "tn.acme.agentx.presence.stdin").async {
257
+ while let line = readLine(strippingNewline: true) {
258
+ guard let data = line.data(using: .utf8),
259
+ let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { continue }
260
+ DispatchQueue.main.async { ctl.handle(obj) }
261
+ }
262
+ DispatchQueue.main.async { ctl.fadeOut { app.terminate(nil) } }
263
+ }
264
+ app.run()
265
+ }
266
+ }
@@ -256,10 +256,16 @@ case "hud":
256
256
  // Long-lived: reads update lines on stdin until EOF.
257
257
  HUD.run()
258
258
 
259
+ case "presence":
260
+ // Long-lived: the agent's own drawn cursor. Never moves the real mouse.
261
+ let name = flag("name") ?? "Agent"
262
+ Presence.run(name: name, initial: flag("initial") ?? String(name.prefix(1)).uppercased(),
263
+ colorHex: flag("color"))
264
+
259
265
  case "trusted":
260
266
  let payload = ["ok": true, "trusted": AXTree.trusted()] as [String: Any]
261
267
  FileHandle.standardOutput.write(try! JSONSerialization.data(withJSONObject: payload))
262
268
 
263
269
  default:
264
- fail("unknown verb \"\(verb)\" — expected read, screens, point, click, type, key, scroll, drag, ocr, capture, hittest, focused, hud or trusted")
270
+ fail("unknown verb \"\(verb)\" — expected read, screens, point, click, type, key, scroll, drag, ocr, capture, hittest, focused, hud, presence or trusted")
265
271
  }
@@ -25,6 +25,8 @@ enum AgentClient {
25
25
  /// The agent that answered and its ElevenLabs voice, when it has one.
26
26
  let agentID: String?
27
27
  let voiceID: String?
28
+ /// Presence mode the daemon chose for this turn (talk, teach, …).
29
+ var presenceMode: String? = nil
28
30
  }
29
31
 
30
32
  /// What, if anything, to say about the step now running.
@@ -103,9 +105,11 @@ enum AgentClient {
103
105
  struct UiMedia: Decodable { let type: String; let url: String; let caption: String? }
104
106
  struct Ui: Decodable { let buttons: [UiButton]?; let media: UiMedia? }
105
107
  struct Voice: Decodable { let elevenlabsVoiceId: String? }
108
+ struct Presence: Decodable { let mode: String? }
106
109
  struct Reply: Decodable {
107
110
  let agentId: String?
108
111
  let voice: Voice?
112
+ let presence: Presence?
109
113
  let text: String?
110
114
  let full: String?
111
115
  let ui: Ui?
@@ -144,6 +148,7 @@ enum AgentClient {
144
148
 
145
149
  return Answer(text: text, written: reply?.full,
146
150
  buttons: buttons + extra, imageURL: image,
147
- durationMs: reply?.duration, agentID: reply?.agentId, voiceID: voiceID)
151
+ durationMs: reply?.duration, agentID: reply?.agentId, voiceID: voiceID,
152
+ presenceMode: reply?.presence?.mode)
148
153
  }
149
154
  }
@@ -295,6 +295,9 @@ final class App: NSObject, NSApplicationDelegate {
295
295
  // it closes itself; start talking and the conversation
296
296
  // simply continues.
297
297
  busy = false
298
+ // A live lesson now runs on screen and speaks for itself; an
299
+ // open mic would hear the agent. Option-Space is the door.
300
+ if ["teach", "watch", "act"].contains(answer.presenceMode ?? "") { return }
298
301
  listenHandsFree(followUp: true)
299
302
  } catch {
300
303
  endNarration()
@@ -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-IVAGDL5M.js";import"./chunk-SPJWXIAV.js";import"./chunk-FIOB3MEX.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-ZSNTLADV.js";import"./chunk-LA6AKS4N.js";import"./chunk-FIOB3MEX.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-QHPZXA42.js.map
8
+ //# sourceMappingURL=App-K5J52F7O.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-IVAGDL5M.js";import"./chunk-SPJWXIAV.js";import"./chunk-FIOB3MEX.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-ZSNTLADV.js";import"./chunk-LA6AKS4N.js";import"./chunk-FIOB3MEX.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-EAHHH365.js.map
7
+ //# sourceMappingURL=ChatApp-LRRAPZH7.js.map
@@ -1,2 +1,2 @@
1
- import{A as a,B as b,C as c}from"./chunk-JDC35PWM.js";import"./chunk-SFQUP3BP.js";import"./chunk-QOYAX2FT.js";import"./chunk-LCIREYTD.js";import"./chunk-L2WSPY6S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-FIOB3MEX.js";export{a as createAgentContext,b as generate,c as generateStream};
2
- //# sourceMappingURL=agent-KBBO7OZS.js.map
1
+ import{A as a,B as b,C as c}from"./chunk-3TNK7VGH.js";import"./chunk-SFQUP3BP.js";import"./chunk-QOYAX2FT.js";import"./chunk-LCIREYTD.js";import"./chunk-L2WSPY6S.js";import"./chunk-VDMYBPYB.js";import"./chunk-DSYKYZMT.js";import"./chunk-FIOB3MEX.js";export{a as createAgentContext,b as generate,c as generateStream};
2
+ //# sourceMappingURL=agent-XEXAYH5J.js.map