Compare commits

...
5 changed files with 22 additions and 10 deletions

No files matched your search

+1
View File
@@ -55,6 +55,7 @@
### Fixes ### Fixes
- Gog calendar: format date ranges as RFC 3339 with timezone to satisfy Google Calendar API (thanks @jayhickey). - Gog calendar: format date ranges as RFC 3339 with timezone to satisfy Google Calendar API (thanks @jayhickey).
- macOS onboarding: add scrollable page gutter for overflowing content (#105) — thanks @thewilloftheshadow.
- Chat UI: keep the chat scrolled to the latest message after switching sessions. - Chat UI: keep the chat scrolled to the latest message after switching sessions.
- Auto-reply: stream completed reply blocks as soon as they finish (configurable default + break); skip empty tool-only blocks unless verbose. - Auto-reply: stream completed reply blocks as soon as they finish (configurable default + break); skip empty tool-only blocks unless verbose.
- Discord: avoid duplicate sends when block streaming is enabled (race with typing hook). - Discord: avoid duplicate sends when block streaming is enabled (race with typing hook).
@@ -133,10 +133,16 @@ extension OnboardingView {
} }
func onboardingPage(@ViewBuilder _ content: () -> some View) -> some View { func onboardingPage(@ViewBuilder _ content: () -> some View) -> some View {
VStack(spacing: 16) { let scrollIndicatorGutter: CGFloat = 18
content() return ScrollView {
Spacer() VStack(spacing: 16) {
content()
Spacer(minLength: 0)
}
.frame(maxWidth: .infinity, alignment: .top)
.padding(.trailing, scrollIndicatorGutter)
} }
.scrollIndicators(.automatic)
.padding(.horizontal, 28) .padding(.horizontal, 28)
.frame(width: self.pageWidth, alignment: .top) .frame(width: self.pageWidth, alignment: .top)
} }
@@ -442,7 +442,7 @@ extension OnboardingView {
} }
func permissionsPage() -> some View { func permissionsPage() -> some View {
self.onboardingPage { return self.onboardingPage {
Text("Grant permissions") Text("Grant permissions")
.font(.largeTitle.weight(.semibold)) .font(.largeTitle.weight(.semibold))
Text("These macOS permissions let Clawdis automate apps and capture context on this Mac.") Text("These macOS permissions let Clawdis automate apps and capture context on this Mac.")
+8 -3
View File
@@ -396,6 +396,11 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
MediaType: media?.contentType, MediaType: media?.contentType,
MediaUrl: media?.path, MediaUrl: media?.path,
}; };
const replyTarget = ctxPayload.To ?? undefined;
if (!replyTarget) {
runtime.error?.(danger("discord: missing reply target"));
return;
}
if (isDirectMessage) { if (isDirectMessage) {
const sessionCfg = cfg.session; const sessionCfg = cfg.session;
@@ -430,7 +435,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
.then(async () => { .then(async () => {
await deliverReplies({ await deliverReplies({
replies: [payload], replies: [payload],
target: ctxPayload.To, target: replyTarget,
token, token,
runtime, runtime,
replyToMode, replyToMode,
@@ -473,7 +478,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
await deliverReplies({ await deliverReplies({
replies, replies,
target: ctxPayload.To, target: replyTarget,
token, token,
runtime, runtime,
replyToMode, replyToMode,
@@ -482,7 +487,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
didSendReply = true; didSendReply = true;
if (isVerbose()) { if (isVerbose()) {
logVerbose( logVerbose(
`discord: delivered ${replies.length} reply${replies.length === 1 ? "" : "ies"} to ${ctxPayload.To}`, `discord: delivered ${replies.length} reply${replies.length === 1 ? "" : "ies"} to ${replyTarget}`,
); );
} }
if ( if (
+3 -3
View File
@@ -27,6 +27,7 @@ export async function callGateway<T = unknown>(
const config = loadConfig(); const config = loadConfig();
const isRemoteMode = config.gateway?.mode === "remote"; const isRemoteMode = config.gateway?.mode === "remote";
const remote = isRemoteMode ? config.gateway?.remote : undefined; const remote = isRemoteMode ? config.gateway?.remote : undefined;
const authToken = config.gateway?.auth?.token;
const url = const url =
(typeof opts.url === "string" && opts.url.trim().length > 0 (typeof opts.url === "string" && opts.url.trim().length > 0
? opts.url.trim() ? opts.url.trim()
@@ -44,9 +45,8 @@ export async function callGateway<T = unknown>(
? remote.token.trim() ? remote.token.trim()
: undefined : undefined
: process.env.CLAWDIS_GATEWAY_TOKEN?.trim() || : process.env.CLAWDIS_GATEWAY_TOKEN?.trim() ||
(typeof config.gateway?.auth?.token === "string" && (typeof authToken === "string" && authToken.trim().length > 0
config.gateway.auth.token.trim().length > 0 ? authToken.trim()
? config.gateway.auth.token.trim()
: undefined)); : undefined));
const password = const password =
(typeof opts.password === "string" && opts.password.trim().length > 0 (typeof opts.password === "string" && opts.password.trim().length > 0