fix: resolve format/build failures

This commit is contained in:
Peter Steinberger
2026-01-19 11:32:15 +00:00
parent b826bd668c
commit 588dc43787
22 changed files with 82 additions and 106 deletions

View File

@@ -482,20 +482,20 @@ export function createExecTool(
"exec.approval.request",
{ timeoutMs: 130_000 },
{
command: params.command,
cwd: workdir,
host: "node",
security: hostSecurity,
ask: hostAsk,
agentId: defaults?.agentId,
resolvedPath: resolution?.resolvedPath ?? null,
sessionKey: defaults?.sessionKey ?? null,
timeoutMs: 120_000,
command: params.command,
cwd: workdir,
host: "node",
security: hostSecurity,
ask: hostAsk,
agentId: defaults?.agentId,
resolvedPath: resolution?.resolvedPath ?? null,
sessionKey: defaults?.sessionKey ?? null,
timeoutMs: 120_000,
},
)) as { decision?: string } | null;
const decision =
decisionResult && typeof decisionResult === "object"
? decisionResult.decision ?? null
? (decisionResult.decision ?? null)
: null;
if (decision === "deny") {
@@ -506,9 +506,7 @@ export function createExecTool(
approvedByAsk = true;
} else if (askFallback === "allowlist") {
if (!allowlistMatch) {
throw new Error(
"exec denied: approval required (approval UI not available)",
);
throw new Error("exec denied: approval required (approval UI not available)");
}
approvedByAsk = true;
} else {
@@ -611,20 +609,20 @@ export function createExecTool(
"exec.approval.request",
{ timeoutMs: 130_000 },
{
command: params.command,
cwd: workdir,
host: "gateway",
security: hostSecurity,
ask: hostAsk,
agentId: defaults?.agentId,
resolvedPath: resolution?.resolvedPath ?? null,
sessionKey: defaults?.sessionKey ?? null,
timeoutMs: 120_000,
command: params.command,
cwd: workdir,
host: "gateway",
security: hostSecurity,
ask: hostAsk,
agentId: defaults?.agentId,
resolvedPath: resolution?.resolvedPath ?? null,
sessionKey: defaults?.sessionKey ?? null,
timeoutMs: 120_000,
},
)) as { decision?: string } | null;
const decision =
decisionResult && typeof decisionResult === "object"
? decisionResult.decision ?? null
? (decisionResult.decision ?? null)
: null;
if (decision === "deny") {
@@ -635,9 +633,7 @@ export function createExecTool(
approvedByAsk = true;
} else if (askFallback === "allowlist") {
if (!allowlistMatch) {
throw new Error(
"exec denied: approval required (approval UI not available)",
);
throw new Error("exec denied: approval required (approval UI not available)");
}
approvedByAsk = true;
} else {

View File

@@ -55,7 +55,9 @@ function resolveAgentIdByWorkspace(
): string[] {
const list = listAgentEntries(cfg);
const ids =
list.length > 0 ? list.map((entry) => normalizeAgentId(entry.id)) : [resolveDefaultAgentId(cfg)];
list.length > 0
? list.map((entry) => normalizeAgentId(entry.id))
: [resolveDefaultAgentId(cfg)];
const normalizedTarget = normalizeWorkspacePath(workspaceDir);
return ids.filter(
(id) => normalizeWorkspacePath(resolveAgentWorkspaceDir(cfg, id)) === normalizedTarget,
@@ -134,10 +136,7 @@ export async function agentsSetIdentityCommand(
}
const fileTheme =
identityFromFile?.theme ??
identityFromFile?.creature ??
identityFromFile?.vibe ??
undefined;
identityFromFile?.theme ?? identityFromFile?.creature ?? identityFromFile?.vibe ?? undefined;
const incomingIdentity: IdentityConfig = {
...(nameRaw || identityFromFile?.name ? { name: nameRaw ?? identityFromFile?.name } : {}),
...(emojiRaw || identityFromFile?.emoji ? { emoji: emojiRaw ?? identityFromFile?.emoji } : {}),

View File

@@ -79,11 +79,7 @@ export function parseIdentityMarkdown(content: string): AgentIdentity {
const cleaned = line.trim().replace(/^\s*-\s*/, "");
const colonIndex = cleaned.indexOf(":");
if (colonIndex === -1) continue;
const label = cleaned
.slice(0, colonIndex)
.replace(/[*_]/g, "")
.trim()
.toLowerCase();
const label = cleaned.slice(0, colonIndex).replace(/[*_]/g, "").trim().toLowerCase();
const value = cleaned
.slice(colonIndex + 1)
.replace(/^[*_]+|[*_]+$/g, "")

View File

@@ -93,7 +93,12 @@ describe("agents set-identity command", () => {
configMocks.readConfigFileSnapshot.mockResolvedValue({
...baseSnapshot,
config: {
agents: { list: [{ id: "main", workspace }, { id: "ops", workspace }] },
agents: {
list: [
{ id: "main", workspace },
{ id: "ops", workspace },
],
},
},
});

View File

@@ -4,7 +4,12 @@ import type { LoggingConfig, SessionConfig, WebConfig } from "./types.base.js";
import type { BrowserConfig } from "./types.browser.js";
import type { ChannelsConfig } from "./types.channels.js";
import type { CronConfig } from "./types.cron.js";
import type { CanvasHostConfig, DiscoveryConfig, GatewayConfig, TalkConfig } from "./types.gateway.js";
import type {
CanvasHostConfig,
DiscoveryConfig,
GatewayConfig,
TalkConfig,
} from "./types.gateway.js";
import type { HooksConfig } from "./types.hooks.js";
import type {
AudioConfig,

View File

@@ -113,7 +113,6 @@ export type GatewayHttpConfig = {
endpoints?: GatewayHttpEndpointsConfig;
};
export type GatewayConfig = {
/** Single multiplexed port for Gateway WS + HTTP (default: 18789). */
port?: number;

View File

@@ -231,12 +231,7 @@ export const ClawdbotSchema = z
port: z.number().int().positive().optional(),
mode: z.union([z.literal("local"), z.literal("remote")]).optional(),
bind: z
.union([
z.literal("auto"),
z.literal("lan"),
z.literal("loopback"),
z.literal("custom"),
])
.union([z.literal("auto"), z.literal("lan"), z.literal("loopback"), z.literal("custom")])
.optional(),
controlUi: z
.object({

View File

@@ -136,10 +136,7 @@ export async function callGateway<T = unknown>(opts: CallGatewayOptions): Promis
});
const url = connectionDetails.url;
const useLocalTls =
config.gateway?.tls?.enabled === true &&
!urlOverride &&
!remoteUrl &&
url.startsWith("wss://");
config.gateway?.tls?.enabled === true && !urlOverride && !remoteUrl && url.startsWith("wss://");
const tlsRuntime = useLocalTls ? await loadGatewayTlsRuntime(config.gateway?.tls) : undefined;
const tlsFingerprint = tlsRuntime?.enabled ? tlsRuntime.fingerprintSha256 : undefined;
const token =

View File

@@ -93,22 +93,14 @@ export class GatewayClient {
wsOptions.checkServerIdentity = (_host: string, cert: CertMeta) => {
const fingerprintValue =
typeof cert === "object" && cert && "fingerprint256" in cert
? (cert as { fingerprint256?: string }).fingerprint256 ?? ""
? ((cert as { fingerprint256?: string }).fingerprint256 ?? "")
: "";
const fingerprint = normalizeFingerprint(
typeof fingerprintValue === "string" ? fingerprintValue : "",
);
const expected = normalizeFingerprint(this.opts.tlsFingerprint ?? "");
if (!expected) {
return new Error("gateway tls fingerprint missing");
}
if (!fingerprint) {
return new Error("gateway tls fingerprint unavailable");
}
if (fingerprint !== expected) {
return new Error("gateway tls fingerprint mismatch");
}
return undefined;
if (!expected || !fingerprint) return false;
return fingerprint === expected;
};
}
this.ws = new WebSocket(url, wsOptions);

View File

@@ -45,7 +45,10 @@ export class ExecApprovalManager {
return record;
}
async waitForDecision(record: ExecApprovalRecord, timeoutMs: number): Promise<ExecApprovalDecision | null> {
async waitForDecision(
record: ExecApprovalRecord,
timeoutMs: number,
): Promise<ExecApprovalDecision | null> {
return await new Promise<ExecApprovalDecision | null>((resolve, reject) => {
const timer = setTimeout(() => {
this.pending.delete(record.id);

View File

@@ -45,7 +45,7 @@ export class NodeRegistry {
const nodeId = connect.device?.id ?? connect.client.id;
const caps = Array.isArray(connect.caps) ? connect.caps : [];
const commands = Array.isArray((connect as { commands?: string[] }).commands)
? (connect as { commands?: string[] }).commands ?? []
? ((connect as { commands?: string[] }).commands ?? [])
: [];
const permissions =
typeof (connect as { permissions?: Record<string, boolean> }).permissions === "object"

View File

@@ -222,7 +222,7 @@ export function createAgentEventHandler({
evt.stream === "lifecycle" && typeof evt.data?.phase === "string" ? evt.data.phase : null;
if (sessionKey) {
nodeSendToSession(sessionKey, "agent", agentPayload);
nodeSendToSession(sessionKey, "agent", agentPayload);
if (!isAborted && evt.stream === "assistant" && typeof evt.data?.text === "string") {
emitChatDelta(sessionKey, clientRunId, evt.seq, evt.data.text);
} else if (!isAborted && (lifecyclePhase === "end" || lifecyclePhase === "error")) {

View File

@@ -9,9 +9,7 @@ import {
} from "../protocol/index.js";
import type { GatewayRequestHandlers } from "./types.js";
export function createExecApprovalHandlers(
manager: ExecApprovalManager,
): GatewayRequestHandlers {
export function createExecApprovalHandlers(manager: ExecApprovalManager): GatewayRequestHandlers {
return {
"exec.approval.request": async ({ params, respond, context }) => {
if (!validateExecApprovalRequestParams(params)) {
@@ -61,12 +59,16 @@ export function createExecApprovalHandlers(
{ dropIfSlow: true },
);
const decision = await manager.waitForDecision(record, timeoutMs);
respond(true, {
id: record.id,
decision,
createdAtMs: record.createdAtMs,
expiresAtMs: record.expiresAtMs,
}, undefined);
respond(
true,
{
id: record.id,
decision,
createdAtMs: record.createdAtMs,
expiresAtMs: record.expiresAtMs,
},
undefined,
);
},
"exec.approval.resolve": async ({ params, respond, client, context }) => {
if (!validateExecApprovalResolveParams(params)) {

View File

@@ -453,14 +453,10 @@ export const nodeHandlers: GatewayRequestHandlers = {
loadGatewayModelCatalog: context.loadGatewayModelCatalog,
logGateway: { warn: context.logGateway.warn },
};
await handleNodeEvent(
nodeContext,
"node",
{
event: p.event,
payloadJSON,
},
);
await handleNodeEvent(nodeContext, "node", {
event: p.event,
payloadJSON,
});
respond(true, { ok: true }, undefined);
});
},

View File

@@ -11,11 +11,7 @@ import type { NodeEvent, NodeEventContext } from "./server-node-events-types.js"
import { loadSessionEntry } from "./session-utils.js";
import { formatForLog } from "./ws-log.js";
export const handleNodeEvent = async (
ctx: NodeEventContext,
nodeId: string,
evt: NodeEvent,
) => {
export const handleNodeEvent = async (ctx: NodeEventContext, nodeId: string, evt: NodeEvent) => {
switch (evt.event) {
case "voice.transcript": {
if (!evt.payloadJSON) return;

View File

@@ -1,4 +1,9 @@
import type { GatewayAuthConfig, GatewayBindMode, GatewayTailscaleConfig, loadConfig } from "../config/config.js";
import type {
GatewayAuthConfig,
GatewayBindMode,
GatewayTailscaleConfig,
loadConfig,
} from "../config/config.js";
import {
assertGatewayAuthConfigured,
type ResolvedGatewayAuth,

View File

@@ -22,7 +22,9 @@ export function logGatewayStartup(params: {
consoleMessage: `agent model: ${chalk.whiteBright(modelRef)}`,
});
const scheme = params.tlsEnabled ? "wss" : "ws";
params.log.info(`listening on ${scheme}://${params.bindHost}:${params.port} (PID ${process.pid})`);
params.log.info(
`listening on ${scheme}://${params.bindHost}:${params.port} (PID ${process.pid})`,
);
params.log.info(`log file: ${getResolvedLoggerSettings().file}`);
if (params.isNixMode) {
params.log.info("gateway: running in Nix mode (config managed externally)");

View File

@@ -260,5 +260,4 @@ describe("gateway server models + voicewake", () => {
ws.close();
await server.close();
});
});

View File

@@ -499,7 +499,9 @@ export function attachGatewayWsMessageHandler(params: {
commands: nodeSession.commands,
cfg: loadConfig(),
}).catch((err) =>
logGateway.warn(`remote bin probe failed for ${nodeSession.nodeId}: ${formatForLog(err)}`),
logGateway.warn(
`remote bin probe failed for ${nodeSession.nodeId}: ${formatForLog(err)}`,
),
);
void loadVoiceWakeConfig()
.then((cfg) => {

View File

@@ -13,7 +13,6 @@ import type { PluginRegistry } from "../plugins/registry.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { DEFAULT_ACCOUNT_ID } from "../routing/session-key.js";
type StubChannelOptions = {
id: ChannelPlugin["id"];
label: string;

View File

@@ -27,11 +27,7 @@ function ensureDir(filePath: string) {
const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
function base64UrlEncode(buf: Buffer): string {
return buf
.toString("base64")
.replaceAll("+", "-")
.replaceAll("/", "_")
.replace(/=+$/g, "");
return buf.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/g, "");
}
function base64UrlDecode(input: string): Buffer {

View File

@@ -26,10 +26,7 @@ import { getMachineDisplayName } from "../infra/machine-name.js";
import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js";
import { loadConfig } from "../config/config.js";
import { VERSION } from "../version.js";
import {
GATEWAY_CLIENT_MODES,
GATEWAY_CLIENT_NAMES,
} from "../utils/message-channel.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { ensureNodeHostConfig, saveNodeHostConfig, type NodeHostGatewayConfig } from "./config.js";
import { GatewayClient } from "../gateway/client.js";
@@ -804,8 +801,7 @@ function coerceNodeInvokePayload(payload: unknown): NodeInvokeRequestPayload | n
? JSON.stringify(obj.params)
: null;
const timeoutMs = typeof obj.timeoutMs === "number" ? obj.timeoutMs : null;
const idempotencyKey =
typeof obj.idempotencyKey === "string" ? obj.idempotencyKey : null;
const idempotencyKey = typeof obj.idempotencyKey === "string" ? obj.idempotencyKey : null;
return {
id,
nodeId,
@@ -840,11 +836,7 @@ async function sendInvokeResult(
}
}
async function sendNodeEvent(
client: GatewayClient,
event: string,
payload: unknown,
) {
async function sendNodeEvent(client: GatewayClient, event: string, payload: unknown) {
try {
await client.request("node.event", {
event,