Skip to content
Merged
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
37 changes: 26 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -443,29 +443,44 @@ jobs:
NPM_TAG="rc"
fi

RELEASE_URL="https://github.com/${GH_REPO}/releases/tag/${TAG}"
RELEASE_DOWNLOAD_BASE="https://github.com/${GH_REPO}/releases/download/${TAG}"
NPM_PACKAGE_URL="https://www.npmjs.com/package/clawmaster/v/${VERSION}"
NPM_DIST_URL="https://www.npmjs.com/package/clawmaster?activeTab=versions"

# Build direct asset URLs deterministically from the release tag.
linux_appimage_url="${RELEASE_DOWNLOAD_BASE}/ClawMaster_${VERSION}_amd64.AppImage"
linux_deb_url="${RELEASE_DOWNLOAD_BASE}/ClawMaster_${VERSION}_amd64.deb"
macos_intel_url="${RELEASE_DOWNLOAD_BASE}/ClawMaster_${VERSION}_x64.dmg"
macos_arm64_url="${RELEASE_DOWNLOAD_BASE}/ClawMaster_${VERSION}_aarch64.dmg"
windows_msi_url="${RELEASE_DOWNLOAD_BASE}/ClawMaster_${VERSION}_x64_en-US.msi"
windows_exe_url="${RELEASE_DOWNLOAD_BASE}/ClawMaster_${VERSION}_x64-setup.exe"
checksums_url="${RELEASE_DOWNLOAD_BASE}/SHA256SUMS.txt"

# Use printf instead of heredoc because YAML's `run: |` indentation
# leaks into the heredoc content — turning every heading into an
# indented code block in the rendered markdown.
{
printf '## Install\n\n'
printf '### CLI + Web Console (Recommended)\n\n'
printf '```bash\n'
printf 'npm install -g clawmaster@%s\n' "$NPM_TAG"
printf 'npm install -g clawmaster\n'
printf 'clawmaster\n'
printf '```\n\n'
printf 'Open http://localhost:16223 — the setup wizard guides you through OpenClaw engine detection and LLM provider configuration.\n\n'
printf '`clawmaster` starts the local service and opens the landing page in your browser by default.\n\n'
printf 'If the browser does not open automatically, use the backup local address: http://localhost:16223\n\n'
printf -- '- npm package: [%s](%s)\n' "clawmaster@${VERSION}" "$NPM_PACKAGE_URL"
printf -- '- all published versions: [%s](%s)\n\n' "npm versions" "$NPM_DIST_URL"
printf '> To pin this exact version: `npm install -g clawmaster@%s`\n\n' "$VERSION"
printf '### Desktop App (Beta)\n\n'
printf 'Download the installer for your platform from the Assets section below.\n\n'
printf '| Platform | Files |\n'
printf 'Direct downloads for this release. Checksums: [`SHA256SUMS.txt`](%s)\n\n' "$checksums_url"
printf '| Platform | Downloads |\n'
printf '|---|---|\n'
printf '| Linux x64 | `.AppImage`, `.deb` |\n'
printf '| macOS Intel | `.dmg` |\n'
printf '| macOS Apple Silicon | `.dmg` |\n'
printf '| Windows x64 | `.msi`, `.exe` |\n\n'
printf '> **Note:** Desktop builds are in beta. The CLI + Web Console is the recommended install method.\n\n'
printf '## Checksums\n\n'
printf 'Verify downloads with `SHA256SUMS.txt` attached to this release.\n\n'
printf '| Linux x64 | [AppImage](%s) · [deb](%s) |\n' "$linux_appimage_url" "$linux_deb_url"
printf '| macOS Intel | [dmg](%s) |\n' "$macos_intel_url"
printf '| macOS Apple Silicon | [dmg](%s) |\n' "$macos_arm64_url"
printf '| Windows x64 | [msi](%s) · [exe](%s) |\n\n' "$windows_msi_url" "$windows_exe_url"
printf '> Desktop builds are in beta. The CLI + Web Console is the recommended install method.\n\n'
printf "## What's Changed\n\n"
printf '%s\n' "$GENERATED_BODY"
} > RELEASE_NOTES.md
Expand Down
33 changes: 23 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -441,17 +441,30 @@ jobs:
await skipLink.first().click();
const skipGatewayStep = page.locator('text=网关').or(page.locator('text=Gateway'));
await skipGatewayStep.first().waitFor({ timeout: 5000 });
await page.locator('text=网关已启动').or(page.locator('text=Gateway started')).first()
.waitFor({ timeout: 10000 })
.catch(() => page.locator('text=已就绪').or(page.locator('text=Ready')).first().waitFor({ timeout: 2000 }));
const startGatewayBtn = page.locator('text=启动网关').or(page.locator('text=Start Gateway'));
const checkGatewayBtn = page.locator('text=重新检查网关').or(page.locator('text=Check Again'));
const skipEnterBtn = page.locator('text=进入管理大师').or(page.locator('text=Enter ClawMaster'));
await skipEnterBtn.first().waitFor({ timeout: 5000 });
await skipEnterBtn.first().click();
await page.waitForTimeout(2000);
const skipMainVisible = await page.locator('.app-layout, [class*="Layout"], nav').first()
.isVisible().catch(() => false);
if (!skipMainVisible) bail('Main app not visible after skip');
ok('Skip flow → main app rendered');
// Skip only needs to prove the wizard lands on the mandatory gateway step
// and offers at least one valid next action from there.
let skipNextAction = await skipEnterBtn.first().isVisible().catch(() => false);
if (!skipNextAction) {
const canStartGateway = await startGatewayBtn.first().isVisible().catch(() => false);
if (canStartGateway) {
await startGatewayBtn.first().click();
} else {
const canCheckGateway = await checkGatewayBtn.first().isVisible().catch(() => false);
if (canCheckGateway) {
await checkGatewayBtn.first().click();
}
}
await page.waitForTimeout(2000);
const enterVisible = await skipEnterBtn.first().isVisible().catch(() => false);
const startVisible = await startGatewayBtn.first().isVisible().catch(() => false);
const checkVisible = await checkGatewayBtn.first().isVisible().catch(() => false);
skipNextAction = enterVisible || startVisible || checkVisible;
}
if (!skipNextAction) bail('Skip flow reached gateway step but exposed no valid next action');
ok('Skip flow reached mandatory gateway step');

