agentix-cli 0.33.0 → 0.34.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 (90) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +43 -2
  2. package/apps/mac-voice/Sources/AgentXVoice/Config.swift +6 -1
  3. package/apps/mac-voice/Sources/AgentXVoice/Progress.swift +5 -3
  4. package/apps/mac-voice/Sources/AgentXVoice/Speech.swift +5 -4
  5. package/apps/mac-voice/Sources/AgentXVoice/main.swift +27 -5
  6. package/dist/{App-2LAWZNMG.js → App-QHPZXA42.js} +2 -2
  7. package/dist/{ChatApp-2KRDHMTV.js → ChatApp-EAHHH365.js} +2 -2
  8. package/dist/{agent-ZRRIMLTX.js → agent-KBBO7OZS.js} +2 -2
  9. package/dist/{board-dashboard-XYB7M5BH.js → board-dashboard-74OLMLAD.js} +4 -4
  10. package/dist/{chunk-UEP7IRBD.js → chunk-33G4TIZT.js} +184 -177
  11. package/dist/chunk-33G4TIZT.js.map +1 -0
  12. package/dist/{chunk-5FEQI22L.js → chunk-5H5L75RN.js} +2 -2
  13. package/dist/chunk-6WGTLDME.js +551 -0
  14. package/dist/chunk-6WGTLDME.js.map +1 -0
  15. package/dist/{chunk-G5MFPNGJ.js → chunk-CY24RXE4.js} +2 -2
  16. package/dist/{chunk-JGJE5Y2J.js → chunk-IUNCX6BG.js} +2 -2
  17. package/dist/{chunk-4CR463C6.js → chunk-IVAGDL5M.js} +2 -2
  18. package/dist/{chunk-K6E7WJ7O.js → chunk-JDC35PWM.js} +2 -2
  19. package/dist/{chunk-JWKIFAXA.js → chunk-MJYE5ADH.js} +2 -2
  20. package/dist/{chunk-MFVI5FOM.js → chunk-PG7BAZIZ.js} +2 -2
  21. package/dist/{chunk-W3YGESNK.js → chunk-QKNAGTJK.js} +2 -2
  22. package/dist/{chunk-2DBGOCCW.js → chunk-QXAUKNMW.js} +2 -2
  23. package/dist/chunk-SPJWXIAV.js +13 -0
  24. package/dist/chunk-SPJWXIAV.js.map +1 -0
  25. package/dist/{chunk-B2XTYYXV.js → chunk-U5P7XGCB.js} +2 -2
  26. package/dist/{chunk-A4YR3PQY.js → chunk-UJF5JUFJ.js} +2 -2
  27. package/dist/{chunk-GWQIMAJ7.js → chunk-X6HLI6XB.js} +2 -2
  28. package/dist/{chunk-6VQKHMEQ.js → chunk-ZMFUBIEQ.js} +5 -5
  29. package/dist/cli.js +1 -1
  30. package/dist/client-CAGQYJML.js +2 -0
  31. package/dist/config-NPLE42XY.js +2 -0
  32. package/dist/config-mutator-FFTODESU.js +2 -0
  33. package/dist/doctor-X4KHQFRF.js +2 -0
  34. package/dist/index.d.ts +110 -0
  35. package/dist/index.js +1 -1
  36. package/dist/program-ISXECD4J.js +2 -0
  37. package/dist/query-XLJ6I34S.js +2 -0
  38. package/dist/{registry-OB6S66XX.js → registry-3RN7I6YW.js} +2 -2
  39. package/dist/{request-planner-F5NVL2G7.js → request-planner-JX7M3PTD.js} +2 -2
  40. package/dist/{review-candidates-IRPKFWL2.js → review-candidates-UTS4RX4U.js} +2 -2
  41. package/dist/{routing-OSPRKRAY.js → routing-D7APOAP6.js} +2 -2
  42. package/dist/scheduler-EGR5AJAQ.js +2 -0
  43. package/dist/{seat-2MHKVMW2.js → seat-UA2ROH3V.js} +2 -2
  44. package/dist/{select-7LCHJVPK.js → select-WQXHYEPD.js} +2 -2
  45. package/dist/wiki-RNANPNUX.js +2 -0
  46. package/package.json +1 -1
  47. package/dist/chunk-2DMVKLLE.js +0 -13
  48. package/dist/chunk-2DMVKLLE.js.map +0 -1
  49. package/dist/chunk-UEP7IRBD.js.map +0 -1
  50. package/dist/chunk-WZD3OS7T.js +0 -550
  51. package/dist/chunk-WZD3OS7T.js.map +0 -1
  52. package/dist/client-IP643GRO.js +0 -2
  53. package/dist/config-IVDP46ZG.js +0 -2
  54. package/dist/config-mutator-UCGAV3SP.js +0 -2
  55. package/dist/doctor-MMT4SREV.js +0 -2
  56. package/dist/program-PK5R7GIC.js +0 -2
  57. package/dist/query-RHVR6QUZ.js +0 -2
  58. package/dist/scheduler-JL6K5HHI.js +0 -2
  59. package/dist/wiki-MY32MON3.js +0 -2
  60. /package/dist/{App-2LAWZNMG.js.map → App-QHPZXA42.js.map} +0 -0
  61. /package/dist/{ChatApp-2KRDHMTV.js.map → ChatApp-EAHHH365.js.map} +0 -0
  62. /package/dist/{agent-ZRRIMLTX.js.map → agent-KBBO7OZS.js.map} +0 -0
  63. /package/dist/{board-dashboard-XYB7M5BH.js.map → board-dashboard-74OLMLAD.js.map} +0 -0
  64. /package/dist/{chunk-5FEQI22L.js.map → chunk-5H5L75RN.js.map} +0 -0
  65. /package/dist/{chunk-G5MFPNGJ.js.map → chunk-CY24RXE4.js.map} +0 -0
  66. /package/dist/{chunk-JGJE5Y2J.js.map → chunk-IUNCX6BG.js.map} +0 -0
  67. /package/dist/{chunk-4CR463C6.js.map → chunk-IVAGDL5M.js.map} +0 -0
  68. /package/dist/{chunk-K6E7WJ7O.js.map → chunk-JDC35PWM.js.map} +0 -0
  69. /package/dist/{chunk-JWKIFAXA.js.map → chunk-MJYE5ADH.js.map} +0 -0
  70. /package/dist/{chunk-MFVI5FOM.js.map → chunk-PG7BAZIZ.js.map} +0 -0
  71. /package/dist/{chunk-W3YGESNK.js.map → chunk-QKNAGTJK.js.map} +0 -0
  72. /package/dist/{chunk-2DBGOCCW.js.map → chunk-QXAUKNMW.js.map} +0 -0
  73. /package/dist/{chunk-B2XTYYXV.js.map → chunk-U5P7XGCB.js.map} +0 -0
  74. /package/dist/{chunk-A4YR3PQY.js.map → chunk-UJF5JUFJ.js.map} +0 -0
  75. /package/dist/{chunk-GWQIMAJ7.js.map → chunk-X6HLI6XB.js.map} +0 -0
  76. /package/dist/{chunk-6VQKHMEQ.js.map → chunk-ZMFUBIEQ.js.map} +0 -0
  77. /package/dist/{client-IP643GRO.js.map → client-CAGQYJML.js.map} +0 -0
  78. /package/dist/{config-IVDP46ZG.js.map → config-NPLE42XY.js.map} +0 -0
  79. /package/dist/{config-mutator-UCGAV3SP.js.map → config-mutator-FFTODESU.js.map} +0 -0
  80. /package/dist/{doctor-MMT4SREV.js.map → doctor-X4KHQFRF.js.map} +0 -0
  81. /package/dist/{program-PK5R7GIC.js.map → program-ISXECD4J.js.map} +0 -0
  82. /package/dist/{query-RHVR6QUZ.js.map → query-XLJ6I34S.js.map} +0 -0
  83. /package/dist/{registry-OB6S66XX.js.map → registry-3RN7I6YW.js.map} +0 -0
  84. /package/dist/{request-planner-F5NVL2G7.js.map → request-planner-JX7M3PTD.js.map} +0 -0
  85. /package/dist/{review-candidates-IRPKFWL2.js.map → review-candidates-UTS4RX4U.js.map} +0 -0
  86. /package/dist/{routing-OSPRKRAY.js.map → routing-D7APOAP6.js.map} +0 -0
  87. /package/dist/{scheduler-JL6K5HHI.js.map → scheduler-EGR5AJAQ.js.map} +0 -0
  88. /package/dist/{seat-2MHKVMW2.js.map → seat-UA2ROH3V.js.map} +0 -0
  89. /package/dist/{select-7LCHJVPK.js.map → select-WQXHYEPD.js.map} +0 -0
  90. /package/dist/{wiki-MY32MON3.js.map → wiki-RNANPNUX.js.map} +0 -0
