agentix-cli 0.59.0 → 0.61.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 (119) hide show
  1. package/apps/mac-voice/Sources/AgentXVoice/AgentClient.swift +4 -0
  2. package/apps/mac-voice/Sources/AgentXVoice/AnswerView.swift +228 -0
  3. package/apps/mac-voice/Sources/AgentXVoice/Orb.swift +36 -9
  4. package/apps/mac-voice/Sources/AgentXVoice/Panel.swift +126 -55
  5. package/apps/mac-voice/Sources/AgentXVoice/PanelAnswer.swift +113 -0
  6. package/apps/mac-voice/Sources/AgentXVoice/PillPlacement.swift +28 -17
  7. package/apps/mac-voice/Sources/AgentXVoice/SettingsLook.swift +90 -0
  8. package/apps/mac-voice/Sources/AgentXVoice/SettingsWindow.swift +10 -3
  9. package/apps/mac-voice/Sources/AgentXVoice/StatusMenu.swift +9 -0
  10. package/apps/mac-voice/Sources/AgentXVoice/Surface.swift +105 -0
  11. package/apps/mac-voice/Sources/AgentXVoice/VoiceSettings.swift +32 -1
  12. package/apps/mac-voice/Sources/AgentXVoice/main.swift +23 -10
  13. package/dist/{App-QEJGXZTY.js → App-LQXWKBVY.js} +2 -2
  14. package/dist/{ChatApp-VKWQN5GM.js → ChatApp-75TL4LKW.js} +2 -2
  15. package/dist/{agent-MJKLI2L5.js → agent-DH4FMMMY.js} +2 -2
  16. package/dist/{board-dashboard-2KVT72J7.js → board-dashboard-C6AZHDHU.js} +657 -188
  17. package/dist/board-dashboard-C6AZHDHU.js.map +1 -0
  18. package/dist/{chunk-WFPRVZBA.js → chunk-27P5NLTC.js} +2 -2
  19. package/dist/{chunk-3EVCHRJF.js → chunk-2VQIPJH5.js} +2 -2
  20. package/dist/{chunk-YRB75GMN.js → chunk-3XVTFNYM.js} +2 -2
  21. package/dist/{chunk-K62U5EJJ.js → chunk-B3DCYBP4.js} +2 -2
  22. package/dist/{chunk-ILXW3ERG.js → chunk-BCXKRD5L.js} +159 -153
  23. package/dist/chunk-BCXKRD5L.js.map +1 -0
  24. package/dist/{chunk-EJQOKSKP.js → chunk-CRSXKQLZ.js} +2 -2
  25. package/dist/{chunk-YCIZ2WHX.js → chunk-DTEQNXK3.js} +2 -2
  26. package/dist/{chunk-N5GOBLUI.js → chunk-E2BJVHBR.js} +2 -2
  27. package/dist/{chunk-6DUTIPTY.js → chunk-E2PWCU2N.js} +2 -2
  28. package/dist/{chunk-2XZGHIVP.js → chunk-JO3PSLWL.js} +5 -5
  29. package/dist/{chunk-YQU74AOL.js → chunk-JORXRF4E.js} +2 -2
  30. package/dist/{chunk-DAAWUFO4.js → chunk-LXUG2X26.js} +2 -2
  31. package/dist/{chunk-JUY77L7C.js → chunk-N5KD3TVN.js} +2 -2
  32. package/dist/{chunk-5OF3EGCZ.js → chunk-NBGNPKAF.js} +2 -2
  33. package/dist/chunk-RVEMQCWW.js +130 -0
  34. package/dist/chunk-RVEMQCWW.js.map +1 -0
  35. package/dist/chunk-S7TCVIET.js +15 -0
  36. package/dist/chunk-S7TCVIET.js.map +1 -0
  37. package/dist/{chunk-WI5R64WO.js → chunk-WBGC7MWX.js} +2 -2
  38. package/dist/{chunk-6ZV2QFXE.js → chunk-WIBMNQKJ.js} +2 -2
  39. package/dist/{chunk-L5OCF33B.js → chunk-WOPFHKBF.js} +2 -2
  40. package/dist/{chunk-SDBU6747.js → chunk-Y76THZUQ.js} +178 -276
  41. package/dist/chunk-Y76THZUQ.js.map +1 -0
  42. package/dist/{chunk-OIDMPPV5.js → chunk-YQCOX4R3.js} +2 -2
  43. package/dist/cli.js +1 -1
  44. package/dist/client-QVZIZFV4.js +2 -0
  45. package/dist/config-3XC7EYB7.js +2 -0
  46. package/dist/config-mutator-HKU63FJM.js +2 -0
  47. package/dist/doctor-YFA4ZSRH.js +2 -0
  48. package/dist/index.d.ts +49 -7
  49. package/dist/index.js +1 -1
  50. package/dist/program-L6VAFALE.js +2 -0
  51. package/dist/{promote-GBR6YSQW.js → promote-UR2GSHKC.js} +2 -2
  52. package/dist/query-XUP3BMVS.js +2 -0
  53. package/dist/{registry-P535FNLB.js → registry-PGALUW5L.js} +2 -2
  54. package/dist/{request-planner-KHTCHF7N.js → request-planner-NHE3IRJN.js} +2 -2
  55. package/dist/{review-candidates-Y5KCRUNU.js → review-candidates-6GKRSRBQ.js} +2 -2
  56. package/dist/{routing-RWCCDJ4D.js → routing-AQKHAU3Z.js} +2 -2
  57. package/dist/schedule-tool-6NMCLTIH.js +2 -0
  58. package/dist/scheduler-RAYGNDWT.js +2 -0
  59. package/dist/{seat-PJPKLH6L.js → seat-6FMW2QI4.js} +2 -2
  60. package/dist/{select-VMTJAX5X.js → select-5VONJMLH.js} +2 -2
  61. package/dist/{set-enabled-LPXH3ZQP.js → set-enabled-YHD3IJJZ.js} +2 -2
  62. package/dist/{tool-MWXG44OT.js → tool-MXJGLJZ5.js} +2 -2
  63. package/dist/wiki-ZQLEYY24.js +2 -0
  64. package/package.json +1 -1
  65. package/apps/mac-voice/Sources/AgentXVoice/ResultCard.swift +0 -198
  66. package/dist/board-dashboard-2KVT72J7.js.map +0 -1
  67. package/dist/chunk-4ZTV6JV7.js +0 -29
  68. package/dist/chunk-4ZTV6JV7.js.map +0 -1
  69. package/dist/chunk-ILXW3ERG.js.map +0 -1
  70. package/dist/chunk-IW4XIZAZ.js +0 -15
  71. package/dist/chunk-IW4XIZAZ.js.map +0 -1
  72. package/dist/chunk-SDBU6747.js.map +0 -1
  73. package/dist/client-X2PTYKVX.js +0 -2
  74. package/dist/config-XB2ORKWS.js +0 -2
  75. package/dist/config-mutator-KMXR3XDG.js +0 -2
  76. package/dist/doctor-6BIMNEGU.js +0 -2
  77. package/dist/program-DHDC6XYB.js +0 -2
  78. package/dist/query-672RGMXO.js +0 -2
  79. package/dist/schedule-tool-H46AK53H.js +0 -2
  80. package/dist/scheduler-3XLWBCX7.js +0 -2
  81. package/dist/wiki-QHMHVFWU.js +0 -2
  82. /package/dist/{App-QEJGXZTY.js.map → App-LQXWKBVY.js.map} +0 -0
  83. /package/dist/{ChatApp-VKWQN5GM.js.map → ChatApp-75TL4LKW.js.map} +0 -0
  84. /package/dist/{agent-MJKLI2L5.js.map → agent-DH4FMMMY.js.map} +0 -0
  85. /package/dist/{chunk-WFPRVZBA.js.map → chunk-27P5NLTC.js.map} +0 -0
  86. /package/dist/{chunk-3EVCHRJF.js.map → chunk-2VQIPJH5.js.map} +0 -0
  87. /package/dist/{chunk-YRB75GMN.js.map → chunk-3XVTFNYM.js.map} +0 -0
  88. /package/dist/{chunk-K62U5EJJ.js.map → chunk-B3DCYBP4.js.map} +0 -0
  89. /package/dist/{chunk-EJQOKSKP.js.map → chunk-CRSXKQLZ.js.map} +0 -0
  90. /package/dist/{chunk-YCIZ2WHX.js.map → chunk-DTEQNXK3.js.map} +0 -0
  91. /package/dist/{chunk-N5GOBLUI.js.map → chunk-E2BJVHBR.js.map} +0 -0
  92. /package/dist/{chunk-6DUTIPTY.js.map → chunk-E2PWCU2N.js.map} +0 -0
  93. /package/dist/{chunk-2XZGHIVP.js.map → chunk-JO3PSLWL.js.map} +0 -0
  94. /package/dist/{chunk-YQU74AOL.js.map → chunk-JORXRF4E.js.map} +0 -0
  95. /package/dist/{chunk-DAAWUFO4.js.map → chunk-LXUG2X26.js.map} +0 -0
  96. /package/dist/{chunk-JUY77L7C.js.map → chunk-N5KD3TVN.js.map} +0 -0
  97. /package/dist/{chunk-5OF3EGCZ.js.map → chunk-NBGNPKAF.js.map} +0 -0
  98. /package/dist/{chunk-WI5R64WO.js.map → chunk-WBGC7MWX.js.map} +0 -0
  99. /package/dist/{chunk-6ZV2QFXE.js.map → chunk-WIBMNQKJ.js.map} +0 -0
  100. /package/dist/{chunk-L5OCF33B.js.map → chunk-WOPFHKBF.js.map} +0 -0
  101. /package/dist/{chunk-OIDMPPV5.js.map → chunk-YQCOX4R3.js.map} +0 -0
  102. /package/dist/{client-X2PTYKVX.js.map → client-QVZIZFV4.js.map} +0 -0
  103. /package/dist/{config-XB2ORKWS.js.map → config-3XC7EYB7.js.map} +0 -0
  104. /package/dist/{config-mutator-KMXR3XDG.js.map → config-mutator-HKU63FJM.js.map} +0 -0
  105. /package/dist/{doctor-6BIMNEGU.js.map → doctor-YFA4ZSRH.js.map} +0 -0
  106. /package/dist/{program-DHDC6XYB.js.map → program-L6VAFALE.js.map} +0 -0
  107. /package/dist/{promote-GBR6YSQW.js.map → promote-UR2GSHKC.js.map} +0 -0
  108. /package/dist/{query-672RGMXO.js.map → query-XUP3BMVS.js.map} +0 -0
  109. /package/dist/{registry-P535FNLB.js.map → registry-PGALUW5L.js.map} +0 -0
  110. /package/dist/{request-planner-KHTCHF7N.js.map → request-planner-NHE3IRJN.js.map} +0 -0
  111. /package/dist/{review-candidates-Y5KCRUNU.js.map → review-candidates-6GKRSRBQ.js.map} +0 -0
  112. /package/dist/{routing-RWCCDJ4D.js.map → routing-AQKHAU3Z.js.map} +0 -0
  113. /package/dist/{schedule-tool-H46AK53H.js.map → schedule-tool-6NMCLTIH.js.map} +0 -0
  114. /package/dist/{scheduler-3XLWBCX7.js.map → scheduler-RAYGNDWT.js.map} +0 -0
  115. /package/dist/{seat-PJPKLH6L.js.map → seat-6FMW2QI4.js.map} +0 -0
  116. /package/dist/{select-VMTJAX5X.js.map → select-5VONJMLH.js.map} +0 -0
  117. /package/dist/{set-enabled-LPXH3ZQP.js.map → set-enabled-YHD3IJJZ.js.map} +0 -0
  118. /package/dist/{tool-MWXG44OT.js.map → tool-MXJGLJZ5.js.map} +0 -0
  119. /package/dist/{wiki-QHMHVFWU.js.map → wiki-ZQLEYY24.js.map} +0 -0