console.log(`\nAll ${step} wizard E2E checks passed`);
await browser.close();
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clawmaster",
"version": "0.3.0",
"version": "0.3.1",
"description": "龙虾管理大师——OpenClaw 生态的六边形战士",
"bin": {
"clawmaster": "bin/clawmaster.mjs"
Expand Down Expand Up @@ -37,7 +37,7 @@
"tauri:dev": "tauri dev",
"tauri:build": "tauri build",
"prepack": "npm run build:backend && npm run build",
"test:cli": "node --test bin/*.test.mjs tests/desktop/harness.unit.test.mjs",
"test:cli": "node --test bin/*.test.mjs scripts/*.test.mjs tests/desktop/harness.unit.test.mjs",
"test:plugins": "npx tsx --test plugins/memory-clawmaster-powermem/*.test.ts",
"test:desktop": "node --test tests/desktop/smoke.test.mjs",
"test:wizard-smoke": "node tests/install/wizard-install-smoke.mjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw-manager/backend",
"version": "0.3.0",
"version": "0.3.1",
"private": true,
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openclaw-manager/web",
"version": "0.3.0",
"version": "0.3.1",
"private": true,
"type": "module",
"scripts": {
Expand Down
20 changes: 3 additions & 17 deletions packages/web/src/app/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { getCommandDescriptors } from './commandRegistry'
import { getCommandShortcutLabel, isAppleClientPlatform } from './commandShortcut'
import { resolveIcon } from './iconRegistry'
import { NAV_SECTIONS, PAGE_META } from './navigationMeta'
import { BrandMark } from '@/shared/components/BrandMark'
import {
Shell,
Sun,
Moon,
Menu,
Expand Down Expand Up @@ -376,9 +376,7 @@ export default function Layout({ children }: LayoutProps) {
<>
<div className="app-sidebar-header shrink-0">
<div className="app-brand">
<div className="app-brand-mark">
<Shell className="h-4 w-4" />
</div>
<BrandMark animated className="app-brand-mark" imageClassName="h-full w-full object-contain" />
<div className="app-brand-copy">
<h1 className="app-brand-name">{t('layout.appName')}</h1>
<p className="app-brand-subtitle">{t('layout.appSub')}</p>
Expand All @@ -389,18 +387,6 @@ export default function Layout({ children }: LayoutProps) {
</button>
</div>

<div className="app-sidebar-overview">
<div className="app-sidebar-overview-card">
<p className="app-sidebar-eyebrow">{currentSection ? t(currentSection.labelKey) : t('layout.appName')}</p>
<p className="app-sidebar-summary">{pageTitle}</p>
<p className="app-sidebar-note">{pageDescription}</p>
<div className="app-sidebar-status-row">
<span className={`h-2 w-2 rounded-full ${gwStatus?.running ? 'bg-green-500' : 'bg-red-500'}`} />
<span>{gwStatus?.running ? t('layout.status.gatewayRunning') : t('layout.status.gatewayStopped')}</span>
</div>
</div>
</div>

<nav className="app-sidebar-nav">
{navSections.map((section) => {
const items = section.items
Expand Down Expand Up @@ -507,7 +493,7 @@ export default function Layout({ children }: LayoutProps) {
{t('layout.update.available', { version: updateBanner.latestVersion })}
</p>
</div>
<Link to="/settings" className="button-secondary text-xs">
<Link to="/settings#settings-update" className="button-secondary text-xs">
{t('layout.update.action')}
</Link>
<button
Expand Down
7 changes: 4 additions & 3 deletions packages/web/src/app/navigationMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export const NAV_SECTIONS: NavSectionMeta[] = [
id: 'extend',
labelKey: 'layout.section.extend',
descriptionKey: 'layout.section.extendDesc',
paths: ['/capabilities', '/skills', '/content-drafts', '/plugins', '/mcp', '/docs'],
paths: ['/capabilities', '/mcp', '/plugins', '/skills', '/ocr', '/content-drafts'],
},
{
id: 'control',
labelKey: 'layout.section.control',
descriptionKey: 'layout.section.controlDesc',
paths: ['/config', '/settings'],
paths: ['/config', '/docs', '/settings'],
},
]

Expand All @@ -47,12 +47,13 @@ export const PAGE_META: Record<string, PageMeta> = {
'/models': { sectionId: 'workspace', descriptionKey: 'layout.page.models' },
'/agents': { sectionId: 'workspace', descriptionKey: 'layout.page.agents' },
'/memory': { sectionId: 'workspace', descriptionKey: 'layout.page.memory' },
'/ocr': { sectionId: 'extend', descriptionKey: 'layout.page.ocr' },
'/capabilities': { sectionId: 'extend', descriptionKey: 'layout.page.capabilities' },
'/skills': { sectionId: 'extend', descriptionKey: 'layout.page.skills' },
'/content-drafts': { sectionId: 'extend', descriptionKey: 'layout.page.contentDrafts' },
'/plugins': { sectionId: 'extend', descriptionKey: 'layout.page.plugins' },
'/mcp': { sectionId: 'extend', descriptionKey: 'layout.page.mcp' },
'/docs': { sectionId: 'extend', descriptionKey: 'layout.page.docs' },
'/docs': { sectionId: 'control', descriptionKey: 'layout.page.docs' },
'/config': { sectionId: 'control', descriptionKey: 'layout.page.config' },
'/settings': { sectionId: 'control', descriptionKey: 'layout.page.settings' },
}
28 changes: 1 addition & 27 deletions packages/web/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -160,38 +160,12 @@
@apply flex items-center justify-between border-b border-border/80 px-4 py-4;
}

.app-sidebar-overview {
@apply border-b border-border/70 px-3 py-3;
}

.app-sidebar-overview-card {
@apply rounded-[1.35rem] border border-border/80 bg-background/70 px-3 py-3;
}

.app-sidebar-eyebrow {
@apply text-[10px] font-semibold uppercase tracking-[0.22em] text-muted-foreground;
}

.app-sidebar-summary {
font-family: var(--font-display);
@apply mt-2 text-lg font-semibold tracking-tight;
}

.app-sidebar-note {
@apply mt-1 text-xs leading-5 text-muted-foreground;
}

.app-sidebar-status-row {
@apply mt-3 inline-flex items-center gap-2 rounded-full border border-border/70 bg-card/75 px-2.5 py-1 text-[11px] font-medium text-muted-foreground;
}

.app-brand {
@apply flex items-center gap-3 min-w-0;
}

.app-brand-mark {
@apply flex h-10 w-10 items-center justify-center rounded-2xl bg-primary text-primary-foreground;
box-shadow: 0 14px 30px rgba(233, 98, 36, 0.22);
@apply flex h-14 w-14 items-center justify-center;
}

.app-brand-copy {
Expand Down
22 changes: 11 additions & 11 deletions packages/web/src/locales/main/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default {
"layout.page.memory": "Check long-term memory health, retrieval, and storage settings.",
"layout.page.capabilities": "Start from user goals, then open MCP, plugins, or skills detail pages as needed.",
"layout.page.skills": "Install workflow skills and browse curated capability bundles.",
"layout.page.contentDrafts": "Review saved draft markdown and generated images from bundled content workflows.",
"layout.page.contentDrafts": "Review saved markdown, generated images, and publishing variants from bundled content workflows.",
"layout.page.plugins": "Enable, disable, and manage OpenClaw plugins.",
"layout.page.mcp": "Review MCP servers, tools, and connector health.",
"layout.page.docs": "Search operational docs and jump to the right guide quickly.",
Expand Down Expand Up @@ -546,16 +546,16 @@ export default {
"settings.localDataStateReady": "Ready",
"settings.localDataStateDegraded": "Fallback",
"settings.localDataStateBlocked": "Blocked",
"settings.localDataEngineEmbedded": "SeekDB embedded",
"settings.localDataEngineEmbedded": "seekdb",
"settings.localDataEngineFallback": "Fallback store",
"settings.localDataEngineUnavailable": "Unavailable",
"settings.localDataReadySummary": "SeekDB embedded can run for this runtime target.",
"settings.localDataFallbackSummary": "ClawMaster will keep working through a file-backed fallback until SeekDB embedded is available.",
"settings.localDataReadySummary": "seekdb can run for this runtime target.",
"settings.localDataFallbackSummary": "ClawMaster will keep working through a file-backed fallback until this target supports seekdb.",
"settings.localDataBlockedSummary": "Local data cannot pick a safe target yet.",
"settings.localDataNoPythonHint": "This foundation uses JavaScript/TypeScript runtime paths only; no Python package or Python-based skill is required.",
"settings.localDataReasonNodeMissing": "Node.js is missing in the selected runtime. SeekDB requires Node 20 or newer, so the fallback store is selected.",
"settings.localDataReasonNodeTooOld": "The selected runtime uses Node.js below 20. Upgrade Node.js to enable SeekDB embedded where the platform supports it.",
"settings.localDataReasonUnsupportedPlatform": "SeekDB embedded bindings are not available on this target yet. Use WSL2, server mode later, or fallback storage.",
"settings.localDataReasonNodeMissing": "Node.js is missing in the selected runtime. seekdb requires Node 20 or newer, so the fallback store is selected.",
"settings.localDataReasonNodeTooOld": "The selected runtime uses Node.js below 20. Upgrade Node.js to enable seekdb where the platform supports it.",
"settings.localDataReasonUnsupportedPlatform": "seekdb bindings are not available on this target yet. Use WSL2, server mode later, or fallback storage.",
"settings.localDataReasonWslDistroMissing": "WSL2 mode is selected, but the saved distro is missing. Re-select the distro before Local Data can safely resolve a target.",
"settings.localDataRuntime": "Runtime",
"settings.localDataProfile": "Profile",
Expand All @@ -569,7 +569,7 @@ export default {
"settings.localDataRoot": "Data root",
"settings.localDataEngineRoot": "Engine root",
"settings.localDataDocuments": "Documents",
"settings.localDataDocsModule": "Docs indexed",
"settings.localDataDocsModule": "Docs index",
"settings.localDataUpdatedAt": "Updated",
"settings.localDataRebuild": "Rebuild Index",
"settings.localDataReset": "Reset Store",
Expand Down Expand Up @@ -920,7 +920,7 @@ export default {
"capability.engine": "Core Engine",
"capability.engine.desc": "OpenClaw CLI and gateway runtime. This is the base layer for every other module.",
"capability.memory": "Memory Management",
"capability.memory.desc": "Native OpenClaw memory health, search, and storage file management.",
"capability.memory.desc": "Bundled PowerMem for native OpenClaw memory health, search, and storage file management.",
"capability.observe": "Observability",
"capability.observe.desc": "clawprobe monitoring, spend tracking, and diagnostics for runtime issues.",
"capability.ocr": "Document & Image Recognition",
Expand Down Expand Up @@ -1162,9 +1162,9 @@ export default {
"nav.logs": "Logs",
"nav.settings": "Settings",
"nav.plugins": "Plugins",
"nav.contentDrafts": "Content Drafts",
"nav.contentDrafts": "Content Studio",
"contentDrafts.kicker": "Bundled skill output",
"contentDrafts.title": "Content Drafts",
"contentDrafts.title": "Content Studio",
"contentDrafts.subtitle": "Review saved markdown drafts and generated images without dropping into the workspace filesystem.",
"contentDrafts.libraryTitle": "Draft Library",
"contentDrafts.libraryBody": "Each saved variant is grouped by run id and publishing platform.",
Expand Down
Loading
Loading