@join-pantheon/cli 0.27.0 → 0.29.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.
@@ -854,6 +854,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
854
854
  private var panelSendButton: NSButton?
855
855
  private var panelRetract: NSButton? // the undo, for a minute after a send
856
856
  private var panelLastSent: String = "" // act id of what was just sent
857
+ private var panelLastSpace: String = "" // the team it was sent in, for the undo
857
858
 
858
859
  private func label(_ text: String, size: CGFloat, weight: NSFont.Weight, color: NSColor, width: CGFloat) -> NSTextField {
859
860
  let l = NSTextField(labelWithString: text)
@@ -1308,6 +1309,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1308
1309
  /// prints "sent KIND id=… seq=…" or "not sent: why" on stdout; both are shown.
1309
1310
  @objc private func panelSend(_ sender: Any?) {
1310
1311
  guard let item = panelItem, let tv = panelReply else { return }
1312
+ // Return is the send key: a second press while the first send is still in
1313
+ // flight must not send the same words twice.
1314
+ if panelSendButton?.isEnabled == false { return }
1311
1315
  let text = tv.string.trimmingCharacters(in: .whitespacesAndNewlines)
1312
1316
  if text.isEmpty { setStatus("Type your reply first."); return }
1313
1317
  let kind = kindCode(panelReplyKind?.titleOfSelectedItem)
@@ -1324,6 +1328,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1324
1328
  let out = (r?.out ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
1325
1329
  if r?.code == 0, let idTok = out.split(separator: " ").first(where: { $0.hasPrefix("id=") }) {
1326
1330
  self.panelLastSent = String(idTok.dropFirst(3))
1331
+ self.panelLastSpace = item.space
1327
1332
  tv.string = ""
1328
1333
  let what = kind == "ANSWER" ? "Answered — it is no longer waiting on you." : kind == "ASK" ? "Asked — the agent that raised this owes you a reply." : "Noted — it stays waiting."
1329
1334
  self.setStatus(what)
@@ -1343,7 +1348,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1343
1348
  @objc private func panelRetractAction() {
1344
1349
  guard !panelLastSent.isEmpty else { return }
1345
1350
  let id = panelLastSent
1346
- guard writeAction(["action": "retract", "act": id]) else { setStatus("Could not write the action."); return }
1351
+ var payload: [String: Any] = ["action": "retract", "act": id]
1352
+ if !panelLastSpace.isEmpty { payload["space"] = panelLastSpace }
1353
+ guard writeAction(payload) else { setStatus("Could not write the action."); return }
1347
1354
  setStatus("Retracting…")
1348
1355
  panelRetract?.isEnabled = false
1349
1356
  DispatchQueue.global().async {
@@ -1376,7 +1383,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1376
1383
  @objc private func panelDone() {
1377
1384
  guard let item = panelItem, item.isDecision else { return }
1378
1385
  setStatus("Marking it done…")
1379
- var payload: [String: Any] = ["action": "done", "decision": item.id]
1386
+ var payload: [String: Any] = ["action": "done", "decision": item.id, "space": item.space]
1380
1387
  if !item.ref.isEmpty { payload["act"] = item.ref }
1381
1388
  guard writeAction(payload) else {
1382
1389
  setStatus("Could not write the action. Use Show the thread instead.")
@@ -1420,8 +1427,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1420
1427
  }
1421
1428
  /// The act behind it, in Terminal, with the reply menu.
1422
1429
  func showThread(_ item: Item) {
1423
- var payload: [String: Any] = ["action": "details"]
1430
+ var payload: [String: Any] = ["action": "details", "space": item.space]
1424
1431
  if !item.ref.isEmpty { payload["act"] = item.ref }
1432
+ if !item.goal.isEmpty { payload["goal"] = item.goal }
1425
1433
  if item.isDecision { payload["decision"] = item.id }
1426
1434
  if writeAction(payload) { openCommand("pantheon-details.command") }
1427
1435
  else { reportFailure("Could not open Terminal. Run pantheon doctor to check your setup.") }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@join-pantheon/cli",
3
- "version": "0.27.0",
3
+ "version": "0.29.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": {
@@ -22,6 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@modelcontextprotocol/sdk": "^1.0.0",
25
+ "undici": "^7.29.1",
25
26
  "ws": "^8.18.0",
26
27
  "zod": "^3.23.8"
27
28
  },