Merge branch 'mp-initial-exploration' of https://github.com/BrainLogicHub/clawdbot-cell into mp-initial-exploration

This commit is contained in:
nloeff 2026-01-26 13:11:57 -08:00
commit 12f42dc39a
9 changed files with 81 additions and 5 deletions

View File

@ -3,7 +3,7 @@ name: Auto response
on: on:
issues: issues:
types: [labeled] types: [labeled]
pull_request: pull_request_target:
types: [labeled] types: [labeled]
permissions: permissions:
@ -14,9 +14,15 @@ jobs:
auto-response: auto-response:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: "2729701"
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Handle labeled items - name: Handle labeled items
uses: actions/github-script@v7 uses: actions/github-script@v7
with: with:
github-token: ${{ steps.app-token.outputs.token }}
script: | script: |
const rules = [ const rules = [
{ {

View File

@ -23,3 +23,4 @@ clawdbot onboard --mode remote --remote-url ws://gateway-host:18789
Flow notes: Flow notes:
- `quickstart`: minimal prompts, auto-generates a gateway token. - `quickstart`: minimal prompts, auto-generates a gateway token.
- `manual`: full prompts for port/bind/auth (alias of `advanced`). - `manual`: full prompts for port/bind/auth (alias of `advanced`).
- Fastest first chat: `clawdbot dashboard` (Control UI, no channel setup).

View File

@ -43,6 +43,18 @@ Start with the smallest access that still works, then widen it as you gain confi
If you run `--deep`, Clawdbot also attempts a best-effort live Gateway probe. If you run `--deep`, Clawdbot also attempts a best-effort live Gateway probe.
## Credential storage map
Use this when auditing access or deciding what to back up:
- **WhatsApp**: `~/.clawdbot/credentials/whatsapp/<accountId>/creds.json`
- **Telegram bot token**: config/env or `channels.telegram.tokenFile`
- **Discord bot token**: config/env (token file not yet supported)
- **Slack tokens**: config/env (`channels.slack.*`)
- **Pairing allowlists**: `~/.clawdbot/credentials/<channel>-allowFrom.json`
- **Model auth profiles**: `~/.clawdbot/agents/<agentId>/agent/auth-profiles.json`
- **Legacy OAuth import**: `~/.clawdbot/credentials/oauth.json`
## Security Audit Checklist ## Security Audit Checklist
When the audit prints findings, treat this as a priority order: When the audit prints findings, treat this as a priority order:

View File

@ -115,6 +115,7 @@ Use this when debugging auth or deciding what to back up:
- **Pairing allowlists**: `~/.clawdbot/credentials/<channel>-allowFrom.json` - **Pairing allowlists**: `~/.clawdbot/credentials/<channel>-allowFrom.json`
- **Model auth profiles**: `~/.clawdbot/agents/<agentId>/agent/auth-profiles.json` - **Model auth profiles**: `~/.clawdbot/agents/<agentId>/agent/auth-profiles.json`
- **Legacy OAuth import**: `~/.clawdbot/credentials/oauth.json` - **Legacy OAuth import**: `~/.clawdbot/credentials/oauth.json`
More detail: [Security](/gateway/security#credential-storage-map).
## Updating (without wrecking your setup) ## Updating (without wrecking your setup)

View File

@ -18,6 +18,9 @@ Primary entrypoint:
clawdbot onboard clawdbot onboard
``` ```
Fastest first chat: open the Control UI (no channel setup needed). Run
`clawdbot dashboard` and chat in the browser. Docs: [Dashboard](/web/dashboard).
Followup reconfiguration: Followup reconfiguration:
```bash ```bash

View File

@ -188,9 +188,9 @@ export async function ensureAgentWorkspace(params?: {
}; };
} }
async function resolveMemoryBootstrapEntries(resolvedDir: string): Promise< async function resolveMemoryBootstrapEntries(
Array<{ name: WorkspaceBootstrapFileName; filePath: string }> resolvedDir: string,
> { ): Promise<Array<{ name: WorkspaceBootstrapFileName; filePath: string }>> {
const candidates: WorkspaceBootstrapFileName[] = [ const candidates: WorkspaceBootstrapFileName[] = [
DEFAULT_MEMORY_FILENAME, DEFAULT_MEMORY_FILENAME,
DEFAULT_MEMORY_ALT_FILENAME, DEFAULT_MEMORY_ALT_FILENAME,

View File

@ -127,4 +127,30 @@ describe("handleDiscordMessageAction", () => {
}), }),
); );
}); });
it("accepts threadId for thread replies (tool compatibility)", async () => {
sendMessageDiscord.mockClear();
const handleDiscordMessageAction = await loadHandleDiscordMessageAction();
await handleDiscordMessageAction({
action: "thread-reply",
params: {
// The `message` tool uses `threadId`.
threadId: "999",
// Include a conflicting channelId to ensure threadId takes precedence.
channelId: "123",
message: "hi",
},
cfg: {} as ClawdbotConfig,
accountId: "ops",
});
expect(sendMessageDiscord).toHaveBeenCalledWith(
"channel:999",
"hi",
expect.objectContaining({
accountId: "ops",
}),
);
});
}); });

View File

@ -393,11 +393,17 @@ export async function tryHandleDiscordMessageActionGuildAdmin(params: {
}); });
const mediaUrl = readStringParam(actionParams, "media", { trim: false }); const mediaUrl = readStringParam(actionParams, "media", { trim: false });
const replyTo = readStringParam(actionParams, "replyTo"); const replyTo = readStringParam(actionParams, "replyTo");
// `message.thread-reply` (tool) uses `threadId`, while the CLI historically used `to`/`channelId`.
// Prefer `threadId` when present to avoid accidentally replying in the parent channel.
const threadId = readStringParam(actionParams, "threadId");
const channelId = threadId ?? resolveChannelId();
return await handleDiscordAction( return await handleDiscordAction(
{ {
action: "threadReply", action: "threadReply",
accountId: accountId ?? undefined, accountId: accountId ?? undefined,
channelId: resolveChannelId(), channelId,
content, content,
mediaUrl: mediaUrl ?? undefined, mediaUrl: mediaUrl ?? undefined,
replyTo: replyTo ?? undefined, replyTo: replyTo ?? undefined,

View File

@ -862,12 +862,33 @@ describe("security audit", () => {
await fs.chmod(configPath, 0o600); await fs.chmod(configPath, 0o600);
const cfg: ClawdbotConfig = { logging: { redactSensitive: "off" } }; const cfg: ClawdbotConfig = { logging: { redactSensitive: "off" } };
const user = "DESKTOP-TEST\\Tester";
const execIcacls = isWindows
? async (_cmd: string, args: string[]) => {
const target = args[0];
if (target === includePath) {
return {
stdout: `${target} NT AUTHORITY\\SYSTEM:(F)\n BUILTIN\\Users:(W)\n ${user}:(F)\n`,
stderr: "",
};
}
return {
stdout: `${target} NT AUTHORITY\\SYSTEM:(F)\n ${user}:(F)\n`,
stderr: "",
};
}
: undefined;
const res = await runSecurityAudit({ const res = await runSecurityAudit({
config: cfg, config: cfg,
includeFilesystem: true, includeFilesystem: true,
includeChannelSecurity: false, includeChannelSecurity: false,
stateDir, stateDir,
configPath, configPath,
platform: isWindows ? "win32" : undefined,
env: isWindows
? { ...process.env, USERNAME: "Tester", USERDOMAIN: "DESKTOP-TEST" }
: undefined,
execIcacls,
}); });
const expectedCheckId = isWindows const expectedCheckId = isWindows