Add ez-assistant and kerberos service folders
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
enum CLIInstaller {
|
||||
static func installedLocation() -> String? {
|
||||
self.installedLocation(
|
||||
searchPaths: CommandResolver.preferredPaths(),
|
||||
fileManager: .default)
|
||||
}
|
||||
|
||||
static func installedLocation(
|
||||
searchPaths: [String],
|
||||
fileManager: FileManager) -> String?
|
||||
{
|
||||
for basePath in searchPaths {
|
||||
let candidate = URL(fileURLWithPath: basePath).appendingPathComponent("moltbot").path
|
||||
var isDirectory: ObjCBool = false
|
||||
|
||||
guard fileManager.fileExists(atPath: candidate, isDirectory: &isDirectory),
|
||||
!isDirectory.boolValue
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
guard fileManager.isExecutableFile(atPath: candidate) else { continue }
|
||||
|
||||
return candidate
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
static func isInstalled() -> Bool {
|
||||
self.installedLocation() != nil
|
||||
}
|
||||
|
||||
static func install(statusHandler: @escaping @MainActor @Sendable (String) async -> Void) async {
|
||||
let expected = GatewayEnvironment.expectedGatewayVersionString() ?? "latest"
|
||||
let prefix = Self.installPrefix()
|
||||
await statusHandler("Installing moltbot CLI…")
|
||||
let cmd = self.installScriptCommand(version: expected, prefix: prefix)
|
||||
let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: nil, timeout: 900)
|
||||
|
||||
if response.success {
|
||||
let parsed = self.parseInstallEvents(response.stdout)
|
||||
let installedVersion = parsed.last { $0.event == "done" }?.version
|
||||
let summary = installedVersion.map { "Installed moltbot \($0)." } ?? "Installed moltbot."
|
||||
await statusHandler(summary)
|
||||
return
|
||||
}
|
||||
|
||||
let parsed = self.parseInstallEvents(response.stdout)
|
||||
if let error = parsed.last(where: { $0.event == "error" })?.message {
|
||||
await statusHandler("Install failed: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
let detail = response.stderr.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let fallback = response.errorMessage ?? "install failed"
|
||||
await statusHandler("Install failed: \(detail.isEmpty ? fallback : detail)")
|
||||
}
|
||||
|
||||
private static func installPrefix() -> String {
|
||||
FileManager().homeDirectoryForCurrentUser
|
||||
.appendingPathComponent(".clawdbot")
|
||||
.path
|
||||
}
|
||||
|
||||
private static func installScriptCommand(version: String, prefix: String) -> [String] {
|
||||
let escapedVersion = self.shellEscape(version)
|
||||
let escapedPrefix = self.shellEscape(prefix)
|
||||
let script = """
|
||||
curl -fsSL https://molt.bot/install-cli.sh | \
|
||||
bash -s -- --json --no-onboard --prefix \(escapedPrefix) --version \(escapedVersion)
|
||||
"""
|
||||
return ["/bin/bash", "-lc", script]
|
||||
}
|
||||
|
||||
private static func parseInstallEvents(_ output: String) -> [InstallEvent] {
|
||||
let decoder = JSONDecoder()
|
||||
let lines = output
|
||||
.split(whereSeparator: \.isNewline)
|
||||
.map { String($0) }
|
||||
var events: [InstallEvent] = []
|
||||
for line in lines {
|
||||
guard let data = line.data(using: .utf8) else { continue }
|
||||
if let event = try? decoder.decode(InstallEvent.self, from: data) {
|
||||
events.append(event)
|
||||
}
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
private static func shellEscape(_ raw: String) -> String {
|
||||
"'" + raw.replacingOccurrences(of: "'", with: "'\"'\"'") + "'"
|
||||
}
|
||||
}
|
||||
|
||||
private struct InstallEvent: Decodable {
|
||||
let event: String
|
||||
let version: String?
|
||||
let message: String?
|
||||
}
|
||||
Reference in New Issue
Block a user