Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ jobs:
run: ${{ matrix.command }}

macos-app:
if: github.event_name == 'pull_request'
if: github.event_name == 'pull_request' && github.repository_owner == 'openclaw'
runs-on: macos-latest
strategy:
fail-fast: false
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Claude Code

on:
issues:
types: [opened, edited]
issue_comment:
types: [created, edited]

jobs:
claude:
runs-on: ubuntu-latest
# Only run when @claude is mentioned in issues/comments
if: contains(github.event.comment.body, '@claude') || contains(github.event.issue.body, '@claude')
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Run Claude Code
uses: anthropics/claude-code-action@v1
with:
prompt: |
${{ github.event.comment.body || github.event.issue.body }}
claude_args: |
--max-turns 10
env:
# Use OAuth token for Claude Max/Pro subscription (no API key needed)
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ permissions: {}

jobs:
label:
if: github.repository_owner == 'openclaw' && secrets.GH_APP_PRIVATE_KEY != ''
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secrets.GH_APP_PRIVATE_KEY reference won't work in if condition

Suggested change
if: github.repository_owner == 'openclaw' && secrets.GH_APP_PRIVATE_KEY != ''
if: github.repository_owner == 'openclaw'
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/labeler.yml
Line: 13:13

Comment:
`secrets.GH_APP_PRIVATE_KEY` reference won't work in `if` condition

```suggestion
    if: github.repository_owner == 'openclaw'
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Condition won't work as intended. Secrets aren't available in if conditions — they're always empty strings in workflow expressions. This check will always evaluate to false on forks.

Suggested change
if: github.repository_owner == 'openclaw' && secrets.GH_APP_PRIVATE_KEY != ''
if: github.repository_owner == 'openclaw'

The secret availability will be enforced when the step tries to use it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/labeler.yml
Line: 13

Comment:
Condition won't work as intended. Secrets aren't available in `if` conditions — they're always empty strings in workflow expressions. This check will always evaluate to false on forks.

```suggestion
    if: github.repository_owner == 'openclaw'
```

The secret availability will be enforced when the step tries to use it.

How can I resolve this? If you propose a fix, please make it concise.

permissions:
contents: read
pull-requests: write
Expand Down Expand Up @@ -48,6 +49,7 @@ jobs:
});

label-issues:
if: github.repository_owner == 'openclaw' && secrets.GH_APP_PRIVATE_KEY != ''
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue — secret check in if won't work.

Suggested change
if: github.repository_owner == 'openclaw' && secrets.GH_APP_PRIVATE_KEY != ''
if: github.repository_owner == 'openclaw'
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/labeler.yml
Line: 52

Comment:
Same issue — secret check in `if` won't work.

```suggestion
    if: github.repository_owner == 'openclaw'