@@ -1,198 +0,0 @@
1
- import AppKit
2
- import WebKit
3
-
4
- /// What the agent said, in a form you can read, click and copy.
5
- ///
6
- /// Speech is lossy in one specific way that matters: a URL cannot be
7
- /// spoken usefully, an image cannot be spoken at all, and a name you have
8
- /// not seen written is a name you cannot act on. The spoken answer is
9
- /// deliberately short and stripped of exactly those things — so without a
10
- /// visual surface, everything worth keeping from a turn is the part that
11
- /// gets thrown away.
12
- ///
13
- /// Rich content arrives through the same `agentx:ui` directive Telegram
14
- /// and WhatsApp already use, parsed server-side, so an agent has one way to
15
- /// attach a link or a picture regardless of where it is speaking.
16
- final class ResultCard: NSPanel {
17
- // A web view, because agents write markdown — headings, bullets,
18
- // fenced code, tables. An NSTextView shows that as a mess of asterisks
19
- // and hashes, which defeats the card's only purpose: being MORE
20
- // readable than the spoken answer, not less.
21
- private let web = WKWebView()
22
- private let links = NSStackView()
23
- private let thumb = NSImageView()
24
-
25
- /// The pill's frame on screen, which the card attaches to. Set by the app.
26
- var anchor: (() -> NSRect)?
27
-
28
- init() {
29
- super.init(contentRect: NSRect(x: 0, y: 0, width: 380, height: 260),
30
- styleMask: [.titled, .closable, .resizable, .utilityWindow, .nonactivatingPanel],
31
- backing: .buffered, defer: false)
32
- title = "Agent"
33
- // Brand radius on the utility panel so it matches the pill it
34
- // sits above rather than defaulting to the system's corner.
35
- contentView?.wantsLayer = true
36
- isFloatingPanel = true
37
- level = .floating
38
- hidesOnDeactivate = false
39
- collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
40
-
41
- let content = NSView(frame: contentRect(forFrameRect: frame))
42
- content.autoresizingMask = [.width, .height]
43
-
44
- // Selectable, so the whole point — copying a link or a name out —
45
- // actually works. Editable would let a stray keystroke destroy the
46
- // answer before it is read.
47
- web.setValue(false, forKey: "drawsBackground")
48
- web.navigationDelegate = self
49
- web.autoresizingMask = [.width, .height]
50
- content.addSubview(web)
51
-
52
- thumb.imageScaling = .scaleProportionallyUpOrDown
53
- thumb.isHidden = true
54
- content.addSubview(thumb)
55
-
56
- links.orientation = .horizontal
57
- links.spacing = 8
58
- links.edgeInsets = NSEdgeInsets(top: 6, left: 10, bottom: 6, right: 10)
59
- content.addSubview(links)
60
-
61
- contentView = content
62
- layout(content)
63
- }
64
-
65
- private func layout(_ content: NSView) {
66
- let w = content.bounds.width, h = content.bounds.height
67
- let linkH: CGFloat = links.arrangedSubviews.isEmpty ? 0 : 34
68
- let imgH: CGFloat = thumb.isHidden ? 0 : 120
69
- thumb.frame = NSRect(x: 10, y: h - imgH - 10, width: w - 20, height: imgH)
70
- web.frame = NSRect(x: 0, y: linkH, width: w, height: h - linkH - imgH - (imgH > 0 ? 16 : 0))
71
- links.frame = NSRect(x: 0, y: 0, width: w, height: linkH)
72
- }
73
-
74
- /// Does this turn have anything the spoken answer did not already
75
- /// deliver?
76
- ///
77
- /// The card opened on every turn, including "Ok." — a window with one
78
- /// word in it, appearing and demanding dismissal, for an answer you had
79
- /// already heard. A surface that adds nothing is worse than no surface:
80
- /// it trains you to ignore it, so the turn where it DOES carry a link
81
- /// gets ignored too.
82
- ///
83
- /// Worth showing when there is rich content, a URL you could click, or
84
- /// materially more written than was spoken. Otherwise the speech was
85
- /// the whole answer.
86
- static func isWorthShowing(spoken: String, written: String?, buttons: [(String, String)], imageURL: String?) -> Bool {
87
- if !buttons.isEmpty || imageURL != nil { return true }
88
- let text = (written?.isEmpty == false ? written! : spoken)
89
- if text.range(of: #"https?://"#, options: .regularExpression) != nil { return true }
90
- // Speech drops formatting, so written is often a little longer for
91
- // the same content. Only a real difference counts.
92
- let spokenLen = spoken.trimmingCharacters(in: .whitespacesAndNewlines).count
93
- let writtenLen = text.trimmingCharacters(in: .whitespacesAndNewlines).count
94
- if writtenLen > spokenLen + 80 { return true }
95
- // Long enough that re-reading it beats re-hearing it.
96
- return writtenLen > 280
97
- }
98
-
99
- /// `spoken` is what was said; `written` is the fuller answer with the
100
- /// URLs and formatting the spoken form had to drop.
101
- @MainActor
102
- func show(spoken: String, written: String?, buttons: [(String, String)], imageURL: String?) {
103
- let source = (written?.isEmpty == false ? written! : spoken)
104
- web.loadHTMLString(Markdown.page(Markdown.toHTML(source), css: Brand.cardCSS), baseURL: nil)
105
-
106
- links.arrangedSubviews.forEach { links.removeArrangedSubview($0); $0.removeFromSuperview() }
107
- for (label, url) in buttons.prefix(4) {
108
- let b = NSButton(title: label, target: self, action: #selector(openLink(_:)))
109
- b.bezelStyle = .rounded
110
- b.toolTip = url
111
- b.identifier = NSUserInterfaceItemIdentifier(url)
112
- links.addArrangedSubview(b)
113
- }
114
-
115
- thumb.isHidden = true
116
- if let s = imageURL, let u = URL(string: s) {
117
- // Off the main thread: a slow image must never stall the UI,
118
- // and the card is useful without it.
119
- URLSession.shared.dataTask(with: u) { [weak self] data, _, _ in
120
- guard let data, let img = NSImage(data: data) else { return }
121
- Task { @MainActor in
122
- guard let self else { return }
123
- self.thumb.image = img
124
- self.thumb.isHidden = false
125
- if let c = self.contentView { self.layout(c) }
126
- }
127
- }.resume()
128
- }
129
-
130
- if let c = contentView { layout(c) }
131
- slideIn()
132
- }
133
-
134
- /// Where the card goes against the pill: above it when there is at
135
- /// least as much room above as below, else below; right edges aligned.
136
- @MainActor
137
- private func placement() -> PillPlacement.Card? {
138
- guard let pill = anchor?() else { return nil }
139
- let screen = NSScreen.screens.first { $0.frame.intersects(pill) } ?? NSScreen.main
140
- guard let visible = screen?.visibleFrame else { return nil }
141
- return PillPlacement.card(size: frame.size, pill: pill, visible: visible)
142
- }
143
-
144
- /// The pill moved: the open card moves with it, without animation.
145
- @MainActor
146
- func follow() {
147
- guard isVisible, let spot = placement() else { return }
148
- setFrameOrigin(spot.origin)
149
- }
150
-
151
- /// Slides out of the pill into place: up when it opens above, down
152
- /// when below. With Reduce Motion it simply appears there.
153
- @MainActor
154
- private func slideIn() {
155
- guard let spot = placement() else { alphaValue = 1; orderFrontRegardless(); return }
156
- let target = spot.origin
157
- let wasVisible = isVisible
158
- guard !wasVisible, !NSWorkspace.shared.accessibilityDisplayShouldReduceMotion else {
159
- setFrameOrigin(target)
160
- alphaValue = 1
161
- orderFrontRegardless()
162
- return
163
- }
164
- setFrameOrigin(NSPoint(x: target.x, y: target.y + (spot.above ? -18 : 18)))
165
- alphaValue = 0
166
- orderFrontRegardless()
167
- NSAnimationContext.runAnimationGroup { ctx in
168
- ctx.duration = 0.28
169
- ctx.timingFunction = Brand.ease
170
- animator().setFrameOrigin(target)
171
- animator().alphaValue = 1
172
- }
173
- }
174
-
175
- @objc private func openLink(_ sender: NSButton) {
176
- guard let s = sender.identifier?.rawValue, let u = URL(string: s) else { return }
177
- NSWorkspace.shared.open(u)
178
- }
179
-
180
- override var canBecomeKey: Bool { true }
181
- }
182
-
183
- extension ResultCard: WKNavigationDelegate {
184
- /// Links open in the real browser. A 380-point utility panel is not a
185
- /// place to read a web page, and navigating away would replace the
186
- /// answer the card exists to hold.
187
- func webView(_ webView: WKWebView,
188
- decidePolicyFor navigationAction: WKNavigationAction,
189
- decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
190
- if navigationAction.navigationType == .linkActivated,
191
- let url = navigationAction.request.url {
192
- NSWorkspace.shared.open(url)
193
- decisionHandler(.cancel)
194
- return
195
- }
196
- decisionHandler(.allow)
197
- }
198
- }