From 47a1774dc0825b684c277877a6bebbca0b05dbed Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 19 Dec 2025 17:46:49 +0100 Subject: [PATCH] Mac: add summarize tool --- .../macos/Sources/Clawdis/ToolsSettings.swift | 281 +++++++++--------- .../SettingsViewSmokeTests.swift | 6 +- 2 files changed, 153 insertions(+), 134 deletions(-) diff --git a/apps/macos/Sources/Clawdis/ToolsSettings.swift b/apps/macos/Sources/Clawdis/ToolsSettings.swift index 389b8853e..eb04fb5ea 100644 --- a/apps/macos/Sources/Clawdis/ToolsSettings.swift +++ b/apps/macos/Sources/Clawdis/ToolsSettings.swift @@ -75,139 +75,154 @@ private enum InstallState: Equatable { // MARK: - View struct ToolsSettings: View { - private let tools: [ToolEntry] = [ - ToolEntry( - id: "mcporter", - name: "๐Ÿงณ mcporter", - url: URL(string: "https://github.com/steipete/mcporter")!, - description: "MCP runtime/CLI to discover servers, run tools, and sync configs across AI clients.", - method: .node(package: "mcporter", binary: "mcporter"), - kind: .tool), - ToolEntry( - id: "peekaboo", - name: "๐Ÿซฃ Peekaboo", - url: URL(string: "https://github.com/steipete/Peekaboo")!, - description: "Lightning-fast macOS screenshots with AI vision helpers for step-by-step automation.", - method: .brew(formula: "steipete/tap/peekaboo", binary: "peekaboo"), - kind: .tool), - ToolEntry( - id: "camsnap", - name: "๐Ÿ“ธ camsnap", - url: URL(string: "https://github.com/steipete/camsnap")!, - description: "One command to grab frames, clips, or motion alerts from RTSP/ONVIF cameras.", - method: .brew(formula: "steipete/tap/camsnap", binary: "camsnap"), - kind: .tool), - ToolEntry( - id: "oracle", - name: "๐Ÿงฟ oracle", - url: URL(string: "https://github.com/steipete/oracle")!, - description: "Runs OpenAI-ready agent workflows from the CLI with session replay and browser control.", - method: .node(package: "@steipete/oracle", binary: "oracle"), - kind: .tool), - ToolEntry( - id: "qmd", - name: "๐Ÿ”Ž qmd", - url: URL(string: "https://github.com/tobi/qmd")!, - description: "Hybrid markdown search (BM25 + vectors + rerank) with an MCP server for agents.", - method: .node(package: "https://github.com/tobi/qmd", binary: "qmd"), - kind: .tool), - ToolEntry( - id: "eightctl", - name: "๐Ÿ›๏ธ eightctl", - url: URL(string: "https://github.com/steipete/eightctl")!, - description: "Control your sleep, from the terminal.", - method: .go(module: "github.com/steipete/eightctl/cmd/eightctl@latest", binary: "eightctl"), - kind: .tool), - ToolEntry( - id: "imsg", - name: "๐Ÿ’ฌ imsg", - url: URL(string: "https://github.com/steipete/imsg")!, - description: "Send, read, stream iMessage & SMS.", - method: .go(module: "github.com/steipete/imsg/cmd/imsg@latest", binary: "imsg"), - kind: .tool), - ToolEntry( - id: "wacli", - name: "๐Ÿ—ƒ๏ธ wacli", - url: URL(string: "https://github.com/steipete/wacli")!, - description: "WhatsApp CLI: sync, search, send.", - method: .go(module: "github.com/steipete/wacli/cmd/wacli@latest", binary: "wacli"), - kind: .tool), - ToolEntry( - id: "spotify-player", - name: "๐ŸŽต spotify-player", - url: URL(string: "https://github.com/aome510/spotify-player")!, - description: "Terminal Spotify client to queue, search, and control playback without leaving chat.", - method: .brew(formula: "spotify_player", binary: "spotify_player"), - kind: .tool), - ToolEntry( - id: "sonoscli", - name: "๐Ÿ”Š sonoscli", - url: URL(string: "https://github.com/steipete/sonoscli")!, - description: "Control Sonos speakers (discover, status, play/pause, volume, grouping) from scripts.", - method: .go(module: "github.com/steipete/sonoscli/cmd/sonos@latest", binary: "sonos"), - kind: .tool), - ToolEntry( - id: "blucli", - name: "๐Ÿซ blucli", - url: URL(string: "https://github.com/steipete/blucli")!, - description: "Play, group, and automate BluOS players from scripts.", - method: .go(module: "github.com/steipete/blucli/cmd/blu@latest", binary: "blu"), - kind: .tool), - ToolEntry( - id: "sag", - name: "๐Ÿ—ฃ๏ธ sag", - url: URL(string: "https://github.com/steipete/sag")!, - description: "ElevenLabs speech with mac-style say UX; streams to speakers by default.", - method: .brew(formula: "steipete/tap/sag", binary: "sag"), - kind: .tool), - ToolEntry( - id: "openhue-cli", - name: "๐Ÿ’ก OpenHue CLI", - url: URL(string: "https://github.com/openhue/openhue-cli")!, - description: "Control Philips Hue lights from scriptsโ€”scenes, dimming, and automations.", - method: .brew(formula: "openhue/cli/openhue-cli", binary: "openhue"), - kind: .tool), - ToolEntry( - id: "openai-whisper", - name: "๐ŸŽ™๏ธ OpenAI Whisper", - url: URL(string: "https://github.com/openai/whisper")!, - description: "Local speech-to-text for quick dictation and voicemail transcripts.", - method: .brew(formula: "openai-whisper", binary: "whisper"), - kind: .tool), - ToolEntry( - id: "gog", - name: "๐Ÿ“ฎ gog", - url: URL(string: "https://github.com/steipete/gogcli")!, - description: "Google Suite CLI: Gmail, Calendar, Drive, Contacts.", - method: .brew(formula: "steipete/tap/gogcli", binary: "gog"), - kind: .tool), - ToolEntry( - id: "gemini-cli", - name: "โ™Š๏ธ Gemini CLI", - url: URL(string: "https://github.com/google-gemini/gemini-cli")!, - description: "Google Gemini models from the terminal for fast Q&A and web-grounded summaries.", - method: .brew(formula: "gemini-cli", binary: "gemini"), - kind: .tool), - ToolEntry( - id: "bird", - name: "๐Ÿฆ bird", - url: URL(string: "https://github.com/steipete/bird")!, - description: "Fast X/Twitter CLI to tweet, reply, read threads, and search without a browser.", - method: .pnpm( - repoPath: "\(NSHomeDirectory())/Projects/bird", - script: "binary", - binary: "bird"), - kind: .tool), - ToolEntry( - id: "agent-tools", - name: "๐Ÿงฐ agent-tools", - url: URL(string: "https://github.com/badlogic/agent-tools")!, - description: "Collection of utilities and scripts tuned for autonomous agents and MCP clients.", - method: .gitClone( - url: "https://github.com/badlogic/agent-tools.git", - destination: "\(NSHomeDirectory())/agent-tools"), - kind: .tool), - ] + private let tools: [ToolEntry] = Self.makeTools() + + static var toolIDsForTests: [String] { + makeTools().map(\.id) + } + + private static func makeTools() -> [ToolEntry] { + [ + ToolEntry( + id: "mcporter", + name: "๐Ÿงณ mcporter", + url: URL(string: "https://github.com/steipete/mcporter")!, + description: "MCP runtime/CLI to discover servers, run tools, and sync configs across AI clients.", + method: .node(package: "mcporter", binary: "mcporter"), + kind: .tool), + ToolEntry( + id: "peekaboo", + name: "๐Ÿซฃ Peekaboo", + url: URL(string: "https://github.com/steipete/Peekaboo")!, + description: "Lightning-fast macOS screenshots with AI vision helpers for step-by-step automation.", + method: .brew(formula: "steipete/tap/peekaboo", binary: "peekaboo"), + kind: .tool), + ToolEntry( + id: "camsnap", + name: "๐Ÿ“ธ camsnap", + url: URL(string: "https://github.com/steipete/camsnap")!, + description: "One command to grab frames, clips, or motion alerts from RTSP/ONVIF cameras.", + method: .brew(formula: "steipete/tap/camsnap", binary: "camsnap"), + kind: .tool), + ToolEntry( + id: "oracle", + name: "๐Ÿงฟ oracle", + url: URL(string: "https://github.com/steipete/oracle")!, + description: "Runs OpenAI-ready agent workflows from the CLI with session replay and browser control.", + method: .node(package: "@steipete/oracle", binary: "oracle"), + kind: .tool), + ToolEntry( + id: "summarize", + name: "๐Ÿงพ summarize", + url: URL(string: "https://github.com/steipete/summarize")!, + description: "Link โ†’ clean text โ†’ summary (web pages, YouTube, and local/remote files).", + method: .brew(formula: "steipete/tap/summarize", binary: "summarize"), + kind: .tool), + ToolEntry( + id: "qmd", + name: "๐Ÿ”Ž qmd", + url: URL(string: "https://github.com/tobi/qmd")!, + description: "Hybrid markdown search (BM25 + vectors + rerank) with an MCP server for agents.", + method: .node(package: "https://github.com/tobi/qmd", binary: "qmd"), + kind: .tool), + ToolEntry( + id: "eightctl", + name: "๐Ÿ›๏ธ eightctl", + url: URL(string: "https://github.com/steipete/eightctl")!, + description: "Control your sleep, from the terminal.", + method: .go(module: "github.com/steipete/eightctl/cmd/eightctl@latest", binary: "eightctl"), + kind: .tool), + ToolEntry( + id: "imsg", + name: "๐Ÿ’ฌ imsg", + url: URL(string: "https://github.com/steipete/imsg")!, + description: "Send, read, stream iMessage & SMS.", + method: .go(module: "github.com/steipete/imsg/cmd/imsg@latest", binary: "imsg"), + kind: .tool), + ToolEntry( + id: "wacli", + name: "๐Ÿ—ƒ๏ธ wacli", + url: URL(string: "https://github.com/steipete/wacli")!, + description: "WhatsApp CLI: sync, search, send.", + method: .go(module: "github.com/steipete/wacli/cmd/wacli@latest", binary: "wacli"), + kind: .tool), + ToolEntry( + id: "spotify-player", + name: "๐ŸŽต spotify-player", + url: URL(string: "https://github.com/aome510/spotify-player")!, + description: "Terminal Spotify client to queue, search, and control playback without leaving chat.", + method: .brew(formula: "spotify_player", binary: "spotify_player"), + kind: .tool), + ToolEntry( + id: "sonoscli", + name: "๐Ÿ”Š sonoscli", + url: URL(string: "https://github.com/steipete/sonoscli")!, + description: "Control Sonos speakers (discover, status, play/pause, volume, grouping) from scripts.", + method: .go(module: "github.com/steipete/sonoscli/cmd/sonos@latest", binary: "sonos"), + kind: .tool), + ToolEntry( + id: "blucli", + name: "๐Ÿซ blucli", + url: URL(string: "https://github.com/steipete/blucli")!, + description: "Play, group, and automate BluOS players from scripts.", + method: .go(module: "github.com/steipete/blucli/cmd/blu@latest", binary: "blu"), + kind: .tool), + ToolEntry( + id: "sag", + name: "๐Ÿ—ฃ๏ธ sag", + url: URL(string: "https://github.com/steipete/sag")!, + description: "ElevenLabs speech with mac-style say UX; streams to speakers by default.", + method: .brew(formula: "steipete/tap/sag", binary: "sag"), + kind: .tool), + ToolEntry( + id: "openhue-cli", + name: "๐Ÿ’ก OpenHue CLI", + url: URL(string: "https://github.com/openhue/openhue-cli")!, + description: "Control Philips Hue lights from scriptsโ€”scenes, dimming, and automations.", + method: .brew(formula: "openhue/cli/openhue-cli", binary: "openhue"), + kind: .tool), + ToolEntry( + id: "openai-whisper", + name: "๐ŸŽ™๏ธ OpenAI Whisper", + url: URL(string: "https://github.com/openai/whisper")!, + description: "Local speech-to-text for quick dictation and voicemail transcripts.", + method: .brew(formula: "openai-whisper", binary: "whisper"), + kind: .tool), + ToolEntry( + id: "gog", + name: "๐Ÿ“ฎ gog", + url: URL(string: "https://github.com/steipete/gogcli")!, + description: "Google Suite CLI: Gmail, Calendar, Drive, Contacts.", + method: .brew(formula: "steipete/tap/gogcli", binary: "gog"), + kind: .tool), + ToolEntry( + id: "gemini-cli", + name: "โ™Š๏ธ Gemini CLI", + url: URL(string: "https://github.com/google-gemini/gemini-cli")!, + description: "Google Gemini models from the terminal for fast Q&A and web-grounded summaries.", + method: .brew(formula: "gemini-cli", binary: "gemini"), + kind: .tool), + ToolEntry( + id: "bird", + name: "๐Ÿฆ bird", + url: URL(string: "https://github.com/steipete/bird")!, + description: "Fast X/Twitter CLI to tweet, reply, read threads, and search without a browser.", + method: .pnpm( + repoPath: "\(NSHomeDirectory())/Projects/bird", + script: "binary", + binary: "bird"), + kind: .tool), + ToolEntry( + id: "agent-tools", + name: "๐Ÿงฐ agent-tools", + url: URL(string: "https://github.com/badlogic/agent-tools")!, + description: "Collection of utilities and scripts tuned for autonomous agents and MCP clients.", + method: .gitClone( + url: "https://github.com/badlogic/agent-tools.git", + destination: "\(NSHomeDirectory())/agent-tools"), + kind: .tool), + ] + } @AppStorage("tools.packageManager") private var packageManagerRaw = NodePackageManager.npm.rawValue @State private var installStates: [String: InstallState] = [:] diff --git a/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift b/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift index 6ea494007..5a1079dde 100644 --- a/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift +++ b/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift @@ -35,7 +35,7 @@ struct SettingsViewSmokeTests { enabled: false, createdAtMs: 1_700_000_000_000, updatedAtMs: 1_700_000_100_000, - schedule: .every(everyMs: 30_000, anchorMs: nil), + schedule: .every(everyMs: 30000, anchorMs: nil), sessionTarget: .isolated, wakeMode: .nextHeartbeat, payload: .agentTurn( @@ -148,4 +148,8 @@ struct SettingsViewSmokeTests { let view = ToolsSettings() _ = view.body } + + @Test func toolsSettingsIncludesSummarize() { + #expect(ToolsSettings.toolIDsForTests.contains("summarize")) + } }