agentix-cli 0.95.0 → 0.96.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/mac-voice/Sources/AgentXVoice/Config.swift +19 -9
- package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +56 -7
- package/apps/mac-voice/Sources/AgentXVoice/PanelAnswer.swift +2 -0
- package/apps/mac-voice/Sources/AgentXVoice/PillMenu.swift +9 -0
- package/apps/mac-voice/Sources/AgentXVoice/PillPlacement.swift +15 -4
- package/apps/mac-voice/Sources/AgentXVoice/SettingsLook.swift +6 -0
- package/apps/mac-voice/Sources/AgentXVoice/SettingsWindow.swift +4 -1
- package/apps/mac-voice/Sources/AgentXVoice/StatusMenu.swift +9 -0
- package/apps/mac-voice/Sources/AgentXVoice/Surface.swift +19 -0
- package/apps/mac-voice/Sources/AgentXVoice/VoiceSettings.swift +8 -2
- package/apps/mac-voice/Sources/AgentXVoice/main.swift +16 -0
- package/dist/{App-6PNLFYAK.js → App-UHSIO3UE.js} +2 -2
- package/dist/{ChatApp-YYBPNTIA.js → ChatApp-LLTFBLJY.js} +2 -2
- package/dist/{agent-THOKXUGD.js → agent-6RJ633MQ.js} +2 -2
- package/dist/{board-dashboard-URZW2L6F.js → board-dashboard-A3ZEI4F6.js} +4 -4
- package/dist/{chunk-24EKSYR7.js → chunk-44UGVUN7.js} +2 -2
- package/dist/{chunk-PNSAL5NB.js → chunk-4XHKJZLJ.js} +2 -2
- package/dist/{chunk-HZJ4S2LT.js → chunk-6DCY2JCB.js} +5 -5
- package/dist/{chunk-VJEO7EOS.js → chunk-6NECC6YS.js} +2 -2
- package/dist/{chunk-VUUDZFRR.js → chunk-ALWMYA2B.js} +2 -2
- package/dist/{chunk-IEEZ3HJW.js → chunk-DU6536CC.js} +2 -2
- package/dist/{chunk-WFZHADE2.js → chunk-EBVB727L.js} +2 -2
- package/dist/{chunk-AP4HOAUV.js → chunk-GHXSBJZS.js} +2 -2
- package/dist/{chunk-FQHY4A5H.js → chunk-IPDEWVVT.js} +2 -2
- package/dist/{chunk-DE4SOF37.js → chunk-J2MHITWR.js} +2 -2
- package/dist/{chunk-NARH4ZMY.js → chunk-KEKO4S45.js} +2 -2
- package/dist/{chunk-KE3FB3SK.js → chunk-KIGFWUKP.js} +2 -2
- package/dist/{chunk-3DB2X334.js → chunk-MKF6HSBA.js} +2 -2
- package/dist/{chunk-3BD54ASS.js → chunk-MNS4SBRR.js} +11 -11
- package/dist/chunk-MNS4SBRR.js.map +1 -0
- package/dist/{chunk-ZGWDZ7X7.js → chunk-QZIEYDIY.js} +2 -2
- package/dist/{chunk-7V7GH57E.js → chunk-TE44E733.js} +2 -2
- package/dist/{chunk-VNVKNVGF.js → chunk-VO2GNAKB.js} +2 -2
- package/dist/{chunk-KFMGQ6S7.js → chunk-XEKZKH3W.js} +2 -2
- package/dist/{chunk-KFMGQ6S7.js.map → chunk-XEKZKH3W.js.map} +1 -1
- package/dist/{chunk-ZGUC3EG6.js → chunk-ZVW645NU.js} +2 -2
- package/dist/{chunk-GE3ISITN.js → chunk-ZYJDAT3E.js} +2 -2
- package/dist/{chunk-RQVRKBLH.js → chunk-ZZSNM2RI.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/{client-EKGV6UYH.js → client-ARS6ZFT2.js} +2 -2
- package/dist/{config-SF2U4WSJ.js → config-XO5Z3BO5.js} +2 -2
- package/dist/config-mutator-MJX4EIYV.js +2 -0
- package/dist/{doctor-3BOJJYBX.js → doctor-VUK3JE6Z.js} +2 -2
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1 -1
- package/dist/{program-T4RVQKES.js → program-HUQB4IIO.js} +136 -136
- package/dist/{program-T4RVQKES.js.map → program-HUQB4IIO.js.map} +1 -1
- package/dist/{promote-L2VBS3X2.js → promote-UGQXA4KV.js} +2 -2
- package/dist/{query-Y5XOM7X6.js → query-DL7RHPMA.js} +2 -2
- package/dist/{registry-ID2KMJCU.js → registry-YIPKBRBH.js} +2 -2
- package/dist/{request-planner-LHVZFBYR.js → request-planner-L2FAVNKP.js} +2 -2
- package/dist/{review-candidates-ZNCQQKQS.js → review-candidates-RPUP4XBU.js} +2 -2
- package/dist/{routing-OAYXRJ7K.js → routing-G66SVTRO.js} +2 -2
- package/dist/schedule-tool-FOWPIWKP.js +2 -0
- package/dist/scheduler-GFVUPAD6.js +2 -0
- package/dist/{seat-Y7QTFQDR.js → seat-ZPH7DA5L.js} +2 -2
- package/dist/{select-OC4FXEIP.js → select-2WTV2BI2.js} +2 -2
- package/dist/{set-enabled-QBPTP6I4.js → set-enabled-KI2FINQD.js} +2 -2
- package/dist/{tool-P257FZXB.js → tool-2P4LRWN4.js} +2 -2
- package/dist/{tool-MEAHEWD2.js → tool-ZFQ46KU3.js} +2 -2
- package/dist/wiki-XATGT3DI.js +2 -0
- package/package.json +1 -1
- package/dist/chunk-3BD54ASS.js.map +0 -1
- package/dist/config-mutator-XTYVB2LB.js +0 -2
- package/dist/schedule-tool-K7UHGVQ2.js +0 -2
- package/dist/scheduler-VQFLXG4Y.js +0 -2
- package/dist/wiki-SZH2KSLQ.js +0 -2
- /package/dist/{App-6PNLFYAK.js.map → App-UHSIO3UE.js.map} +0 -0
- /package/dist/{ChatApp-YYBPNTIA.js.map → ChatApp-LLTFBLJY.js.map} +0 -0
- /package/dist/{agent-THOKXUGD.js.map → agent-6RJ633MQ.js.map} +0 -0
- /package/dist/{board-dashboard-URZW2L6F.js.map → board-dashboard-A3ZEI4F6.js.map} +0 -0
- /package/dist/{chunk-24EKSYR7.js.map → chunk-44UGVUN7.js.map} +0 -0
- /package/dist/{chunk-PNSAL5NB.js.map → chunk-4XHKJZLJ.js.map} +0 -0
- /package/dist/{chunk-HZJ4S2LT.js.map → chunk-6DCY2JCB.js.map} +0 -0
- /package/dist/{chunk-VJEO7EOS.js.map → chunk-6NECC6YS.js.map} +0 -0
- /package/dist/{chunk-VUUDZFRR.js.map → chunk-ALWMYA2B.js.map} +0 -0
- /package/dist/{chunk-IEEZ3HJW.js.map → chunk-DU6536CC.js.map} +0 -0
- /package/dist/{chunk-WFZHADE2.js.map → chunk-EBVB727L.js.map} +0 -0
- /package/dist/{chunk-AP4HOAUV.js.map → chunk-GHXSBJZS.js.map} +0 -0
- /package/dist/{chunk-FQHY4A5H.js.map → chunk-IPDEWVVT.js.map} +0 -0
- /package/dist/{chunk-DE4SOF37.js.map → chunk-J2MHITWR.js.map} +0 -0
- /package/dist/{chunk-NARH4ZMY.js.map → chunk-KEKO4S45.js.map} +0 -0
- /package/dist/{chunk-KE3FB3SK.js.map → chunk-KIGFWUKP.js.map} +0 -0
- /package/dist/{chunk-3DB2X334.js.map → chunk-MKF6HSBA.js.map} +0 -0
- /package/dist/{chunk-ZGWDZ7X7.js.map → chunk-QZIEYDIY.js.map} +0 -0
- /package/dist/{chunk-7V7GH57E.js.map → chunk-TE44E733.js.map} +0 -0
- /package/dist/{chunk-VNVKNVGF.js.map → chunk-VO2GNAKB.js.map} +0 -0
- /package/dist/{chunk-ZGUC3EG6.js.map → chunk-ZVW645NU.js.map} +0 -0
- /package/dist/{chunk-GE3ISITN.js.map → chunk-ZYJDAT3E.js.map} +0 -0
- /package/dist/{chunk-RQVRKBLH.js.map → chunk-ZZSNM2RI.js.map} +0 -0
- /package/dist/{client-EKGV6UYH.js.map → client-ARS6ZFT2.js.map} +0 -0
- /package/dist/{config-SF2U4WSJ.js.map → config-XO5Z3BO5.js.map} +0 -0
- /package/dist/{config-mutator-XTYVB2LB.js.map → config-mutator-MJX4EIYV.js.map} +0 -0
- /package/dist/{doctor-3BOJJYBX.js.map → doctor-VUK3JE6Z.js.map} +0 -0
- /package/dist/{promote-L2VBS3X2.js.map → promote-UGQXA4KV.js.map} +0 -0
- /package/dist/{query-Y5XOM7X6.js.map → query-DL7RHPMA.js.map} +0 -0
- /package/dist/{registry-ID2KMJCU.js.map → registry-YIPKBRBH.js.map} +0 -0
- /package/dist/{request-planner-LHVZFBYR.js.map → request-planner-L2FAVNKP.js.map} +0 -0
- /package/dist/{review-candidates-ZNCQQKQS.js.map → review-candidates-RPUP4XBU.js.map} +0 -0
- /package/dist/{routing-OAYXRJ7K.js.map → routing-G66SVTRO.js.map} +0 -0
- /package/dist/{schedule-tool-K7UHGVQ2.js.map → schedule-tool-FOWPIWKP.js.map} +0 -0
- /package/dist/{scheduler-VQFLXG4Y.js.map → scheduler-GFVUPAD6.js.map} +0 -0
- /package/dist/{seat-Y7QTFQDR.js.map → seat-ZPH7DA5L.js.map} +0 -0
- /package/dist/{select-OC4FXEIP.js.map → select-2WTV2BI2.js.map} +0 -0
- /package/dist/{set-enabled-QBPTP6I4.js.map → set-enabled-KI2FINQD.js.map} +0 -0
- /package/dist/{tool-P257FZXB.js.map → tool-2P4LRWN4.js.map} +0 -0
- /package/dist/{tool-MEAHEWD2.js.map → tool-ZFQ46KU3.js.map} +0 -0
- /package/dist/{wiki-SZH2KSLQ.js.map → wiki-XATGT3DI.js.map} +0 -0
|
@@ -45,15 +45,25 @@ enum Config {
|
|
|
45
45
|
/// Where the pill was last dragged to (its bottom-left corner, in
|
|
46
46
|
/// screen points). Nil: the default corner.
|
|
47
47
|
static var pillOrigin: CGPoint? {
|
|
48
|
-
get {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
48
|
+
get { point("pillOrigin") }
|
|
49
|
+
set { setPoint(newValue, "pillOrigin") }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Where the pill reduced to its orb was last dragged to. Nil: the
|
|
53
|
+
/// middle of the bottom edge. Kept apart from the pill's own place.
|
|
54
|
+
static var orbOrigin: CGPoint? {
|
|
55
|
+
get { point("orbOrigin") }
|
|
56
|
+
set { setPoint(newValue, "orbOrigin") }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private static func point(_ key: String) -> CGPoint? {
|
|
60
|
+
guard let xy = UserDefaults.standard.array(forKey: key) as? [Double], xy.count == 2 else { return nil }
|
|
61
|
+
return CGPoint(x: xy[0], y: xy[1])
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private static func setPoint(_ p: CGPoint?, _ key: String) {
|
|
65
|
+
if let p { UserDefaults.standard.set([Double(p.x), Double(p.y)], forKey: key) }
|
|
66
|
+
else { UserDefaults.standard.removeObject(forKey: key) }
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
/// Where the character was last dragged to (the point under it, in
|
|
@@ -36,6 +36,12 @@ final class Panel: NSPanel {
|
|
|
36
36
|
let separator = NSBox()
|
|
37
37
|
/// Hidden by close, Esc or the menu until the next talk key.
|
|
38
38
|
var dismissed = false
|
|
39
|
+
/// Reduced to the orb alone (#457): a small circle with no words and no
|
|
40
|
+
/// buttons, dragged and remembered apart from the pill. A click, a
|
|
41
|
+
/// call or an answer to read opens the full pill again.
|
|
42
|
+
private(set) var reduced = false
|
|
43
|
+
/// Told when the pill reduces or opens.
|
|
44
|
+
var onReduced: ((Bool) -> Void)?
|
|
39
45
|
/// Above zero while the app moves or resizes the pill, so only a drag
|
|
40
46
|
/// is remembered.
|
|
41
47
|
var placing = 0
|
|
@@ -136,7 +142,10 @@ final class Panel: NSPanel {
|
|
|
136
142
|
let now = NSEvent.mouseLocation
|
|
137
143
|
let moved = hypot(now.x - start.x, now.y - start.y)
|
|
138
144
|
let onRow = convertToScreen(row.convert(row.bounds, to: nil)).contains(start)
|
|
139
|
-
|
|
145
|
+
// Reduced, a click opens the pill; it does not start talking.
|
|
146
|
+
if moved < 4 && onRow {
|
|
147
|
+
if reduced { MainActor.assumeIsolated { setReduced(false) } } else { onClick?() }
|
|
148
|
+
}
|
|
140
149
|
}
|
|
141
150
|
super.mouseUp(with: event)
|
|
142
151
|
}
|
|
@@ -201,6 +210,14 @@ final class Panel: NSPanel {
|
|
|
201
210
|
}
|
|
202
211
|
}
|
|
203
212
|
|
|
213
|
+
/// A call must not be missed behind an orb: it opens the full pill.
|
|
214
|
+
var opensFullPill: Bool {
|
|
215
|
+
switch self {
|
|
216
|
+
case .ringing, .onCall: return true
|
|
217
|
+
default: return false
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
204
221
|
/// Idle is an invitation and belongs in meta type; everything else
|
|
205
222
|
/// is a running commentary and belongs in body type.
|
|
206
223
|
var isMeta: Bool { if case .idle = self { return true }; return false }
|
|
@@ -312,6 +329,9 @@ final class Panel: NSPanel {
|
|
|
312
329
|
let answerHeight = max(0, bounds.height - h)
|
|
313
330
|
let above = growth.above
|
|
314
331
|
row.frame = NSRect(x: 0, y: above ? 0 : answerHeight, width: bounds.width, height: h)
|
|
332
|
+
// Reduced, the orb is all there is: in the middle of its circle.
|
|
333
|
+
orb.frame.origin.x = reduced ? (bounds.width - Self.orbFrame) / 2 : 28 - Self.orbFrame / 2
|
|
334
|
+
if reduced { return }
|
|
315
335
|
closeButton.frame.origin.x = bounds.width - 28
|
|
316
336
|
// The mini orbs sit between the words and the close button, and
|
|
317
337
|
// the words give up that room while they show.
|
|
@@ -345,17 +365,41 @@ final class Panel: NSPanel {
|
|
|
345
365
|
}
|
|
346
366
|
let screens = NSScreen.screens.map(\.visibleFrame)
|
|
347
367
|
let fallback = (NSScreen.main ?? NSScreen.screens.first)?.visibleFrame ?? .zero
|
|
348
|
-
place(PillPlacement.clamp(saved: Config.pillOrigin, size: frame.size,
|
|
368
|
+
place(PillPlacement.clamp(saved: reduced ? Config.orbOrigin : Config.pillOrigin, size: frame.size,
|
|
369
|
+
screens: screens, fallback: fallback,
|
|
370
|
+
rest: reduced ? PillPlacement.orbOrigin : PillPlacement.defaultOrigin))
|
|
349
371
|
}
|
|
350
372
|
|
|
351
|
-
/// Back to the bottom-right corner
|
|
373
|
+
/// Back to where it first sat (the pill: the bottom-right corner; the
|
|
374
|
+
/// orb: the middle of the bottom edge), forgetting where it was dragged.
|
|
352
375
|
/// Not while it is the character's bubble: nothing would move, and
|
|
353
376
|
/// the place kept for the orb look would be lost.
|
|
354
377
|
@MainActor
|
|
355
378
|
func resetPosition() {
|
|
356
379
|
guard bubble == nil else { return }
|
|
357
|
-
Config.pillOrigin = nil
|
|
380
|
+
if reduced { Config.orbOrigin = nil } else { Config.pillOrigin = nil }
|
|
381
|
+
restorePosition()
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/// Reduce the pill to its orb, or open it again. The two forms keep
|
|
385
|
+
/// their own places. Nothing to reduce to while the character stands
|
|
386
|
+
/// in for the orb.
|
|
387
|
+
@MainActor
|
|
388
|
+
func setReduced(_ on: Bool) {
|
|
389
|
+
guard reduced != on, !on || PillMenu.canReduce(showsOrb: showsOrb) else { return }
|
|
390
|
+
collapse(animated: false)
|
|
391
|
+
reduced = on
|
|
392
|
+
clip?.isHidden = on
|
|
393
|
+
closeButton.isHidden = true
|
|
394
|
+
miniOrbs.isHidden = on || busyCount == 0
|
|
395
|
+
(contentView as? Surface)?.shape(circle: on ? PillPlacement.orbSize.height : nil)
|
|
396
|
+
placing += 1
|
|
397
|
+
setContentSize(on ? PillPlacement.orbSize : Self.size)
|
|
398
|
+
placing -= 1
|
|
358
399
|
restorePosition()
|
|
400
|
+
invalidateShadow()
|
|
401
|
+
render(current)
|
|
402
|
+
onReduced?(on)
|
|
359
403
|
}
|
|
360
404
|
|
|
361
405
|
/// The character's speech bubble (#491): the pill sits above `head`,
|
|
@@ -396,6 +440,7 @@ final class Panel: NSPanel {
|
|
|
396
440
|
@objc private func moved() {
|
|
397
441
|
MainActor.assumeIsolated {
|
|
398
442
|
guard placing == 0 else { return }
|
|
443
|
+
if reduced { Config.orbOrigin = frame.origin; return }
|
|
399
444
|
Config.pillOrigin = expanded ? collapsedFrame().origin : frame.origin
|
|
400
445
|
}
|
|
401
446
|
}
|
|
@@ -427,6 +472,7 @@ final class Panel: NSPanel {
|
|
|
427
472
|
@MainActor
|
|
428
473
|
func setShowsOrb(_ on: Bool) {
|
|
429
474
|
guard showsOrb != on else { return }
|
|
475
|
+
if !on { setReduced(false) }
|
|
430
476
|
showsOrb = on
|
|
431
477
|
orb.isHidden = !on
|
|
432
478
|
orb.setOnScreen(on && isVisible)
|
|
@@ -451,7 +497,7 @@ final class Panel: NSPanel {
|
|
|
451
497
|
@objc private func closeClicked() { onDismiss?() }
|
|
452
498
|
|
|
453
499
|
override func mouseEntered(with event: NSEvent) {
|
|
454
|
-
closeButton.isHidden =
|
|
500
|
+
closeButton.isHidden = reduced
|
|
455
501
|
hovering = true
|
|
456
502
|
MainActor.assumeIsolated { armCollapse() }
|
|
457
503
|
}
|
|
@@ -484,6 +530,7 @@ final class Panel: NSPanel {
|
|
|
484
530
|
/// corruption that traps somewhere unrelated an hour later.
|
|
485
531
|
@MainActor
|
|
486
532
|
func render(_ state: State) {
|
|
533
|
+
if reduced && state.opensFullPill { setReduced(false) }
|
|
487
534
|
current = state
|
|
488
535
|
// The agent's colour, except where the state is the message: an
|
|
489
536
|
// error, or notifications held.
|
|
@@ -514,7 +561,8 @@ final class Panel: NSPanel {
|
|
|
514
561
|
|
|
515
562
|
// Grown into an answer, it stays until it collapses, idle or not;
|
|
516
563
|
// so does a pill with agents still busy in its mini orbs.
|
|
517
|
-
|
|
564
|
+
// Reduced, the orb is the assistant's place on screen: it stays, idle or not.
|
|
565
|
+
if dismissed || (state.isMeta && !alwaysVisible && !expanded && busyCount == 0 && !reduced) { hide() } else { show() }
|
|
518
566
|
// After showing or hiding: a still character draws its bubble's
|
|
519
567
|
// tail only while the bubble is on screen.
|
|
520
568
|
onLook?(state, tint, colors)
|
|
@@ -526,6 +574,7 @@ final class Panel: NSPanel {
|
|
|
526
574
|
@MainActor
|
|
527
575
|
func showCall(_ mode: CallBar.Mode) {
|
|
528
576
|
guard mode != callBar.mode else { return }
|
|
577
|
+
if mode != .hidden { setReduced(false) }
|
|
529
578
|
callBar.show(mode)
|
|
530
579
|
if let content = contentView { layoutContent(content.bounds) }
|
|
531
580
|
}
|
|
@@ -536,7 +585,7 @@ final class Panel: NSPanel {
|
|
|
536
585
|
func showBusy(_ orbs: [MiniOrbsModel.Orb], more: Int) {
|
|
537
586
|
let count = orbs.isEmpty ? 0 : orbs.count + more
|
|
538
587
|
miniOrbs.show(orbs, more: more)
|
|
539
|
-
miniOrbs.isHidden = count == 0
|
|
588
|
+
miniOrbs.isHidden = count == 0 || reduced
|
|
540
589
|
if count != busyCount {
|
|
541
590
|
busyCount = count
|
|
542
591
|
if let content = contentView { layoutContent(content.bounds) }
|
|
@@ -23,6 +23,8 @@ extension Panel {
|
|
|
23
23
|
@MainActor
|
|
24
24
|
func grow(answerHeight: CGFloat) {
|
|
25
25
|
guard !dismissed else { return }
|
|
26
|
+
// An answer to read, or one that asks: the full pill opens for it.
|
|
27
|
+
setReduced(false)
|
|
26
28
|
let pill = collapsedFrame()
|
|
27
29
|
guard let visible = visibleFrame(for: pill) else { return }
|
|
28
30
|
let height = min(Self.size.height + min(answerHeight, cardMaxHeight), visible.height)
|
|
@@ -13,4 +13,13 @@ enum PillMenu {
|
|
|
13
13
|
static func click(showPill: Bool, visible: Bool) -> Bool {
|
|
14
14
|
!isChecked(showPill: showPill, visible: visible)
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
/// The item that reduces the pill to its orb, or brings the pill back.
|
|
18
|
+
static func reduceTitle(reduced: Bool) -> String {
|
|
19
|
+
reduced ? "Show full pill" : "Reduce to orb"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/// Only a pill that has its orb can be reduced to it: while the
|
|
23
|
+
/// character stands in for the orb, there is nothing to reduce to.
|
|
24
|
+
static func canReduce(showsOrb: Bool) -> Bool { showsOrb }
|
|
16
25
|
}
|
|
@@ -13,13 +13,24 @@ enum PillPlacement {
|
|
|
13
13
|
CGPoint(x: visible.maxX - size.width - inset, y: visible.minY + inset)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/// The pill reduced to its orb: a circle as tall as the pill.
|
|
17
|
+
static let orbSize = CGSize(width: 54, height: 54)
|
|
18
|
+
|
|
19
|
+
/// Where the reduced orb first sits: the middle of the bottom edge of
|
|
20
|
+
/// `visible`, clear of the Dock.
|
|
21
|
+
static func orbOrigin(size: CGSize, visible: CGRect) -> CGPoint {
|
|
22
|
+
CGPoint(x: (visible.midX - size.width / 2).rounded(), y: visible.minY + inset)
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
/// A saved position made safe: the pill lands fully on the screen it
|
|
17
26
|
/// overlaps most. When it overlaps none (the monitor it was on has been
|
|
18
27
|
/// unplugged, or the saved value is nonsense) it goes back to the
|
|
19
|
-
/// default
|
|
20
|
-
|
|
28
|
+
/// default place on `fallback`. Nil `saved`: the default place, which
|
|
29
|
+
/// is the bottom-right corner unless `rest` says otherwise.
|
|
30
|
+
static func clamp(saved: CGPoint?, size: CGSize, screens: [CGRect], fallback: CGRect,
|
|
31
|
+
rest defaultOrigin: (CGSize, CGRect) -> CGPoint = PillPlacement.defaultOrigin) -> CGPoint {
|
|
21
32
|
guard let saved, saved.x.isFinite, saved.y.isFinite else {
|
|
22
|
-
return defaultOrigin(size
|
|
33
|
+
return defaultOrigin(size, fallback)
|
|
23
34
|
}
|
|
24
35
|
let frame = CGRect(origin: saved, size: size)
|
|
25
36
|
var best: CGRect?
|
|
@@ -31,7 +42,7 @@ enum PillPlacement {
|
|
|
31
42
|
if area > bestArea { bestArea = area; best = screen }
|
|
32
43
|
}
|
|
33
44
|
guard let screen = best, bestArea > 0 else {
|
|
34
|
-
return defaultOrigin(size
|
|
45
|
+
return defaultOrigin(size, fallback)
|
|
35
46
|
}
|
|
36
47
|
return inside(frame, screen).origin
|
|
37
48
|
}
|
|
@@ -55,6 +55,8 @@ struct PalettePicker: View {
|
|
|
55
55
|
/// "Shown as": the orb, or the character that stands in for it (#458).
|
|
56
56
|
struct LookSection: View {
|
|
57
57
|
@Binding var look: String
|
|
58
|
+
/// Nil hides the control: the daemon is older than the reduced pill.
|
|
59
|
+
var startReduced: Binding<Bool>?
|
|
58
60
|
|
|
59
61
|
var body: some View {
|
|
60
62
|
Section {
|
|
@@ -62,6 +64,10 @@ struct LookSection: View {
|
|
|
62
64
|
Text("Orb").tag("orb")
|
|
63
65
|
Text("Character").tag("character")
|
|
64
66
|
}
|
|
67
|
+
if let startReduced {
|
|
68
|
+
Toggle("Start reduced to the orb", isOn: startReduced)
|
|
69
|
+
.disabled(look == "character")
|
|
70
|
+
}
|
|
65
71
|
} header: {
|
|
66
72
|
Text("Assistant")
|
|
67
73
|
} footer: {
|
|
@@ -375,7 +375,10 @@ private struct GeneralTab: View {
|
|
|
375
375
|
}
|
|
376
376
|
if draft.general.look != nil {
|
|
377
377
|
LookSection(look: Binding(get: { model.draft?.general.look ?? "orb" },
|
|
378
|
-
set: { model.draft?.general.look = $0 })
|
|
378
|
+
set: { model.draft?.general.look = $0 }),
|
|
379
|
+
startReduced: draft.general.startReduced == nil ? nil
|
|
380
|
+
: Binding(get: { model.draft?.general.startReduced ?? false },
|
|
381
|
+
set: { model.draft?.general.startReduced = $0 }))
|
|
379
382
|
}
|
|
380
383
|
if draft.general.card != nil {
|
|
381
384
|
AnswerCardSection(card: Binding(get: { model.draft?.general.card ?? .standard },
|
|
@@ -49,6 +49,11 @@ final class StatusMenu: NSObject, NSMenuDelegate {
|
|
|
49
49
|
var onResetPosition: (() -> Void)?
|
|
50
50
|
/// Whether the pill is on screen, for "Hide pill" and "Show floating pill".
|
|
51
51
|
var pillVisible: () -> Bool = { false }
|
|
52
|
+
/// Whether the pill is reduced to its orb, and whether it can be.
|
|
53
|
+
var pillReduced: () -> Bool = { false }
|
|
54
|
+
var canReduce: () -> Bool = { true }
|
|
55
|
+
/// Reduce the pill to its orb (true), or open it again.
|
|
56
|
+
var onReduce: ((Bool) -> Void)?
|
|
52
57
|
/// The character look: whether the character is on screen. Nil with
|
|
53
58
|
/// the orb look.
|
|
54
59
|
var characterVisible: () -> Bool? = { nil }
|
|
@@ -248,6 +253,9 @@ final class StatusMenu: NSObject, NSMenuDelegate {
|
|
|
248
253
|
let pill = action("Show floating pill", #selector(togglePill), key: "")
|
|
249
254
|
pill.state = PillMenu.isChecked(showPill: Config.showPill, visible: pillVisible()) ? .on : .off
|
|
250
255
|
menu.addItem(pill)
|
|
256
|
+
let reduce = action(PillMenu.reduceTitle(reduced: pillReduced()), #selector(toggleReduce), key: "")
|
|
257
|
+
reduce.isEnabled = pillReduced() || canReduce()
|
|
258
|
+
menu.addItem(reduce)
|
|
251
259
|
let orb = action("Animated orb", #selector(toggleOrb), key: "")
|
|
252
260
|
orb.state = Config.animatedOrb ? .on : .off
|
|
253
261
|
menu.addItem(orb)
|
|
@@ -324,6 +332,7 @@ final class StatusMenu: NSObject, NSMenuDelegate {
|
|
|
324
332
|
onAnimatedOrbChanged?(Config.animatedOrb)
|
|
325
333
|
}
|
|
326
334
|
|
|
335
|
+
@objc private func toggleReduce() { onReduce?(!pillReduced()) }
|
|
327
336
|
@objc private func togglePlayMode() { Config.playMode.toggle() }
|
|
328
337
|
@objc private func startPlay() { onPlay?() }
|
|
329
338
|
|
|
@@ -50,6 +50,25 @@ final class Surface: NSVisualEffectView {
|
|
|
50
50
|
@available(*, unavailable)
|
|
51
51
|
required init?(coder: NSCoder) { fatalError("not from a nib") }
|
|
52
52
|
|
|
53
|
+
/// The pill's own shape, or a circle `diameter` across for the pill
|
|
54
|
+
/// reduced to its orb. The stretchable mask cannot make a circle: its
|
|
55
|
+
/// corners would be wider than the view.
|
|
56
|
+
func shape(circle diameter: CGFloat?) {
|
|
57
|
+
guard let diameter else {
|
|
58
|
+
layer?.cornerRadius = Brand.Radius.lg
|
|
59
|
+
layer?.cornerCurve = .continuous
|
|
60
|
+
maskImage = Self.mask(radius: Brand.Radius.lg)
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
layer?.cornerRadius = diameter / 2
|
|
64
|
+
layer?.cornerCurve = .circular
|
|
65
|
+
maskImage = NSImage(size: NSSize(width: diameter, height: diameter), flipped: false) { rect in
|
|
66
|
+
NSColor.black.setFill()
|
|
67
|
+
NSBezierPath(ovalIn: rect).fill()
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
53
72
|
override func resizeSubviews(withOldSize oldSize: NSSize) {
|
|
54
73
|
super.resizeSubviews(withOldSize: oldSize)
|
|
55
74
|
layoutContent?(bounds)
|
|
@@ -29,12 +29,16 @@ struct VoiceSettings: Codable, Equatable {
|
|
|
29
29
|
/// What shows the assistant's state: "orb" or "character". Nil
|
|
30
30
|
/// from a daemon older than the character.
|
|
31
31
|
var look: String?
|
|
32
|
+
/// The pill starts reduced to its orb. Nil from a daemon older
|
|
33
|
+
/// than the reduced pill.
|
|
34
|
+
var startReduced: Bool?
|
|
32
35
|
|
|
33
36
|
init(provider: String, fallback: String, stt: String, localStt: String = "mlx-whisper",
|
|
34
|
-
endOfTurn: String = "vad", hotkeys: Hotkeys, card: Card? = nil, look: String? = nil
|
|
37
|
+
endOfTurn: String = "vad", hotkeys: Hotkeys, card: Card? = nil, look: String? = nil,
|
|
38
|
+
startReduced: Bool? = nil) {
|
|
35
39
|
self.provider = provider; self.fallback = fallback; self.stt = stt
|
|
36
40
|
self.localStt = localStt; self.endOfTurn = endOfTurn; self.hotkeys = hotkeys
|
|
37
|
-
self.card = card; self.look = look
|
|
41
|
+
self.card = card; self.look = look; self.startReduced = startReduced
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
/// A daemon from before these fields leaves them out: the defaults.
|
|
@@ -48,6 +52,7 @@ struct VoiceSettings: Codable, Equatable {
|
|
|
48
52
|
hotkeys = try c.decode(Hotkeys.self, forKey: .hotkeys)
|
|
49
53
|
card = try c.decodeIfPresent(Card.self, forKey: .card)
|
|
50
54
|
look = try c.decodeIfPresent(String.self, forKey: .look)
|
|
55
|
+
startReduced = try c.decodeIfPresent(Bool.self, forKey: .startReduced)
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
58
|
struct Voice: Codable, Equatable {
|
|
@@ -107,6 +112,7 @@ struct VoiceSettings: Codable, Equatable {
|
|
|
107
112
|
if self.general.localStt != old.general.localStt { general["localStt"] = self.general.localStt }
|
|
108
113
|
if self.general.endOfTurn != old.general.endOfTurn { general["endOfTurn"] = self.general.endOfTurn }
|
|
109
114
|
if let look = self.general.look, look != old.general.look { general["look"] = look }
|
|
115
|
+
if let start = self.general.startReduced, start != old.general.startReduced { general["startReduced"] = start }
|
|
110
116
|
var keys: [String: Any] = [:]
|
|
111
117
|
if self.general.hotkeys.talk != old.general.hotkeys.talk { keys["talk"] = self.general.hotkeys.talk }
|
|
112
118
|
if self.general.hotkeys.stop != old.general.hotkeys.stop { keys["stop"] = self.general.hotkeys.stop }
|
|
@@ -20,6 +20,8 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
20
20
|
private let statusMenu = StatusMenu()
|
|
21
21
|
/// Stands in for the pill's orb when voice.look is "character".
|
|
22
22
|
private let character = CharacterHost()
|
|
23
|
+
/// voice.startReduced has been applied for this launch.
|
|
24
|
+
private var startApplied = false
|
|
23
25
|
/// The character playing on a frozen picture of the screen (#505).
|
|
24
26
|
private let play = PlayHost()
|
|
25
27
|
/// The agent whose by-name answer is on screen now, while no turn runs.
|
|
@@ -212,6 +214,11 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
212
214
|
panel.setShowsOrb(!asCharacter)
|
|
213
215
|
character.setShown(asCharacter)
|
|
214
216
|
if !asCharacter { panel.detach() }
|
|
217
|
+
// voice.startReduced is how the assistant starts: read once.
|
|
218
|
+
if !startApplied {
|
|
219
|
+
startApplied = true
|
|
220
|
+
if saved.general.startReduced == true, !asCharacter { panel.summon(); panel.setReduced(true) }
|
|
221
|
+
}
|
|
215
222
|
if settingsWindow.model.recording == nil { registerHotkeys() }
|
|
216
223
|
// Colours may have changed.
|
|
217
224
|
statusMenu.refresh()
|
|
@@ -403,6 +410,15 @@ final class App: NSObject, NSApplicationDelegate {
|
|
|
403
410
|
panel.answer.onOpenChat = { [weak self] in self?.openChat() }
|
|
404
411
|
statusMenu.pillVisible = { [weak self] in self?.panel.isVisible ?? false }
|
|
405
412
|
statusMenu.onHidePill = { [weak self] in self?.dismissPill() }
|
|
413
|
+
statusMenu.pillReduced = { [weak self] in self?.panel.reduced ?? false }
|
|
414
|
+
statusMenu.canReduce = { [weak self] in PillMenu.canReduce(showsOrb: self?.panel.showsOrb ?? true) }
|
|
415
|
+
statusMenu.onReduce = { [weak self] on in
|
|
416
|
+
guard let self else { return }
|
|
417
|
+
Log.info("pill: \(on ? "reduced to the orb" : "opened")")
|
|
418
|
+
// Asking for the orb brings back a pill that was dismissed.
|
|
419
|
+
if on { self.panel.summon() }
|
|
420
|
+
self.panel.setReduced(on)
|
|
421
|
+
}
|
|
406
422
|
statusMenu.characterVisible = { [weak self] in self?.character.onScreen }
|
|
407
423
|
statusMenu.onShowCharacter = { [weak self] in self?.summonPill() }
|
|
408
424
|
// Each does nothing with the other's look.
|
|
@@ -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-
|
|
1
|
+
import{a as F,b as L,c as U,d as N,e as O,f as H,g as j}from"./chunk-U2CKL755.js";import{b as B,c as D,d as A,e as P,g as M}from"./chunk-IPDEWVVT.js";import"./chunk-XEKZKH3W.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useEffect as R,useReducer as V,useRef as G}from"react";import{Box as i,Text as o,useApp as W,useInput as J}from"ink";import{randomUUID as z}from"crypto";async function*q(e){let r=[];e.type&&r.push(`type=${encodeURIComponent(e.type)}`);let t=`${e.baseUrl.replace(/\/+$/,"")}/events${r.length?`?${r.join("&")}`:""}`,n={Accept:"text/event-stream"};e.token&&(n.Authorization=`Bearer ${e.token}`);let s=await fetch(t,{headers:n,signal:e.signal});if(!s.ok||!s.body)throw new Error(`SSE connect failed: HTTP ${s.status}`);let u=s.body.getReader(),p=new TextDecoder,y="";try{for(;;){let{done:f,value:l}=await u.read();if(f)return;y+=p.decode(l,{stream:!0});let d;for(;(d=y.indexOf(`
|
|
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-
|
|
8
|
+
//# sourceMappingURL=App-UHSIO3UE.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-
|
|
1
|
+
import{a as Y,b as Z,c as _,d as ee,e as te,f as ne,g as re}from"./chunk-U2CKL755.js";import{b as Q,g as X}from"./chunk-IPDEWVVT.js";import"./chunk-XEKZKH3W.js";import"./chunk-RJ7DASOU.js";import"./chunk-BRK6M6LA.js";import"./chunk-2QNT5JDS.js";import"./chunk-QIJLFPWE.js";import{useCallback as oe,useMemo as H,useRef as P,useState as k}from"react";import{Box as g,Text as t,useApp as he,useInput as xe,useStdout as Te}from"ink";import{randomUUID as se}from"crypto";var m={accent:"cyan",agent:"green",working:"magenta",error:"red",muted:"gray"},q="\u25C7 agentx",F="\u258C";import{jsx as c,jsxs as o}from"react/jsx-runtime";var ie="/help /agent <id> /agents /clear /who /exit",be=[{cmd:"/agent",desc:"switch the target agent (/agent <id>)"},{cmd:"/agents",desc:"list registered agents"},{cmd:"/clear",desc:"start a fresh session"},{cmd:"/who",desc:"show agent + chat id"},{cmd:"/help",desc:"list commands"},{cmd:"/exit",desc:"quit the chat"}];function Pe({conn:n,agentId:p,channel:f,chatId:a,agents:h}){let{exit:w}=he(),{stdout:O}=Te(),V=Math.max(40,Math.min((O?.columns||80)-4,100)),[z,U]=k([]),[$,S]=k(null),[T,le]=k(p),[A,ae]=k(h),[E,ue]=k(a),[y,x]=k(""),[J,de]=k(""),W=P([]),u=P(-1),M=P(null),R=P(null),v=$?.live??!1,j=H(()=>Z(y,A.map(s=>s.id),process.cwd()),[y,A]),N=H(()=>{let s=/^\/(\w*)$/.exec(y);if(!s)return null;let e=be.filter(r=>r.cmd.slice(1).startsWith(s[1].toLowerCase()));return e.length?e:null},[y]),b=s=>de(s),K=oe(s=>{let e=se().slice(0,8),r=Date.now(),i=new AbortController;R.current=i;let d={id:e,you:s,agentId:T,segs:[],live:!0,startedAt:r};S({...d});let L=()=>S({...d,segs:d.segs.map(C=>({...C}))});(async()=>{try{let C=await X(n,T,s,{channel:f,chatId:E,signal:i.signal,onText:l=>{let I=d.segs[d.segs.length-1];I&&I.type==="text"?I.content=(I.content??"")+l:d.segs.push({type:"text",content:l}),L()},onThinking:l=>{d.thinking=(d.thinking??"")+l,L()},onTool:l=>{l.status==="start"&&l.name?(d.segs.push({type:"tool",name:l.name,arg:l.arg}),L()):l.status==="result"&&l.error&&(d.segs.push({type:"tool",name:l.name??"tool",error:!0}),L())}});U(l=>[...l,{...d,live:!1,elapsedMs:Date.now()-r,outTokens:C.usage?.outputTokens,error:C.error}]),S(null)}catch(C){let l=i.signal.aborted||C?.name==="AbortError";U(I=>[...I,{...d,live:!1,elapsedMs:Date.now()-r,interrupted:l,error:l?void 0:C?.message||String(C)}]),S(null)}finally{R.current===i&&(R.current=null)}})()},[n,T,f,E]),me=oe(s=>{let e=s.trim();if(e){if(W.current.push(e),u.current=-1,e==="/exit"||e==="/quit"){w();return}if(e==="/help"){b(ie);return}if(e==="/who"){b(`@${T} \xB7 chatId=${E} \xB7 channel=${f}`);return}if(e==="/clear"){let r=`chat-cli:${se().slice(0,12)}`;ue(r),U([]),b(`fresh chatId=${r} (warm process dropped)`);return}if(e==="/agents"){Q(n).then(r=>{ae(r),b(r.map(i=>i.id===T?`[${i.id}]`:i.id).join(" "))}).catch(r=>b(`failed to list agents: ${r?.message||r}`));return}if(e.startsWith("/agent ")){let r=e.slice(7).replace(/^@/,"").trim();if(!r){b("usage: /agent <id>");return}if(!A.find(i=>i.id===r)){b(`unknown agent: @${r}`);return}le(r),b(`now talking to @${r}`);return}if(e.startsWith("/")){b(`unknown command \xB7 ${ie}`);return}K(e)}},[n,T,A,f,E,w,K]);xe((s,e)=>{if(e.ctrl&&s==="c"){w();return}if(e.escape){if(v&&R.current){R.current.abort();return}w();return}if(e.tab){if(N){x(N[0].cmd+" ");return}let i=_(y,M,A.map(d=>d.id),process.cwd());i!==null&&(x(i),u.current=-1);return}if(e.upArrow){let i=W.current;if(!i.length)return;u.current=u.current<0?i.length-1:Math.max(0,u.current-1),x(i[u.current]??"");return}if(e.downArrow){let i=W.current;if(u.current<0)return;if(u.current=u.current+1,u.current>=i.length){u.current=-1,x("");return}x(i[u.current]??"");return}if(e.backspace||e.delete){M.current=null,x(i=>i.slice(0,-1));return}if(e.ctrl||e.meta)return;let r=ee(s??"",e.return,y);switch(r.kind){case"paste":M.current=null,x(i=>i+r.text),u.current=-1;return;case"type":M.current=null,x(i=>i+r.text),u.current=-1;return;case"continue":x(r.buffer);return;case"submit":if(v)return;M.current=null,x(""),me(r.text);return;case"none":return}});let G=v?m.working:m.accent,ge=y.length?y.split(`
|
|
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-
|
|
7
|
+
//# sourceMappingURL=ChatApp-LLTFBLJY.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{A as a,B as b,C as c}from"./chunk-
|
|
2
|
-
//# sourceMappingURL=agent-
|
|
1
|
+
import{A as a,B as b,C as c}from"./chunk-QZIEYDIY.js";import"./chunk-SFQUP3BP.js";import"./chunk-QOYAX2FT.js";import"./chunk-5MUJZODV.js";import"./chunk-7I7IEX4S.js";import"./chunk-JHCI6XCJ.js";import"./chunk-DSYKYZMT.js";import"./chunk-QIJLFPWE.js";export{a as createAgentContext,b as generate,c as generateStream};
|
|
2
|
+
//# sourceMappingURL=agent-6RJ633MQ.js.map
|