@join-pantheon/cli 0.30.0 → 0.31.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.
@@ -70,6 +70,8 @@ struct Item {
70
70
  let space: String
71
71
  /// whose human must decide this: this member for their own decision, the teammate for theirs, "" when it is not a decision
72
72
  let decider: String
73
+ /// one-click answers for a question this machine asked its own person (may a teammate wake it, may runs use commands)
74
+ var choices: [(label: String, answer: String)] = []
73
75
 
74
76
  var isDecision: Bool { kind == "decision" }
75
77
  var heading: String {
@@ -155,7 +157,11 @@ func fetchState() -> TrayState {
155
157
  goal: i["goal"] as? String ?? "",
156
158
  ref: i["ref"] as? String ?? "",
157
159
  space: i["space"] as? String ?? "",
158
- decider: i["decider"] as? String ?? ""
160
+ decider: i["decider"] as? String ?? "",
161
+ choices: (i["choices"] as? [[String: Any]] ?? []).compactMap { c in
162
+ guard let l = c["label"] as? String, let a = c["answer"] as? String else { return nil }
163
+ return (label: l, answer: a)
164
+ }
159
165
  ))
160
166
  }
161
167
  for d in (j["decisions"] as? [[String: Any]] ?? []) {
@@ -1189,6 +1195,22 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1189
1195
  rows.spacing = 8
1190
1196
  rows.translatesAutoresizingMaskIntoConstraints = false
1191
1197
 
1198
+ // A question this machine asked its own person: answered in one click, here.
1199
+ if item.isDecision && !item.choices.isEmpty {
1200
+ let row0 = NSStackView()
1201
+ row0.orientation = .horizontal
1202
+ row0.spacing = 10
1203
+ for (n, c) in item.choices.enumerated() {
1204
+ let b = button(c.label, #selector(panelChoose(_:)), "Answers it on this machine: \(c.answer)")
1205
+ b.tag = n
1206
+ // No Return key here: a habitual Enter must never grant "Always". A
1207
+ // permission is a click on the words that give it.
1208
+ b.keyEquivalent = ""
1209
+ row0.addArrangedSubview(b)
1210
+ }
1211
+ rows.addArrangedSubview(row0)
1212
+ }
1213
+
1192
1214
  let row1 = NSStackView()
1193
1215
  row1.orientation = .horizontal
1194
1216
  row1.spacing = 10
@@ -1319,6 +1341,31 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1319
1341
  switch title { case "Answer": return "ANSWER"; case "Ask back": return "ASK"; default: return "NOTE" }
1320
1342
  }
1321
1343
 
1344
+ /// One of the question's own answers, sent as its ANSWER — the same local path
1345
+ /// a typed reply takes, so a grant it carries takes effect on this machine.
1346
+ @objc private func panelChoose(_ sender: NSButton) {
1347
+ guard let item = panelItem, sender.tag >= 0, sender.tag < item.choices.count else { return }
1348
+ let c = item.choices[sender.tag]
1349
+ var payload: [String: Any] = ["action": "reply", "kind": "ANSWER", "body": c.answer, "goal": item.goal, "space": item.space, "decision": item.id]
1350
+ if !item.ref.isEmpty { payload["act"] = item.ref }
1351
+ guard writeAction(payload) else { setStatus("Could not write the action. Use Show the thread instead."); return }
1352
+ setStatus("Answering…")
1353
+ sender.isEnabled = false
1354
+ DispatchQueue.global().async {
1355
+ let r = run(pantheonBin, ["explain", "--queued"], timeout: 25)
1356
+ DispatchQueue.main.async {
1357
+ sender.isEnabled = true
1358
+ let out = (r?.out ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
1359
+ if r?.code == 0 {
1360
+ self.setStatus("\(c.label) — done.")
1361
+ self.refresh()
1362
+ } else {
1363
+ self.setStatus(out.hasPrefix("not sent: ") ? String(out.dropFirst("not sent: ".count)) : "the relay could not be reached")
1364
+ }
1365
+ }
1366
+ }
1367
+ }
1368
+
1322
1369
  /// Send the words in the box as the chosen act. The CLI does the sending and
1323
1370
  /// prints "sent KIND id=… seq=…" or "not sent: why" on stdout; both are shown.
1324
1371
  @objc private func panelSend(_ sender: Any?) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@join-pantheon/cli",
3
- "version": "0.30.0",
3
+ "version": "0.31.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": {