@join-pantheon/cli 0.23.1 → 0.24.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 +5 -3
- package/dist/agents.js +14 -2
- package/dist/cli.js +142 -13
- package/dist/doctor.js +8 -0
- package/dist/mcp-supervisor.js +403 -0
- package/dist/mcp-windows.js +135 -0
- package/dist/mcp.js +12 -2
- package/dist/notice.js +12 -3
- package/dist/notifier.js +28 -6
- package/dist/relay.js +281 -186
- package/dist/worker.js +5 -3
- package/helper/macos/main.swift +25 -7
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -13,7 +13,7 @@ import { allowed, recordRun } from "./spend.js";
|
|
|
13
13
|
import { loadProfile, reservedDecisionsNote } from "./profile.js";
|
|
14
14
|
import { clip } from "./brief.js";
|
|
15
15
|
import { composeWorker } from "./notice.js";
|
|
16
|
-
import { installedTools } from "./notifier.js";
|
|
16
|
+
import { installedTools, preferredTool } from "./notifier.js";
|
|
17
17
|
import { loadPersonas, matchPersona, personaByName, personaMatches, effectivePolicy, personaBrief, describePersona, } from "./persona.js";
|
|
18
18
|
import { isContinuationFor, LIMITS, shouldDeferToHuman } from "./protocol.js";
|
|
19
19
|
const git = (cwd, ...args) => execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
@@ -593,7 +593,7 @@ export class Worker {
|
|
|
593
593
|
if (this.opts.notify && (!ok || loadProfile(this.cfg).notifications?.worker_done)) {
|
|
594
594
|
try {
|
|
595
595
|
const reply = client.mineSince(startedAt, o.goal).pop() ?? null;
|
|
596
|
-
this.opts.notify(composeWorker({ ok, triggeredBy, obligationBody: o.body, goal: o.goal ? client.goals.get(o.goal) : undefined, reply, obligationRef: o.ref }, { tools
|
|
596
|
+
this.opts.notify(composeWorker({ ok, triggeredBy, obligationBody: o.body, goal: o.goal ? client.goals.get(o.goal) : undefined, reply, obligationRef: o.ref }, (() => { const tools = installedTools(); return { tools, preferred: preferredTool(loadProfile(this.cfg), tools, this.opts.home) }; })()));
|
|
597
597
|
}
|
|
598
598
|
catch { }
|
|
599
599
|
}
|
|
@@ -690,6 +690,8 @@ export class Worker {
|
|
|
690
690
|
this.opts.log(`! self-upgrade failed: ${e.message}`);
|
|
691
691
|
}
|
|
692
692
|
if (result.ok && !result.alreadyCurrent && result.to === result.from) {
|
|
693
|
+
delete policy.attempts.self_upgrade;
|
|
694
|
+
savePolicy(policy, home);
|
|
693
695
|
this.opts.log(`* self-upgrade: the registry does not serve ${relayPkg} yet (installed ${result.to}); will check again`);
|
|
694
696
|
return;
|
|
695
697
|
}
|
|
@@ -697,7 +699,7 @@ export class Worker {
|
|
|
697
699
|
await client.send({
|
|
698
700
|
act: "NOTE", goal: null, after_seq: client.readSeq,
|
|
699
701
|
summary: `self-upgraded pantheon ${result.from} -> ${result.to}; worker restarting on the new build`,
|
|
700
|
-
body: `This machine's worker upgraded pantheon ${result.from} -> ${result.to} (fast-forward pull + rebuild, granted by its human) and is restarting on the new build.`,
|
|
702
|
+
body: `This machine's worker upgraded pantheon ${result.from} -> ${result.to} (fast-forward pull + rebuild, granted by its human) and is restarting on the new build. Agent windows on this machine opened on 0.24 or later switch to the new version by themselves; a window opened on an older pantheon needs one reconnect (/mcp → pantheon → Reconnect, or reopen it).`,
|
|
701
703
|
}).catch((e) => this.opts.log(`! could not report the upgrade on the ledger: ${e.message}`));
|
|
702
704
|
await this.bringMachineAlong();
|
|
703
705
|
this.opts.log(`* self-upgrade done: ${result.from} -> ${result.to}; restarting worker to load it`);
|
package/helper/macos/main.swift
CHANGED
|
@@ -29,7 +29,7 @@ if args.count == 2, args[1] == "version" {
|
|
|
29
29
|
exit(0)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
struct Tool: Decodable { let id: String; let label: String }
|
|
32
|
+
struct Tool: Decodable { let id: String; let label: String; let kind: String?; let bundle: String?; let deeplink: String? }
|
|
33
33
|
struct Primary: Decodable { let label: String; let `default`: String; let tools: [Tool]; let prompt: String }
|
|
34
34
|
struct Details: Decodable { let act: String?; let decision: String? }
|
|
35
35
|
struct Notice: Decodable {
|
|
@@ -105,17 +105,35 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
105
105
|
NSApp.terminate(nil)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
let
|
|
111
|
-
|
|
108
|
+
/// Remember the pick: the next notice opens here by default.
|
|
109
|
+
private func remember(_ tool: String) {
|
|
110
|
+
guard !notice.bin_dir.isEmpty, let data = try? JSONSerialization.data(withJSONObject: ["tool": tool]) else { return }
|
|
111
|
+
try? data.write(to: URL(fileURLWithPath: notice.bin_dir).appendingPathComponent(".hud-pref.json"), options: .atomic)
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
private func open(_ toolId: String) {
|
|
115
115
|
guard let p = notice.primary else { return }
|
|
116
|
-
|
|
116
|
+
remember(toolId)
|
|
117
|
+
let tool = p.tools.first { $0.id == toolId }
|
|
118
|
+
if let t = tool, t.kind == "app" {
|
|
119
|
+
// A deep link carries the question itself; an app without one gets it on the clipboard and comes to the front.
|
|
120
|
+
if let template = t.deeplink, let encoded = p.prompt.addingPercentEncoding(withAllowedCharacters: .alphanumerics), let url = URL(string: template.replacingOccurrences(of: "{prompt}", with: encoded)) {
|
|
121
|
+
NSWorkspace.shared.open(url)
|
|
122
|
+
NSApp.terminate(nil); return
|
|
123
|
+
}
|
|
124
|
+
NSPasteboard.general.clearContents(); NSPasteboard.general.setString(p.prompt, forType: .string)
|
|
125
|
+
if let b = t.bundle, let appURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: b) {
|
|
126
|
+
let config = NSWorkspace.OpenConfiguration(); config.activates = true
|
|
127
|
+
NSWorkspace.shared.openApplication(at: appURL, configuration: config) { _, _ in NSApp.terminate(nil) }
|
|
128
|
+
} else { NSApp.terminate(nil) }
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
act(["action": "open", "tool": toolId, "prompt": p.prompt, "decision": notice.details?.decision as Any, "act": notice.details?.act as Any].compactMapValues { $0 is NSNull ? nil : $0 }, command: "pantheon-explain.command")
|
|
117
132
|
}
|
|
118
133
|
|
|
134
|
+
@objc func openTool(_ sender: NSMenuItem) { open((sender.representedObject as? String) ?? notice.primary?.default ?? "") }
|
|
135
|
+
@objc func openDefault(_ sender: Any?) { open(notice.primary?.default ?? "") }
|
|
136
|
+
|
|
119
137
|
@objc func showDetails(_ sender: Any?) {
|
|
120
138
|
act(["action": "details", "act": notice.details?.act as Any, "decision": notice.details?.decision as Any].compactMapValues { $0 is NSNull ? nil : $0 }, command: "pantheon-details.command")
|
|
121
139
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@join-pantheon/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.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": {
|