Skip to content

Commit 3684038

Browse files
authored
chore(sync): sync qwen-code desktop updates (#33)
* ci(desktop): mac code-signing + App Store Connect API-key notarization (#5013) OpenWork-Sync-Mode: export Qwen-Code-Base: 2cfa32f78576d4c131b8fdc98437eaf1a090caf7 Qwen-Code-Commit: 963fc543d1d1e32b8ac246bec41bda519a550f2f OpenWork-Base: e0b7151 * docs(desktop): use main for brand builder skill (#5021) OpenWork-Sync-Mode: export Qwen-Code-Base: c491f33928ba6c63ff2ed8e743fbc698c79e75fc Qwen-Code-Commit: 3c55295f63aaba00fc4bde615c295ddd8f1400e1 OpenWork-Base: e0b7151 * perf(desktop): add --cli-only flag to skip non-CLI packages during vendor build (#5025) OpenWork-Sync-Mode: export Qwen-Code-Base: 3c55295f63aaba00fc4bde615c295ddd8f1400e1 Qwen-Code-Commit: 5121c6563ef78b9b3bad606324ffde89292a5d84 OpenWork-Base: e0b7151 * fix(desktop): isolate update feed from CLI releases (#5139) OpenWork-Sync-Mode: export Qwen-Code-Base: 57a90f7302114dc54f794f5d696b2e3314ac647e Qwen-Code-Commit: a969c84620b5e81b3e9cc8c05598c3da1b6e40a9 OpenWork-Base: e0b7151 * feat(desktop): show git branch in working directory badge (#5082) OpenWork-Sync-Mode: export Qwen-Code-Base: 99d4c1246eeb8dc1c8336b9893d6922584c3db50 Qwen-Code-Commit: a629dd0ab6af9f1d21859b61695ec72a4e85e187 OpenWork-Base: e0b7151 * chore(sync): record qwen-code desktop-v0.0.4 release (no version change) qwen-code's desktop release version bump (0.0.4) is intentionally not applied; OpenWork keeps its own release version (0.1.0). Recorded as an empty commit so future syncs skip this source commit. OpenWork-Sync-Mode: export Qwen-Code-Base: ad6368b3ae5c788264ee88c5b36574b72267a064 Qwen-Code-Commit: ee8fb8001090a3f5e6a5b10a89d913bb780cfc79 OpenWork-Base: e0b7151
1 parent e0b7151 commit 3684038

9 files changed

Lines changed: 84 additions & 36 deletions

File tree

.agents/skills/desktop-brand-builder/SKILL.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,22 @@ Use explicit user-provided override values as-is after basic validation.
6565
## Build Workflow
6666

6767
Use an isolated build directory under the current working directory so user
68-
changes in the current worktree are not mutated. Default to the qwen-code desktop branch; do not clone from
69-
`craft-agents-oss`, OpenWork, or another local checkout unless the user
70-
explicitly asks for that source:
68+
changes in the current worktree are not mutated. Default to the qwen-code main
69+
branch; do not clone from `craft-agents-oss`, OpenWork, or another local
70+
checkout unless the user explicitly asks for that source:
7171

7272
```bash
7373
BUILD_ROOT="$PWD/brand-builds/<brandId>-<timestamp>"
7474
mkdir -p "$BUILD_ROOT"
75-
git clone --branch dragon/feat-unstable-desktop-app --single-branch \
75+
git clone --branch main --single-branch \
7676
https://github.com/QwenLM/qwen-code.git \
7777
"$BUILD_ROOT/qwen-code"
7878
cd "$BUILD_ROOT/qwen-code"
79-
git checkout -B dragon/brand-<brandId> origin/dragon/feat-unstable-desktop-app
79+
git checkout -B brand-<brandId> origin/main
8080
```
8181

8282
If the branch fetch or checkout fails, stop and report the failure. Do not
83-
continue as if `dragon/brand-<brandId>` was created.
83+
continue as if `brand-<brandId>` was created.
8484

8585
Create a temporary `brand.json` in the build directory:
8686

apps/electron/scripts/build-dmg.sh

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,17 +150,15 @@ if [ -n "$APPLE_SIGNING_IDENTITY" ]; then
150150
export CSC_NAME="$CSC_NAME_CLEAN"
151151
fi
152152

153-
# Add notarization if all credentials are available
153+
# Add notarization if all credentials are available.
154+
# electron-builder (>=24) auto-notarizes via notarytool whenever APPLE_ID,
155+
# APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID are present in the env.
156+
# No `notarize:` config block or NOTARIZE flag is required (or read).
154157
if [ -n "$APPLE_ID" ] && [ -n "$APPLE_TEAM_ID" ] && [ -n "$APPLE_APP_SPECIFIC_PASSWORD" ]; then
155158
echo "Notarization enabled"
156159
export APPLE_ID="$APPLE_ID"
157160
export APPLE_TEAM_ID="$APPLE_TEAM_ID"
158161
export APPLE_APP_SPECIFIC_PASSWORD="$APPLE_APP_SPECIFIC_PASSWORD"
159-
160-
# Enable notarization in electron-builder by setting env vars
161-
# The electron-builder.yml has notarize section commented out,
162-
# but we can enable it via environment
163-
export NOTARIZE=true
164162
fi
165163

166164
# Run electron-builder

apps/electron/src/renderer/components/app-shell/input/FreeFormInput.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ChevronDown,
1212
AlertCircle,
1313
CornerDownRight,
14+
GitBranch,
1415
X,
1516
} from 'lucide-react';
1617
import { Icon_Home, Icon_Folder } from '@craft-agent/ui';
@@ -2753,15 +2754,22 @@ function WorkingDirectoryBadge({
27532754

27542755
// Fetch git branch when working directory changes
27552756
React.useEffect(() => {
2757+
let cancelled = false;
2758+
setGitBranch(null);
2759+
27562760
if (workingDirectory) {
27572761
window.electronAPI
27582762
?.getGitBranch?.(workingDirectory)
27592763
.then((branch: string | null) => {
2760-
setGitBranch(branch);
2764+
if (!cancelled) {
2765+
setGitBranch(branch);
2766+
}
27612767
});
2762-
} else {
2763-
setGitBranch(null);
27642768
}
2769+
2770+
return () => {
2771+
cancelled = true;
2772+
};
27652773
}, [workingDirectory]);
27662774

27672775
// Reset filter, refresh history, and focus input when popover opens
@@ -2833,6 +2841,7 @@ function WorkingDirectoryBadge({
28332841
const folderName = hasFolder
28342842
? getPathBasename(workingDirectory) || 'Folder'
28352843
: 'Work in Folder';
2844+
const visibleGitBranch = hasFolder ? gitBranch : null;
28362845

28372846
// Show reset option when a folder is selected and it differs from session folder
28382847
const showReset =
@@ -2854,6 +2863,21 @@ function WorkingDirectoryBadge({
28542863
<FreeFormInputContextBadge
28552864
icon={<Icon_Home className="h-4 w-4" />}
28562865
label={folderName}
2866+
ariaLabel={
2867+
visibleGitBranch
2868+
? `${folderName}, ${t('chat.onBranch', {
2869+
branch: visibleGitBranch,
2870+
})}`
2871+
: folderName
2872+
}
2873+
trailingContent={
2874+
visibleGitBranch ? (
2875+
<span className="inline-flex min-w-0 max-w-[120px] shrink items-center gap-1 text-muted-foreground">
2876+
<GitBranch className="h-3 w-3 shrink-0" />
2877+
<span className="truncate">{visibleGitBranch}</span>
2878+
</span>
2879+
) : undefined
2880+
}
28572881
isExpanded={isEmptySession}
28582882
hasSelection={hasFolder}
28592883
showChevron={true}

apps/electron/src/renderer/components/app-shell/input/FreeFormInputContextBadge.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export interface FreeFormInputContextBadgeProps {
99
icon: React.ReactNode
1010
/** Label text - shown in expanded state or collapsed with selection */
1111
label: string
12+
/** Accessible label for the full badge when visible metadata is appended */
13+
ariaLabel?: string
14+
/** Optional trailing metadata shown after the label */
15+
trailingContent?: React.ReactNode
1216
/** Whether to show expanded state (icon + label + chevron) vs collapsed */
1317
isExpanded?: boolean
1418
/** Whether there's an active selection (affects collapsed state styling and shows label) */
@@ -45,6 +49,8 @@ export const FreeFormInputContextBadge = React.forwardRef<HTMLButtonElement, Fre
4549
{
4650
icon,
4751
label,
52+
ariaLabel,
53+
trailingContent,
4854
isExpanded = false,
4955
hasSelection = false,
5056
showChevron = false,
@@ -68,7 +74,7 @@ export const FreeFormInputContextBadge = React.forwardRef<HTMLButtonElement, Fre
6874
<button
6975
ref={mergedRef as React.Ref<HTMLButtonElement>}
7076
type="button"
71-
aria-label={label}
77+
aria-label={ariaLabel ?? label}
7278
onClick={onClick}
7379
disabled={disabled}
7480
data-tutorial={dataTutorial}
@@ -107,6 +113,8 @@ export const FreeFormInputContextBadge = React.forwardRef<HTMLButtonElement, Fre
107113
)
108114
)}
109115

116+
{showLabel && trailingContent}
117+
110118
{/* Optional chevron - only in expanded state */}
111119
{isExpanded && showChevron && (
112120
<ChevronDown className="h-3 w-3 opacity-50 shrink-0" />

docs/plans/2026-06-08-desktop-auto-update-design.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ Before this change, the desktop app already had most of the runtime surface:
2323
Update source configuration belongs in `packages/shared/src/branding.ts` with the rest of desktop brand metadata. Each brand owns its release location:
2424

2525
- `openwork` uses `modelstudioai/openwork`.
26-
- `qwen-code` uses `QwenLM/qwen-code`.
26+
- `qwen-code` uses a fixed `QwenLM/qwen-code` `desktop-latest` release download URL so desktop updates do not depend on the repository-wide GitHub latest release.
2727

28-
The brand config exposes a GitHub update source with `provider`, `owner`, `repo`, and `releasePageUrl`. `scripts/electron-builder-config.ts` reads it and emits the `publish` block in `apps/electron/electron-builder.generated.yml`. Runtime code reads the same brand update source for logs and fallback release-page actions.
28+
The brand config exposes an update source plus `releasePageUrl`. GitHub sources use `provider`, `owner`, and `repo`; generic sources use `provider` and `url`. `scripts/electron-builder-config.ts` reads it and emits the `publish` block in `apps/electron/electron-builder.generated.yml`. Runtime code reads the same brand update source to decide whether packaged builds can check for updates.
2929

3030
## Release Flow
3131

32-
The existing desktop release workflow remains responsible for uploading assets to GitHub Releases. `electron-builder` should generate updater metadata, but the workflow continues to publish assets itself.
32+
The existing desktop release workflow remains responsible for uploading assets to GitHub Releases. `electron-builder` should generate updater metadata, but the workflow continues to publish assets itself. Qwen Code publishes versioned `desktop-v*` releases for history and also clobbers the fixed `desktop-latest` release used by the generic update feed.
3333

3434
Expected assets include platform installers and feed files:
3535

packages/shared/src/branding.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@
1010
// Brand config type
1111
// ---------------------------------------------------------------------------
1212

13+
type GitHubUpdateSource = {
14+
provider: 'github';
15+
owner: string;
16+
repo: string;
17+
releasePageUrl: string;
18+
};
19+
20+
type GenericUpdateSource = {
21+
provider: 'generic';
22+
url: string;
23+
releasePageUrl: string;
24+
};
25+
26+
type UpdateSource = GitHubUpdateSource | GenericUpdateSource;
27+
1328
export interface BrandConfig {
1429
/** Internal identifier */
1530
id: string;
@@ -30,12 +45,7 @@ export interface BrandConfig {
3045
/** Session viewer base URL */
3146
viewerUrl: string;
3247
/** Stable desktop auto-update source for packaged app builds. */
33-
updates?: {
34-
provider: 'github';
35-
owner: string;
36-
repo: string;
37-
releasePageUrl: string;
38-
};
48+
updates?: UpdateSource;
3949
/** Brand-owned external links shown in the Help menu */
4050
helpMenuLinks: Array<{ labelKey: string; url: string; icon: string }>;
4151
/** Brand-specific Electron resource paths, relative to apps/electron/ */
@@ -80,9 +90,8 @@ const QWEN_CODE_BRAND: BrandConfig = {
8090
selfReferName: 'Qwen Code',
8191
viewerUrl: 'https://agents.craft.do',
8292
updates: {
83-
provider: 'github',
84-
owner: 'QwenLM',
85-
repo: 'qwen-code',
93+
provider: 'generic',
94+
url: 'https://github.com/QwenLM/qwen-code/releases/download/desktop-latest',
8695
releasePageUrl: 'https://github.com/QwenLM/qwen-code/releases',
8796
},
8897
helpMenuLinks: [

scripts/build/darwin.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ export async function packageDarwin(config: BuildConfig): Promise<string> {
3232
process.env.CSC_NAME = cscName;
3333
}
3434

35-
// Add notarization if all credentials are available
35+
// Add notarization if all credentials are available.
36+
// electron-builder auto-notarizes via notarytool when APPLE_ID,
37+
// APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID are present in the env;
38+
// no `notarize:` config block or NOTARIZE flag is required (or read).
3639
if (
3740
process.env.APPLE_ID &&
3841
process.env.APPLE_TEAM_ID &&
3942
process.env.APPLE_APP_SPECIFIC_PASSWORD
4043
) {
4144
console.log(' Notarization enabled');
42-
process.env.NOTARIZE = 'true';
4345
}
4446

4547
// Run electron-builder

scripts/electron-builder-config.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,18 @@ linux.icon = BRAND.assets.linuxIcon;
5353
linux.artifactName = artifactName;
5454

5555
if (BRAND.updates) {
56-
config.publish = {
57-
provider: BRAND.updates.provider,
58-
owner: BRAND.updates.owner,
59-
repo: BRAND.updates.repo,
60-
};
56+
if (BRAND.updates.provider === 'github') {
57+
config.publish = {
58+
provider: BRAND.updates.provider,
59+
owner: BRAND.updates.owner,
60+
repo: BRAND.updates.repo,
61+
};
62+
} else {
63+
config.publish = {
64+
provider: BRAND.updates.provider,
65+
url: BRAND.updates.url,
66+
};
67+
}
6168
} else {
6269
delete config.publish;
6370
}

scripts/vendor-qwen-code.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ async function vendorLocalCheckout(repoRoot: string): Promise<void> {
102102
console.log(`Building Qwen Code CLI from ${repoRoot}...`);
103103

104104
const npm = npmCommand();
105-
await run([npm, 'run', 'build'], repoRoot);
105+
await run([npm, 'run', 'build', '--', '--cli-only'], repoRoot);
106106
await run([npm, 'run', 'bundle'], repoRoot);
107107
await run([npm, 'run', 'prepare:package'], repoRoot);
108108

0 commit comments

Comments
 (0)