@@ -22,6 +22,9 @@ enum AgentClient {
22
22
  let buttons: [(String, String)]
23
23
  let imageURL: String?
24
24
  let durationMs: Int?
25
+ /// The agent that answered and its ElevenLabs voice, when it has one.
26
+ let agentID: String?
27
+ let voiceID: String?
25
28
  }
26
29
 
27
30
  /// What, if anything, to say about the step now running.
@@ -49,6 +52,39 @@ enum AgentClient {
49
52
  return (try? JSONDecoder().decode(Reply.self, from: data))?.say
50
53
  }
51
54
 
55
+ // MARK: Talk mode
56
+ //
57
+ // While two agents talk out loud (`agentx talk`), Option-Space is the
58
+ // door: pressing it hushes them at once, and what is said goes to the
59
+ // talk instead of /ask. See src/daemon/voice-talk-api.ts.
60
+
61
+ /// Silence a running talk. Returns whether one is running, so the
62
+ /// caller knows where the words about to be spoken should go. Never
63
+ /// throws: no daemon means no talk.
64
+ static func talkHush() async -> Bool {
65
+ guard let (data, _) = try? await post("/talk/hush", [:], timeout: 2) else { return false }
66
+ struct Reply: Decodable { let active: Bool? }
67
+ return (try? JSONDecoder().decode(Reply.self, from: data))?.active ?? false
68
+ }
69
+
70
+ /// Hand the listener's words to the talk; "stop" ends it.
71
+ static func talkDoor(_ text: String) async throws {
72
+ let (_, response) = try await post("/talk/door", ["text": text], timeout: 5)
73
+ if let http = response as? HTTPURLResponse, !(200..<300).contains(http.statusCode) {
74
+ throw NSError(domain: "AgentXVoice", code: http.statusCode,
75
+ userInfo: [NSLocalizedDescriptionKey: "The talk has ended"])
76
+ }
77
+ }
78
+
79
+ private static func post(_ path: String, _ body: [String: Any], timeout: TimeInterval) async throws -> (Data, URLResponse) {
80
+ var req = URLRequest(url: URL(string: "\(Config.daemonURL)\(path)")!)
81
+ req.httpMethod = "POST"
82
+ req.timeoutInterval = timeout
83
+ req.setValue("application/json", forHTTPHeaderField: "Content-Type")
84
+ req.httpBody = try JSONSerialization.data(withJSONObject: body)
85
+ return try await URLSession.shared.data(for: req)
86
+ }
87
+
52
88
  static func ask(_ message: String) async throws -> Answer {
53
89
  var req = URLRequest(url: URL(string: "\(Config.daemonURL)/ask")!)
54
90
  req.httpMethod = "POST"
@@ -59,13 +95,17 @@ enum AgentClient {
59
95
  req.httpBody = try JSONSerialization.data(withJSONObject: [
60
96
  "message": message,
61
97
  "agent": Config.agentID,
98
+ "session": Config.voiceSession,
62
99
  ])
63
100
 
64
101
  let (data, response) = try await URLSession.shared.data(for: req)
65
102
  struct UiButton: Decodable { let label: String; let url: String }
66
103
  struct UiMedia: Decodable { let type: String; let url: String; let caption: String? }
67
104
  struct Ui: Decodable { let buttons: [UiButton]?; let media: UiMedia? }
105
+ struct Voice: Decodable { let elevenlabsVoiceId: String? }
68
106
  struct Reply: Decodable {
107
+ let agentId: String?
108
+ let voice: Voice?
69
109
  let text: String?
70
110
  let full: String?
71
111
  let ui: Ui?
@@ -73,6 +113,7 @@ enum AgentClient {
73
113
  let duration: Int?
74
114
  }
75
115
  let reply = try? JSONDecoder().decode(Reply.self, from: data)
116
+ let voiceID = reply?.voice?.elevenlabsVoiceId
76
117
 
77
118
  // 202 means accepted-but-busy: the daemon has already written a
78
119
  // speakable explanation into `text`. Falling through to the error
@@ -81,7 +122,7 @@ enum AgentClient {
81
122
  if let http = response as? HTTPURLResponse, http.statusCode == 202,
82
123
  let queuedText = reply?.text, !queuedText.isEmpty {
83
124
  return Answer(text: queuedText, written: nil, buttons: [], imageURL: nil,
84
- durationMs: reply?.duration)
125
+ durationMs: reply?.duration, agentID: reply?.agentId, voiceID: voiceID)
85
126
  }
86
127
 
87
128
  if let http = response as? HTTPURLResponse, !(200..<300).contains(http.statusCode) {
@@ -103,6 +144,6 @@ enum AgentClient {
103
144
 
104
145
  return Answer(text: text, written: reply?.full,
105
146
  buttons: buttons + extra, imageURL: image,
106
- durationMs: reply?.duration)
147
+ durationMs: reply?.duration, agentID: reply?.agentId, voiceID: voiceID)
107
148
  }
108
149
  }
@@ -10,8 +10,13 @@ enum Config {
10
10
  static let daemonURL = env("AGENTX_DAEMON_URL") ?? "http://127.0.0.1:18800"
11
11
  static let agentID = env("AGENTX_VOICE_AGENT") ?? "secretary-agent"
12
12
 
13
- /// ElevenLabs default voice. Override with AGENTX_VOICE_ID.
13
+ /// ElevenLabs default voice, used when the answering agent has none
14
+ /// configured. Override with AGENTX_VOICE_ID.
14
15
  static let voiceID = env("AGENTX_VOICE_ID") ?? "21m00Tcm4TlvDq8ikWAM"
16
+
17
+ /// One voice session per launch. The daemon uses it to decide whether
18
+ /// an agent still needs to introduce itself.
19
+ static let voiceSession = UUID().uuidString
15
20
  static let sttModel = env("AGENTX_STT_MODEL") ?? "scribe_v1"
16
21
 
17
22
  /// How to invoke smart paste. Run through a login shell, so this is a
@@ -16,7 +16,8 @@ final class Progress: NSObject, URLSessionDataDelegate {
16
16
  private var session: URLSession?
17
17
  private var buffer = Data()
18
18
  private let agentID: String
19
- private let onStep: (String) -> Void
19
+ /// The step label, and the working agent's voice id when it has one.
20
+ private let onStep: (String, String?) -> Void
20
21
 
21
22
  /// Every touch of `buffer`, `task` and `session` happens here.
22
23
  ///
@@ -30,7 +31,7 @@ final class Progress: NSObject, URLSessionDataDelegate {
30
31
  private let queue = DispatchQueue(label: "tn.acme.agentx.voice.progress")
31
32
  private var stopped = false
32
33
 
33
- init(agentID: String, onStep: @escaping (String) -> Void) {
34
+ init(agentID: String, onStep: @escaping (String, String?) -> Void) {
34
35
  self.agentID = agentID
35
36
  self.onStep = onStep
36
37
  }
@@ -112,7 +113,8 @@ final class Progress: NSObject, URLSessionDataDelegate {
112
113
  // and narrating theirs would be both confusing and a privacy leak.
113
114
  guard (obj["agentId"] as? String) == agentID else { return }
114
115
  guard let label = summarise(obj) else { return }
115
- DispatchQueue.main.async { self.onStep(label) }
116
+ let voiceID = (obj["voice"] as? [String: Any])?["elevenlabsVoiceId"] as? String
117
+ DispatchQueue.main.async { self.onStep(label, voiceID) }
116
118
  }
117
119
 
118
120
  /// Turn a step event into something worth showing in 180 points of
@@ -72,11 +72,12 @@ enum Speech {
72
72
 
73
73
  // MARK: Text to speech
74
74
 
75
- static func speak(_ text: String) async {
75
+ /// `voiceID` is the answering agent's voice; nil means the global default.
76
+ static func speak(_ text: String, voiceID: String? = nil) async {
76
77
  guard !text.isEmpty else { return }
77
78
  if let key = Config.elevenLabsKey {
78
79
  do {
79
- let mp3 = try await elevenLabsTTS(text: text, key: key)
80
+ let mp3 = try await elevenLabsTTS(text: text, voiceID: voiceID ?? Config.voiceID, key: key)
80
81
  try await Player.shared.play(mp3)
81
82
  return
82
83
  } catch {
@@ -86,8 +87,8 @@ enum Speech {
86
87
  _ = try? run("/usr/bin/say", [text])
87
88
  }
88
89
 
89
- private static func elevenLabsTTS(text: String, key: String) async throws -> Data {
90
- let url = URL(string: "https://api.elevenlabs.io/v1/text-to-speech/\(Config.voiceID)")!
90
+ private static func elevenLabsTTS(text: String, voiceID: String, key: String) async throws -> Data {
91
+ let url = URL(string: "https://api.elevenlabs.io/v1/text-to-speech/\(voiceID)")!
91
92
  var req = URLRequest(url: url)
92
93
  req.httpMethod = "POST"
93
94
  req.timeoutInterval = 60
@@ -28,6 +28,12 @@ final class App: NSObject, NSApplicationDelegate {
28
28
  private var lastStep = "Thinking…"
29
29
  private var spokenSteps = Set<String>()
30
30
  private var lastSpokeAt = Date.distantPast
31
+ /// The answering agent's voice, learned from the daemon. Nil until
32
+ /// then, which speaks in the global default.
33
+ private var voiceID: String?
34
+ /// Set on Option-Space: whether a talk was running (and is now hushed),
35
+ /// so the words spoken go to the talk rather than to /ask.
36
+ private var talkCheck: Task<Bool, Never>?
31
37
 
32
38
  /// ⌘⌥V. Everything except the hotkey lives in `agentx paste`.
33
39
  private func smartPaste() {
@@ -223,6 +229,9 @@ final class App: NSObject, NSApplicationDelegate {
223
229
  // A turn already in flight must not be interrupted by a stray
224
230
  // keypress; the answer is still coming and will be spoken.
225
231
  guard !busy, !recorder.isRecording else { return }
232
+ // Two agents may be talking out loud. Hush them now, before a word
233
+ // is said, and remember whether they were there.
234
+ talkCheck = Task { await AgentClient.talkHush() }
226
235
  do {
227
236
  try recorder.start()
228
237
  panel.render(.listening)
@@ -233,6 +242,8 @@ final class App: NSObject, NSApplicationDelegate {
233
242
 
234
243
  private func stopAndSend() {
235
244
  guard recorder.isRecording else { return }
245
+ let talk = talkCheck
246
+ talkCheck = nil
236
247
  guard let wav = recorder.stop() else {
237
248
  panel.render(.error("Too short — hold while speaking"))
238
249
  resetSoon()
@@ -249,11 +260,21 @@ final class App: NSObject, NSApplicationDelegate {
249
260
  busy = false; resetSoon(); return
250
261
  }
251
262
  Log.info("heard: \(heard)")
263
+ if await talk?.value == true {
264
+ // The talk answers out loud through the daemon; nothing
265
+ // to speak here.
266
+ try await AgentClient.talkDoor(heard)
267
+ Log.info("sent to the talk")
268
+ panel.render(.idle)
269
+ busy = false
270
+ return
271
+ }
252
272
  beginNarration()
253
273
 
254
274
  let answer = try await AgentClient.ask(heard)
255
275
  endNarration()
256
- Log.info("answer: \(answer.text)")
276
+ if let v = answer.voiceID { voiceID = v }
277
+ Log.info("answer (\(answer.agentID ?? "?")): \(answer.text)")
257
278
  // Show BEFORE speaking, but only when there is something
258
279
  // the speech cannot deliver — a link, an image, or more
259
280
  // text than was read aloud. A card that opens on every
@@ -268,7 +289,7 @@ final class App: NSObject, NSApplicationDelegate {
268
289
  // Scroll the sentence being spoken, so it can be read as
269
290
  // well as heard — and re-read after, which speech cannot do.
270
291
  panel.render(.saying(answer.text))
271
- await Speech.speak(answer.text)
292
+ await Speech.speak(answer.text, voiceID: voiceID)
272
293
  panel.render(.idle)
273
294
  // Leave the microphone open for a moment. Say nothing and
274
295
  // it closes itself; start talking and the conversation
@@ -281,7 +302,7 @@ final class App: NSObject, NSApplicationDelegate {
281
302
  panel.render(.error(short(error.localizedDescription)))
282
303
  // Say it aloud too — a voice assistant that fails only in
283
304
  // a 230px label has failed silently for anyone not looking.
284
- await Speech.speak("Sorry, that didn't work.")
305
+ await Speech.speak("Sorry, that didn't work.", voiceID: voiceID)
285
306
  resetSoon()
286
307
  }
287
308
  busy = false
@@ -303,9 +324,10 @@ final class App: NSObject, NSApplicationDelegate {
303
324
 
304
325
  // Progress delivers on its own serial queue; hop to main before
305
326
  // touching any view.
306
- progress = Progress(agentID: Config.agentID) { [weak self] step in
327
+ progress = Progress(agentID: Config.agentID) { [weak self] step, voice in
307
328
  Task { @MainActor in
308
329
  guard let self, self.busy else { return }
330
+ if let voice { self.voiceID = voice }
309
331
  self.lastStep = step
310
332
  Log.info("step: \(step)")
311
333
  self.panel.render(.working(step, Int(Date().timeIntervalSince(self.startedAt))))
@@ -356,7 +378,7 @@ final class App: NSObject, NSApplicationDelegate {
356
378
  tool: tool, detail: detail, elapsed: Int(elapsed)) else { return }
357
379
  guard !self.spokenSteps.contains(phrase) else { return }
358
380
  self.spokenSteps.insert(phrase)
359
- await Speech.speak(phrase.prefix(1).capitalized + phrase.dropFirst() + ".")
381
+ await Speech.speak(phrase.prefix(1).capitalized + phrase.dropFirst() + ".", voiceID: self.voiceID)
360
382
  }
361
383
  }
362
384
 
@@ -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-4CR463C6.js";import"./chunk-2DMVKLLE.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-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(`
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-2LAWZNMG.js.map
8
+ //# sourceMappingURL=App-QHPZXA42.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-4CR463C6.js";import"./chunk-2DMVKLLE.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-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(`
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-2KRDHMTV.js.map
7
+ //# sourceMappingURL=ChatApp-EAHHH365.js.map
@@ -1,2 +1,2 @@
1
- import{A as a,B as b,C as c}from"./chunk-K6E7WJ7O.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-ZRRIMLTX.js.map
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