```

How can I resolve this? If you propose a fix, please make it concise.

permissions:
issues: write
runs-on: ubuntu-latest
Expand Down
21 changes: 18 additions & 3 deletions extensions/memory-lancedb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
* Provides seamless auto-recall and auto-capture via lifecycle hooks.
*/

import type * as LanceDB from "@lancedb/lancedb";
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import * as lancedb from "@lancedb/lancedb";
import { Type } from "@sinclair/typebox";
import { randomUUID } from "node:crypto";
import OpenAI from "openai";
Expand Down Expand Up @@ -44,8 +44,9 @@ type MemorySearchResult = {
const TABLE_NAME = "memories";

class MemoryDB {
private db: lancedb.Connection | null = null;
private table: lancedb.Table | null = null;
private lancedb: typeof import("@lancedb/lancedb") | null = null;
private db: LanceDB.Connection | null = null;
private table: LanceDB.Table | null = null;
private initPromise: Promise<void> | null = null;

constructor(
Expand All @@ -65,7 +66,21 @@ class MemoryDB {
return this.initPromise;
}

private async getLanceDB(): Promise<typeof import("@lancedb/lancedb")> {
if (this.lancedb) return this.lancedb;
try {
this.lancedb = await import("@lancedb/lancedb");
return this.lancedb;
} catch (err) {
// LanceDB currently ships platform-specific native deps. Fail gracefully on unsupported platforms.
throw new Error(
`memory-lancedb: LanceDB native module unavailable on ${process.platform}/${process.arch}: ${String(err)}`,
);
}
}

private async doInitialize(): Promise<void> {
const lancedb = await this.getLanceDB();
this.db = await lancedb.connect(this.dbPath);
const tables = await this.db.tableNames();

Expand Down
1 change: 1 addition & 0 deletions hooks/logs/hooks.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"timestamp":"2026-02-07T03:11:12.846Z","level":"debug","hook":"voice-macos","event":"voice","message":"Speech completed"}
6 changes: 6 additions & 0 deletions src/channels/plugins/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export type ChannelUiMetaEntry = {
label: string;
detailLabel: string;
systemImage?: string;
description?: string;
docsPath?: string;
docsLabel?: string;
};

export type ChannelUiCatalog = {
Expand Down Expand Up @@ -242,6 +245,9 @@ export function buildChannelUiCatalog(
label: plugin.meta.label,
detailLabel,
...(plugin.meta.systemImage ? { systemImage: plugin.meta.systemImage } : {}),
...(plugin.meta.blurb ? { description: plugin.meta.blurb } : {}),
...(plugin.meta.docsPath ? { docsPath: plugin.meta.docsPath } : {}),
...(plugin.meta.docsLabel ? { docsLabel: plugin.meta.docsLabel } : {}),
};
});
const order = entries.map((entry) => entry.id);
Expand Down
22 changes: 22 additions & 0 deletions src/channels/plugins/types.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,32 @@ import type {
export type ChannelConfigUiHint = {
label?: string;
help?: string;
group?: string;
order?: number;
advanced?: boolean;
sensitive?: boolean;
placeholder?: string;
itemTemplate?: unknown;
docsPath?: string;
impacts?: Array<{
relation?: "requires" | "conflicts" | "recommends" | "risk";
targetPath?: string;
when?: "truthy" | "falsy" | "defined" | "notDefined" | "equals" | "notEquals" | "includes";
whenValue?: unknown;
targetWhen?:
| "truthy"
| "falsy"
| "defined"
| "notDefined"
| "equals"
| "notEquals"
| "includes";
targetValue?: unknown;
message: string;
fixValue?: unknown;
fixLabel?: string;
docsPath?: string;
}>;
};

export type ChannelConfigSchema = {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/gateway-cli/run-loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export async function runGatewayLoop(params: {
gatewayLog.error("shutdown timed out; exiting without full cleanup");
cleanupSignals();
params.runtime.exit(0);
}, 5000);
}, 15_000);

void (async () => {
try {
Expand Down
26 changes: 26 additions & 0 deletions src/config/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,30 @@ describe("config schema", () => {
expect(defaultsHint?.help).toContain("last");
expect(listHint?.help).toContain("bluebubbles");
});

it("adds docs and impact metadata for high-risk settings", () => {
const res = buildConfigSchema({
channels: [
{
id: "discord",
label: "Discord",
description: "Discord bot channel",
docsPath: "/channels/discord",
configSchema: { type: "object" },
},
],
});

expect(res.uiHints["gateway.mode"]?.docsPath).toBe("/web/dashboard");
expect(res.uiHints["gateway.mode"]?.impacts?.length).toBeGreaterThan(0);
expect(res.uiHints["channels.discord"]?.docsPath).toBe("/channels/discord");
expect(res.uiHints["channels.discord.actions.roles"]?.docsPath).toBe("/channels/discord");
expect(res.uiHints["channels.discord.actions.roles"]?.impacts?.[0]?.relation).toBe("requires");
expect(res.uiHints["channels.*.allowBots"]?.docsPath).toBe("/gateway/configuration");
expect(res.uiHints["channels.*.allowBots"]?.impacts?.[0]?.relation).toBe("risk");
expect(res.uiHints["channels.*.dm.policy"]?.impacts?.[0]?.targetPath).toBe(
"channels.*.dm.allowFrom",
);
expect(res.uiHints["channels.telegram.streamMode"]?.impacts?.[0]?.relation).toBe("conflicts");
});
});
Loading