diff --git a/src/agents/clawdis-tools.sessions.test.ts b/src/agents/clawdis-tools.sessions.test.ts index e764e20f8..e45846b14 100644 --- a/src/agents/clawdis-tools.sessions.test.ts +++ b/src/agents/clawdis-tools.sessions.test.ts @@ -125,7 +125,7 @@ describe("sessions tools", () => { callGatewayMock.mockReset(); const calls: Array<{ method?: string; params?: unknown }> = []; let agentCallCount = 0; - let historyCallCount = 0; + let _historyCallCount = 0; let sendCallCount = 0; let waitRunId: string | undefined; let nextHistoryIsWaitReply = false; @@ -153,7 +153,7 @@ describe("sessions tools", () => { return { runId: params?.runId ?? "run-1", status: "ok" }; } if (request.method === "chat.history") { - historyCallCount += 1; + _historyCallCount += 1; const text = nextHistoryIsWaitReply ? "done" : "ANNOUNCE_SKIP"; nextHistoryIsWaitReply = false; return { @@ -219,8 +219,9 @@ describe("sessions tools", () => { (call) => typeof (call.params as { extraSystemPrompt?: string }) ?.extraSystemPrompt === "string" && - (call.params as { extraSystemPrompt?: string }) - ?.extraSystemPrompt?.includes("Agent-to-agent message context"), + ( + call.params as { extraSystemPrompt?: string } + )?.extraSystemPrompt?.includes("Agent-to-agent message context"), ), ).toBe(true); expect( @@ -228,8 +229,9 @@ describe("sessions tools", () => { (call) => typeof (call.params as { extraSystemPrompt?: string }) ?.extraSystemPrompt === "string" && - (call.params as { extraSystemPrompt?: string }) - ?.extraSystemPrompt?.includes("Agent-to-agent post step"), + ( + call.params as { extraSystemPrompt?: string } + )?.extraSystemPrompt?.includes("Agent-to-agent post step"), ), ).toBe(true); expect(waitCalls).toHaveLength(3); diff --git a/src/agents/clawdis-tools.ts b/src/agents/clawdis-tools.ts index 7f785baba..5b0d1e2ed 100644 --- a/src/agents/clawdis-tools.ts +++ b/src/agents/clawdis-tools.ts @@ -2774,7 +2774,9 @@ function buildAgentToAgentPostContext(params: { ? `Requester surface: ${params.requesterSurface}.` : undefined, `Target session: ${params.targetSessionKey}.`, - params.targetChannel ? `Target surface: ${params.targetChannel}.` : undefined, + params.targetChannel + ? `Target surface: ${params.targetChannel}.` + : undefined, `Original request: ${params.originalMessage}`, params.roundOneReply ? `Round 1 reply: ${params.roundOneReply}` @@ -2840,34 +2842,35 @@ function createSessionsSendTool(opts?: { extraSystemPrompt: agentMessageContext, }; - const resolveAnnounceTarget = async (): Promise => { - const parsed = resolveAnnounceTargetFromKey(resolvedKey); - if (parsed) return parsed; - try { - const list = (await callGateway({ - method: "sessions.list", - params: { - includeGlobal: true, - includeUnknown: true, - limit: 200, - }, - })) as { sessions?: Array> }; - const sessions = Array.isArray(list?.sessions) ? list.sessions : []; - const match = - sessions.find((entry) => entry?.key === resolvedKey) ?? - sessions.find((entry) => entry?.key === displayKey); - const channel = - typeof match?.lastChannel === "string" - ? match.lastChannel - : undefined; - const to = - typeof match?.lastTo === "string" ? match.lastTo : undefined; - if (channel && to) return { channel, to }; - } catch { - // ignore; fall through to null - } - return null; - }; + const resolveAnnounceTarget = + async (): Promise => { + const parsed = resolveAnnounceTargetFromKey(resolvedKey); + if (parsed) return parsed; + try { + const list = (await callGateway({ + method: "sessions.list", + params: { + includeGlobal: true, + includeUnknown: true, + limit: 200, + }, + })) as { sessions?: Array> }; + const sessions = Array.isArray(list?.sessions) ? list.sessions : []; + const match = + sessions.find((entry) => entry?.key === resolvedKey) ?? + sessions.find((entry) => entry?.key === displayKey); + const channel = + typeof match?.lastChannel === "string" + ? match.lastChannel + : undefined; + const to = + typeof match?.lastTo === "string" ? match.lastTo : undefined; + if (channel && to) return { channel, to }; + } catch { + // ignore; fall through to null + } + return null; + }; const runAgentToAgentPost = async (roundOneReply?: string) => { const announceTarget = await resolveAnnounceTarget(); @@ -2917,9 +2920,7 @@ function createSessionsSendTool(opts?: { params: { sessionKey: resolvedKey, limit: 50 }, })) as { messages?: unknown[] }; const postFiltered = stripToolMessages( - Array.isArray(postHistory?.messages) - ? postHistory.messages - : [], + Array.isArray(postHistory?.messages) ? postHistory.messages : [], ); const postLast = postFiltered.length > 0 diff --git a/src/commands/onboard-skills.ts b/src/commands/onboard-skills.ts index 7b52fc069..a15f9b5cd 100644 --- a/src/commands/onboard-skills.ts +++ b/src/commands/onboard-skills.ts @@ -3,7 +3,7 @@ import { buildWorkspaceSkillStatus } from "../agents/skills-status.js"; import type { ClawdisConfig } from "../config/config.js"; import type { RuntimeEnv } from "../runtime.js"; import type { WizardPrompter } from "../wizard/prompts.js"; -import { resolveNodeManagerOptions } from "./onboard-helpers.js"; +import { detectBinary, resolveNodeManagerOptions } from "./onboard-helpers.js"; function summarizeInstallFailure(message: string): string | undefined { const cleaned = message @@ -59,6 +59,13 @@ export async function setupSkills( ); const blocked = report.skills.filter((s) => s.blockedByAllowlist); + const needsBrewPrompt = + process.platform !== "win32" && + report.skills.some((skill) => + skill.install.some((option) => option.kind === "brew"), + ) && + !(await detectBinary("brew")); + await prompter.note( [ `Eligible: ${eligible.length}`, @@ -74,6 +81,29 @@ export async function setupSkills( }); if (!shouldConfigure) return cfg; + if (needsBrewPrompt) { + await prompter.note( + [ + "Many skill dependencies are shipped via Homebrew.", + "Without brew, you'll need to build from source or download releases manually.", + ].join("\n"), + "Homebrew recommended", + ); + const showBrewInstall = await prompter.confirm({ + message: "Show Homebrew install command?", + initialValue: true, + }); + if (showBrewInstall) { + await prompter.note( + [ + "Run:", + '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', + ].join("\n"), + "Homebrew install", + ); + } + } + const nodeManager = (await prompter.select({ message: "Preferred node manager for skill installs", options: resolveNodeManagerOptions(), diff --git a/src/gateway/server-methods.ts b/src/gateway/server-methods.ts index f9b2f8ee2..df6e5a5e4 100644 --- a/src/gateway/server-methods.ts +++ b/src/gateway/server-methods.ts @@ -57,7 +57,10 @@ import { type DiscordProbe, probeDiscord } from "../discord/probe.js"; import { shouldLogVerbose } from "../globals.js"; import { sendMessageIMessage } from "../imessage/index.js"; import { type IMessageProbe, probeIMessage } from "../imessage/probe.js"; -import { onAgentEvent, registerAgentRunContext } from "../infra/agent-events.js"; +import { + onAgentEvent, + registerAgentRunContext, +} from "../infra/agent-events.js"; import type { startNodeBridgeServer } from "../infra/bridge/server.js"; import { getLastHeartbeatEvent } from "../infra/heartbeat-events.js"; import { setHeartbeatsEnabled } from "../infra/heartbeat-runner.js"; diff --git a/src/gateway/server.cron.test.ts b/src/gateway/server.cron.test.ts index aa6bf6839..b2af8bbc8 100644 --- a/src/gateway/server.cron.test.ts +++ b/src/gateway/server.cron.test.ts @@ -214,9 +214,7 @@ describe("gateway server cron", () => { testState.cronStorePath = undefined; }); - test( - "enables cron scheduler by default and runs due jobs automatically", - async () => { + test("enables cron scheduler by default and runs due jobs automatically", async () => { const dir = await fs.mkdtemp( path.join(os.tmpdir(), "clawdis-gw-cron-default-on-"), ); @@ -307,7 +305,5 @@ describe("gateway server cron", () => { testState.cronStorePath = undefined; await fs.rm(dir, { recursive: true, force: true }); } - }, - 15_000, - ); + }, 15_000); });