Compare commits
2 Commits
main
...
fix/export
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c163c71b5 | ||
|
|
277881b52f |
@ -24,6 +24,7 @@ Docs: https://docs.clawd.bot
|
|||||||
- Cron: cap reminder context history to 10 messages and honor `contextMessages`. (#1103) Thanks @mkbehr.
|
- Cron: cap reminder context history to 10 messages and honor `contextMessages`. (#1103) Thanks @mkbehr.
|
||||||
- Exec approvals: treat main as the default agent + migrate legacy default allowlists. (#1417) Thanks @czekaj.
|
- Exec approvals: treat main as the default agent + migrate legacy default allowlists. (#1417) Thanks @czekaj.
|
||||||
- UI: refresh debug panel on route-driven tab changes. (#1373) Thanks @yazinsai.
|
- UI: refresh debug panel on route-driven tab changes. (#1373) Thanks @yazinsai.
|
||||||
|
- UI: export config form section metadata for shared usage. (#1418) Thanks @MaudeBot.
|
||||||
|
|
||||||
## 2026.1.21
|
## 2026.1.21
|
||||||
|
|
||||||
|
|||||||
@ -141,6 +141,10 @@ describe("createTelegramBot", () => {
|
|||||||
// groupPolicy tests
|
// groupPolicy tests
|
||||||
|
|
||||||
it("accepts group messages when mentionPatterns match (without @botUsername)", async () => {
|
it("accepts group messages when mentionPatterns match (without @botUsername)", async () => {
|
||||||
|
const originalTz = process.env.TZ;
|
||||||
|
process.env.TZ = "UTC";
|
||||||
|
|
||||||
|
try {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
@ -176,9 +180,18 @@ describe("createTelegramBot", () => {
|
|||||||
expect(payload.WasMentioned).toBe(true);
|
expect(payload.WasMentioned).toBe(true);
|
||||||
expect(payload.SenderName).toBe("Ada");
|
expect(payload.SenderName).toBe("Ada");
|
||||||
expect(payload.SenderId).toBe("9");
|
expect(payload.SenderId).toBe("9");
|
||||||
expect(payload.Body).toMatch(/^\[Telegram Test Group id:7 (\+\d+[smhd] )?2025-01-09T00:00Z\]/);
|
expect(payload.Body).toMatch(
|
||||||
|
/^\[Telegram Test Group id:7 (\+\d+[smhd] )?2025-01-09 00:00 [^\]]+\]/,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
process.env.TZ = originalTz;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
it("keeps group envelope headers stable (sender identity is separate)", async () => {
|
it("keeps group envelope headers stable (sender identity is separate)", async () => {
|
||||||
|
const originalTz = process.env.TZ;
|
||||||
|
process.env.TZ = "UTC";
|
||||||
|
|
||||||
|
try {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
@ -217,7 +230,12 @@ describe("createTelegramBot", () => {
|
|||||||
expect(payload.SenderName).toBe("Ada Lovelace");
|
expect(payload.SenderName).toBe("Ada Lovelace");
|
||||||
expect(payload.SenderId).toBe("99");
|
expect(payload.SenderId).toBe("99");
|
||||||
expect(payload.SenderUsername).toBe("ada");
|
expect(payload.SenderUsername).toBe("ada");
|
||||||
expect(payload.Body).toMatch(/^\[Telegram Ops id:42 (\+\d+[smhd] )?2025-01-09T00:00Z\]/);
|
expect(payload.Body).toMatch(
|
||||||
|
/^\[Telegram Ops id:42 (\+\d+[smhd] )?2025-01-09 00:00 [^\]]+\]/,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
process.env.TZ = originalTz;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
|
|||||||
@ -329,7 +329,7 @@ describe("createTelegramBot", () => {
|
|||||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||||
const payload = replySpy.mock.calls[0][0];
|
const payload = replySpy.mock.calls[0][0];
|
||||||
expect(payload.Body).toMatch(
|
expect(payload.Body).toMatch(
|
||||||
/^\[Telegram Ada Lovelace \(@ada_bot\) id:1234 (\+\d+[smhd] )?2025-01-09T00:00Z\]/,
|
/^\[Telegram Ada Lovelace \(@ada_bot\) id:1234 (\+\d+[smhd] )?2025-01-09 01:00 [^\]]+\]/,
|
||||||
);
|
);
|
||||||
expect(payload.Body).toContain("hello world");
|
expect(payload.Body).toContain("hello world");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -451,7 +451,7 @@ describe("createTelegramBot", () => {
|
|||||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||||
const payload = replySpy.mock.calls[0][0];
|
const payload = replySpy.mock.calls[0][0];
|
||||||
expect(payload.Body).toMatch(
|
expect(payload.Body).toMatch(
|
||||||
/^\[Telegram Ada Lovelace \(@ada_bot\) id:1234 (\+\d+[smhd] )?2025-01-09T00:00Z\]/,
|
/^\[Telegram Ada Lovelace \(@ada_bot\) id:1234 (\+\d+[smhd] )?2025-01-09 01:00 [^\]]+\]/,
|
||||||
);
|
);
|
||||||
expect(payload.Body).toContain("hello world");
|
expect(payload.Body).toContain("hello world");
|
||||||
} finally {
|
} finally {
|
||||||
@ -551,6 +551,10 @@ describe("createTelegramBot", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("accepts group messages when mentionPatterns match (without @botUsername)", async () => {
|
it("accepts group messages when mentionPatterns match (without @botUsername)", async () => {
|
||||||
|
const originalTz = process.env.TZ;
|
||||||
|
process.env.TZ = "UTC";
|
||||||
|
|
||||||
|
try {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
@ -585,12 +589,21 @@ describe("createTelegramBot", () => {
|
|||||||
const payload = replySpy.mock.calls[0][0];
|
const payload = replySpy.mock.calls[0][0];
|
||||||
expectInboundContextContract(payload);
|
expectInboundContextContract(payload);
|
||||||
expect(payload.WasMentioned).toBe(true);
|
expect(payload.WasMentioned).toBe(true);
|
||||||
expect(payload.Body).toMatch(/^\[Telegram Test Group id:7 (\+\d+[smhd] )?2025-01-09T00:00Z\]/);
|
expect(payload.Body).toMatch(
|
||||||
|
/^\[Telegram Test Group id:7 (\+\d+[smhd] )?2025-01-09 00:00 [^\]]+\]/,
|
||||||
|
);
|
||||||
expect(payload.SenderName).toBe("Ada");
|
expect(payload.SenderName).toBe("Ada");
|
||||||
expect(payload.SenderId).toBe("9");
|
expect(payload.SenderId).toBe("9");
|
||||||
|
} finally {
|
||||||
|
process.env.TZ = originalTz;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes sender identity in group envelope headers", async () => {
|
it("includes sender identity in group envelope headers", async () => {
|
||||||
|
const originalTz = process.env.TZ;
|
||||||
|
process.env.TZ = "UTC";
|
||||||
|
|
||||||
|
try {
|
||||||
onSpy.mockReset();
|
onSpy.mockReset();
|
||||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
|
||||||
replySpy.mockReset();
|
replySpy.mockReset();
|
||||||
@ -627,10 +640,15 @@ describe("createTelegramBot", () => {
|
|||||||
expect(replySpy).toHaveBeenCalledTimes(1);
|
expect(replySpy).toHaveBeenCalledTimes(1);
|
||||||
const payload = replySpy.mock.calls[0][0];
|
const payload = replySpy.mock.calls[0][0];
|
||||||
expectInboundContextContract(payload);
|
expectInboundContextContract(payload);
|
||||||
expect(payload.Body).toMatch(/^\[Telegram Ops id:42 (\+\d+[smhd] )?2025-01-09T00:00Z\]/);
|
expect(payload.Body).toMatch(
|
||||||
|
/^\[Telegram Ops id:42 (\+\d+[smhd] )?2025-01-09 00:00 [^\]]+\]/,
|
||||||
|
);
|
||||||
expect(payload.SenderName).toBe("Ada Lovelace");
|
expect(payload.SenderName).toBe("Ada Lovelace");
|
||||||
expect(payload.SenderId).toBe("99");
|
expect(payload.SenderId).toBe("99");
|
||||||
expect(payload.SenderUsername).toBe("ada");
|
expect(payload.SenderUsername).toBe("ada");
|
||||||
|
} finally {
|
||||||
|
process.env.TZ = originalTz;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
||||||
|
|||||||
@ -329,11 +329,11 @@ describe("web auto-reply", () => {
|
|||||||
const firstArgs = resolver.mock.calls[0][0];
|
const firstArgs = resolver.mock.calls[0][0];
|
||||||
const secondArgs = resolver.mock.calls[1][0];
|
const secondArgs = resolver.mock.calls[1][0];
|
||||||
expect(firstArgs.Body).toMatch(
|
expect(firstArgs.Body).toMatch(
|
||||||
/\[WhatsApp \+1 (\+\d+[smhd] )?2025-01-01T00:00Z\] \[clawdbot\] first/,
|
/\[WhatsApp \+1 (\+\d+[smhd] )?2025-01-01 01:00 [^\]]+\] \[clawdbot\] first/,
|
||||||
);
|
);
|
||||||
expect(firstArgs.Body).not.toContain("second");
|
expect(firstArgs.Body).not.toContain("second");
|
||||||
expect(secondArgs.Body).toMatch(
|
expect(secondArgs.Body).toMatch(
|
||||||
/\[WhatsApp \+1 (\+\d+[smhd] )?2025-01-01T01:00Z\] \[clawdbot\] second/,
|
/\[WhatsApp \+1 (\+\d+[smhd] )?2025-01-01 02:00 [^\]]+\] \[clawdbot\] second/,
|
||||||
);
|
);
|
||||||
expect(secondArgs.Body).not.toContain("first");
|
expect(secondArgs.Body).not.toContain("first");
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { render } from "lit";
|
import { render } from "lit";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import { analyzeConfigSchema, renderConfigForm } from "./views/config-form";
|
import { analyzeConfigSchema, renderConfigForm, SECTION_META } from "./views/config-form";
|
||||||
|
|
||||||
const rootSchema = {
|
const rootSchema = {
|
||||||
type: "object",
|
type: "object",
|
||||||
@ -40,6 +40,10 @@ const rootSchema = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("config form renderer", () => {
|
describe("config form renderer", () => {
|
||||||
|
it("exposes section metadata", () => {
|
||||||
|
expect(SECTION_META.env.label).toBe("Environment Variables");
|
||||||
|
});
|
||||||
|
|
||||||
it("renders inputs and patches values", () => {
|
it("renders inputs and patches values", () => {
|
||||||
const onPatch = vi.fn();
|
const onPatch = vi.fn();
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
|
|||||||
@ -54,7 +54,7 @@ const sectionIcons = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Section metadata
|
// Section metadata
|
||||||
const SECTION_META: Record<string, { label: string; description: string }> = {
|
export const SECTION_META: Record<string, { label: string; description: string }> = {
|
||||||
env: { label: "Environment Variables", description: "Environment variables passed to the gateway process" },
|
env: { label: "Environment Variables", description: "Environment variables passed to the gateway process" },
|
||||||
update: { label: "Updates", description: "Auto-update settings and release channel" },
|
update: { label: "Updates", description: "Auto-update settings and release channel" },
|
||||||
agents: { label: "Agents", description: "Agent configurations, models, and identities" },
|
agents: { label: "Agents", description: "Agent configurations, models, and identities" },
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export { renderConfigForm, type ConfigFormProps } from "./config-form.render";
|
export { renderConfigForm, type ConfigFormProps, SECTION_META } from "./config-form.render";
|
||||||
export {
|
export {
|
||||||
analyzeConfigSchema,
|
analyzeConfigSchema,
|
||||||
type ConfigSchemaAnalysis,
|
type ConfigSchemaAnalysis,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { html, nothing } from "lit";
|
import { html, nothing } from "lit";
|
||||||
import type { ConfigUiHints } from "../types";
|
import type { ConfigUiHints } from "../types";
|
||||||
import { analyzeConfigSchema, renderConfigForm } from "./config-form";
|
import { analyzeConfigSchema, renderConfigForm, SECTION_META } from "./config-form";
|
||||||
import {
|
import {
|
||||||
hintForPath,
|
hintForPath,
|
||||||
humanize,
|
humanize,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user