@join-pantheon/cli 0.29.1 → 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.
- package/README.md +142 -40
- package/bin/pantheon.js +12 -0
- package/dist/accounts.js +151 -26
- package/dist/agents.js +224 -17
- package/dist/claude-confine.js +299 -0
- package/dist/cli.js +1116 -137
- package/dist/client.js +294 -10
- package/dist/command-state.js +102 -0
- package/dist/config.js +287 -14
- package/dist/continued.js +42 -10
- package/dist/doctor.js +191 -23
- package/dist/file-lock.js +197 -0
- package/dist/grants.js +1 -1
- package/dist/history-view.js +2 -1
- package/dist/home-guard.js +565 -0
- package/dist/hooks-install.js +2 -1
- package/dist/identity.js +101 -1
- package/dist/install.js +76 -26
- package/dist/kiro-files.js +2 -2
- package/dist/ledger.js +111 -28
- package/dist/machine.js +494 -32
- package/dist/mcp-supervisor.js +29 -7
- package/dist/mcp-windows.js +47 -25
- package/dist/mcp.js +99 -36
- package/dist/network.js +39 -8
- package/dist/nonces.js +130 -0
- package/dist/notify.js +26 -9
- package/dist/pending.js +121 -22
- package/dist/persona.js +21 -0
- package/dist/pins.js +161 -0
- package/dist/profile.js +22 -1
- package/dist/protocol.js +40 -1
- package/dist/quickstart.js +173 -24
- package/dist/reads.js +37 -0
- package/dist/refusal.js +14 -1
- package/dist/relay.js +1341 -207
- package/dist/repo-find.js +127 -0
- package/dist/repo-route.js +70 -0
- package/dist/roster-file.js +190 -25
- package/dist/run-failure.js +99 -3
- package/dist/secret-guard.js +141 -0
- package/dist/service.js +91 -35
- package/dist/setup-guide.js +91 -31
- package/dist/spend.js +6 -2
- package/dist/store.js +94 -10
- package/dist/text-file.js +74 -0
- package/dist/tray.js +24 -3
- package/dist/untrusted.js +24 -5
- package/dist/update-check.js +2 -0
- package/dist/upgrade.js +9 -5
- package/dist/verify-act.js +102 -0
- package/dist/which.js +69 -12
- package/dist/worker-fleet.js +30 -9
- package/dist/worker-policy.js +231 -7
- package/dist/worker.js +1717 -130
- package/helper/macos/menubar.swift +63 -2
- package/package.json +2 -2
|
@@ -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 {
|
|
@@ -119,7 +121,7 @@ func run(_ launchPath: String, _ args: [String], timeout: Double = 10) -> (out:
|
|
|
119
121
|
|
|
120
122
|
func fetchState() -> TrayState {
|
|
121
123
|
var s = TrayState()
|
|
122
|
-
guard let r = run(pantheonBin, ["tray-status"]), r.code == 0,
|
|
124
|
+
guard let r = run(pantheonBin, ["tray-status"], timeout: 20), r.code == 0,
|
|
123
125
|
let data = r.out.data(using: .utf8),
|
|
124
126
|
let j = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return s }
|
|
125
127
|
s.reachable = true
|
|
@@ -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]] ?? []) {
|
|
@@ -477,12 +483,26 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
477
483
|
}
|
|
478
484
|
}
|
|
479
485
|
|
|
486
|
+
/// Consecutive checks that did not come back (timed out, or did not parse).
|
|
487
|
+
private var missedChecks = 0
|
|
480
488
|
@objc func refresh() {
|
|
481
489
|
guard !refreshing else { return }
|
|
482
490
|
refreshing = true
|
|
483
491
|
DispatchQueue.global().async {
|
|
484
492
|
let next = fetchState()
|
|
485
493
|
DispatchQueue.main.async {
|
|
494
|
+
// A check that did not come back is not news that the relay is down: on a
|
|
495
|
+
// busy machine `pantheon tray-status` can take longer than its limit, and
|
|
496
|
+
// the mark flipped to the slashed "unreachable" state with a "!" — while
|
|
497
|
+
// the relay, the team and every decision were fine. What was last known is
|
|
498
|
+
// kept through two misses; only a third in a row is shown as "unable to
|
|
499
|
+
// check". A check that did come back always wins.
|
|
500
|
+
if !next.reachable && self.hasLoaded && self.state.reachable && self.missedChecks < 2 {
|
|
501
|
+
self.missedChecks += 1
|
|
502
|
+
self.refreshing = false
|
|
503
|
+
return
|
|
504
|
+
}
|
|
505
|
+
self.missedChecks = next.reachable ? 0 : self.missedChecks + 1
|
|
486
506
|
self.state = next
|
|
487
507
|
self.hasLoaded = true
|
|
488
508
|
self.refreshing = false
|
|
@@ -1175,6 +1195,22 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
1175
1195
|
rows.spacing = 8
|
|
1176
1196
|
rows.translatesAutoresizingMaskIntoConstraints = false
|
|
1177
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
|
+
|
|
1178
1214
|
let row1 = NSStackView()
|
|
1179
1215
|
row1.orientation = .horizontal
|
|
1180
1216
|
row1.spacing = 10
|
|
@@ -1305,6 +1341,31 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
|
|
|
1305
1341
|
switch title { case "Answer": return "ANSWER"; case "Ask back": return "ASK"; default: return "NOTE" }
|
|
1306
1342
|
}
|
|
1307
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
|
+
|
|
1308
1369
|
/// Send the words in the box as the chosen act. The CLI does the sending and
|
|
1309
1370
|
/// prints "sent KIND id=… seq=…" or "not sent: why" on stdout; both are shown.
|
|
1310
1371
|
@objc private func panelSend(_ sender: Any?) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@join-pantheon/cli",
|
|
3
|
-
"version": "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": {
|
|
7
7
|
"pantheon": "bin/pantheon.js"
|
|
8
8
|
},
|
|
9
9
|
"engines": {
|
|
10
|
-
"node": ">=22"
|
|
10
|
+
"node": ">=22.13"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p .",
|