@join-pantheon/cli 0.24.4 → 0.25.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.
@@ -78,7 +78,9 @@ struct Item {
78
78
  /// "praneet · 2d ago · pantheon"
79
79
  var subtitle: String {
80
80
  var parts: [String] = []
81
- if kind == "owed" { parts.append("you owe") } else if kind == "waiting" { parts.append(who) }
81
+ // Who is asking, on every kind. A decision row used to say only "11h ago",
82
+ // which is the one fact a reader could already guess.
83
+ if kind == "owed" { parts.append("you owe") } else if !who.isEmpty { parts.append(who) }
82
84
  if when > 0 { parts.append(Item.age(when)) }
83
85
  if !space.isEmpty { parts.append(space) }
84
86
  return parts.joined(separator: " · ")
@@ -179,11 +181,30 @@ final class RowView: NSView {
179
181
  private var overCopy = false
180
182
  private var copied = false
181
183
 
184
+ private let titleLines: Int
185
+ private static let titleFont = NSFont.systemFont(ofSize: 13, weight: .medium)
186
+ private static let lineHeight: CGFloat = 17
187
+
188
+ /// How many lines this title needs, at most two. A one-line row truncated
189
+ /// mid-word ("Sid asked: Sid is asking: is this work in producti…") hid the
190
+ /// only part worth reading; two lines carry almost every real title whole.
191
+ static func lines(for text: String, width: CGFloat) -> Int {
192
+ let para = NSMutableParagraphStyle()
193
+ para.lineBreakMode = .byWordWrapping
194
+ let h = (text as NSString).boundingRect(
195
+ with: NSSize(width: width, height: .greatestFiniteMagnitude),
196
+ options: [.usesLineFragmentOrigin, .usesFontLeading],
197
+ attributes: [.font: titleFont, .paragraphStyle: para]).height
198
+ return max(1, min(2, Int(ceil(h / lineHeight))))
199
+ }
200
+
182
201
  init(item: Item, width: CGFloat, onOpen: @escaping (Item) -> Void, onCopy: @escaping (Item) -> Void) {
183
202
  self.item = item
184
203
  self.onOpen = onOpen
185
204
  self.onCopy = onCopy
186
- super.init(frame: NSRect(x: 0, y: 0, width: width, height: item.subtitle.isEmpty ? 30 : 42))
205
+ self.titleLines = RowView.lines(for: item.title, width: width - 14 - 48)
206
+ let textHeight = CGFloat(titleLines) * RowView.lineHeight
207
+ super.init(frame: NSRect(x: 0, y: 0, width: width, height: textHeight + (item.subtitle.isEmpty ? 13 : 29)))
187
208
  setAccessibilityRole(.button)
188
209
  setAccessibilityLabel("\(item.title). \(item.subtitle). Return opens it; the button on the right copies the question.")
189
210
  }
@@ -191,6 +212,7 @@ final class RowView: NSView {
191
212
 
192
213
  private var copyRect: NSRect { NSRect(x: bounds.maxX - 42, y: bounds.midY - 12, width: 28, height: 24) }
193
214
 
215
+
194
216
  override func updateTrackingAreas() {
195
217
  super.updateTrackingAreas()
196
218
  for a in trackingAreas { removeTrackingArea(a) }
@@ -227,17 +249,25 @@ final class RowView: NSView {
227
249
  let fg: NSColor = selected ? .selectedMenuItemTextColor : .labelColor
228
250
  let dim: NSColor = selected ? NSColor.selectedMenuItemTextColor.withAlphaComponent(0.7) : .secondaryLabelColor
229
251
  let para = NSMutableParagraphStyle()
230
- para.lineBreakMode = .byTruncatingTail
252
+ para.lineBreakMode = .byWordWrapping // break between words, not inside one
253
+ para.lineSpacing = 0
254
+ let flat = NSMutableParagraphStyle()
255
+ flat.lineBreakMode = .byTruncatingTail
231
256
  let textWidth = bounds.width - 14 - 48
232
257
  let hasSub = !item.subtitle.isEmpty
233
- let titleY = hasSub ? bounds.midY - 1 : bounds.midY - 8
234
- NSAttributedString(string: item.title, attributes: [
235
- .font: NSFont.systemFont(ofSize: 13, weight: .medium), .foregroundColor: fg, .paragraphStyle: para,
236
- ]).draw(in: NSRect(x: 14, y: titleY, width: textWidth, height: 18))
258
+ let titleHeight = CGFloat(titleLines) * RowView.lineHeight
259
+ let titleY = bounds.maxY - 7 - titleHeight
260
+ let cell = NSTextFieldCell() // gives the last visible line its ellipsis
261
+ cell.attributedStringValue = NSAttributedString(string: item.title, attributes: [
262
+ .font: RowView.titleFont, .foregroundColor: fg, .paragraphStyle: para,
263
+ ])
264
+ cell.truncatesLastVisibleLine = true
265
+ cell.wraps = true
266
+ cell.drawInterior(withFrame: NSRect(x: 12, y: titleY, width: textWidth, height: titleHeight), in: self)
237
267
  if hasSub {
238
268
  NSAttributedString(string: item.subtitle, attributes: [
239
- .font: NSFont.systemFont(ofSize: 11), .foregroundColor: dim, .paragraphStyle: para,
240
- ]).draw(in: NSRect(x: 14, y: bounds.midY - 17, width: textWidth, height: 15))
269
+ .font: NSFont.systemFont(ofSize: 11), .foregroundColor: dim, .paragraphStyle: flat,
270
+ ]).draw(in: NSRect(x: 14, y: bounds.minY + 6, width: textWidth, height: 14))
241
271
  }
242
272
 
243
273
  // the copy control
@@ -406,7 +436,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
406
436
  addRows(menu, theirs.count == 1 ? "Waiting on \(who)" : "Waiting on \(who) · \(theirs.count)", theirs)
407
437
  }
408
438
  if !decisions.isEmpty {
409
- menu.addItem(makeItem("\(decisions.count > 1 ? "Review all \(decisions.count) decisions" : "Review the decision") in \(state.surfaceName)", #selector(openAllDecisions)))
439
+ menu.addItem(makeItem(decisions.count > 1 ? "Review all \(decisions.count) in \(state.surfaceName)" : "Review it in \(state.surfaceName)", #selector(openAllDecisions)))
410
440
  }
411
441
  }
412
442
  menu.addItem(.separator())
@@ -826,7 +856,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
826
856
  for item in items.prefix(6) {
827
857
  let mi = NSMenuItem(title: item.title, action: nil, keyEquivalent: "")
828
858
  mi.toolTip = item.detail
829
- mi.view = RowView(item: item, width: 360,
859
+ mi.view = RowView(item: item, width: 430,
830
860
  onOpen: { [weak self] it in self?.showDetail(it) },
831
861
  onCopy: { [weak self] it in self?.copyPrompt(it) })
832
862
  menu.addItem(mi)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@join-pantheon/cli",
3
- "version": "0.24.4",
3
+ "version": "0.25.0",
4
4
  "description": "Let your coding agent collaborate directly with your teammates' agents — ask, agree an interface, and deliver, without a human relaying messages.",
5
5
  "type": "module",
6
6
  "bin": {