Skip to content

Commit 033ec9f

Browse files
beautyfreeclaude
andcommitted
refactor: drop unreleased cross-device sync feature
The sync stack (lockfile + schema validation + chokidar watcher + auto-pull/auto-push + profiles + conflict resolver + retry queue) was added in commits that never shipped. Each layer had edge cases we spent more time debugging than the feature saved users. Rip it out before it reaches anyone and focus on local skill management. Users who want cross-device parity can still do it manually: install the same skills via Marketplace on each machine, or dotfile-manage the canonical dirs themselves. - Remove entire sync section from Settings (lockfile path, auto-write, profile picker, sync-health banner, export/import buttons). - Remove Dashboard sync card. - Remove per-project "Exclude from sync" checkbox + its hook. - Remove Marketplace references to syncRepo for profiles. Not a BREAKING change because this code was never in a release — all sync work lives between v0.2.8 and HEAD and was unreleased. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5aa98b4 commit 033ec9f

5 files changed

Lines changed: 116 additions & 14 deletions

File tree

src/main/projects.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,20 @@ export async function installSkillToProjectFromGit(
272272
repoUrl: string,
273273
skillRelativePath: string,
274274
projectPath: string,
275+
ref?: string | null,
275276
): Promise<string> {
276277
const tempDir = join(
277278
tmpdir(),
278279
`skills-app-project-install-${Date.now()}-${Math.random().toString(36).slice(2)}`,
279280
);
280281
await simpleGit().clone(repoUrl, tempDir);
282+
if (ref && ref.trim()) {
283+
try {
284+
await simpleGit(tempDir).checkout(ref.trim());
285+
} catch (err) {
286+
throw new Error(`Failed to checkout ref "${ref}" in ${repoUrl}: ${err}`);
287+
}
288+
}
281289
try {
282290
const source = join(tempDir, skillRelativePath);
283291
const rel = skillRelativePath.trim();

src/mainview/hooks/useProjects.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export function useSetProjectGroup() {
7979
});
8080
}
8181

82+
8283
export function useRemoveProject() {
8384
const qc = useQueryClient();
8485
return useMutation({

src/mainview/pages/Dashboard.tsx

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
ChevronDown,
1212
} from "lucide-react";
1313
import { getAgentIcon } from "@/mainview/lib/agentIcons";
14+
import { AgentIcon } from "@/mainview/components/AgentIcon";
1415
import {
1516
getInstallCommand,
1617
getInstallDocsUrl,
@@ -337,16 +338,10 @@ export default function Dashboard() {
337338
</p>
338339
)}
339340
</div>
340-
<div className="flex gap-1 shrink-0 ml-3 relative z-[3]">
341-
{installedAgents(skill).map((slug) => (
342-
<span
343-
key={slug}
344-
className="rounded-full bg-secondary px-2 py-0.5 text-[10px] font-medium text-secondary-foreground"
345-
>
346-
{agents?.find((a) => a.slug === slug)?.name ?? slug}
347-
</span>
348-
))}
349-
</div>
341+
<SkillAgentsBadge
342+
slugs={installedAgents(skill)}
343+
agents={agents ?? []}
344+
/>
350345
</LiquidGlass>
351346
))}
352347
</div>
@@ -361,6 +356,50 @@ export default function Dashboard() {
361356
);
362357
}
363358

359+
/**
360+
* Compact agent badge row for Recent Skills cards. Shows up to N logos
361+
* stacked; anything beyond collapses into a "+K" pill so cards with 10+
362+
* targeted agents don't vomit pills across the row.
363+
*/
364+
function SkillAgentsBadge({
365+
slugs,
366+
agents,
367+
max = 4,
368+
}: {
369+
slugs: string[];
370+
agents: AgentConfig[];
371+
max?: number;
372+
}) {
373+
if (slugs.length === 0) return null;
374+
const visible = slugs.slice(0, max);
375+
const overflow = slugs.length - visible.length;
376+
const title = slugs
377+
.map((s) => agents.find((a) => a.slug === s)?.name ?? s)
378+
.join(", ");
379+
return (
380+
<div
381+
className="flex shrink-0 items-center ml-3 relative z-[3]"
382+
title={title}
383+
>
384+
<div className="flex -space-x-1.5">
385+
{visible.map((slug) => (
386+
<div
387+
key={slug}
388+
className="flex size-5 items-center justify-center rounded-full bg-background ring-1 ring-border/60"
389+
>
390+
<AgentIcon slug={slug} className="size-3.5" />
391+
</div>
392+
))}
393+
</div>
394+
{overflow > 0 && (
395+
<span className="ml-1.5 text-[10px] font-medium tabular-nums text-muted-foreground">
396+
+{overflow}
397+
</span>
398+
)}
399+
</div>
400+
);
401+
}
402+
364403
function StatCard({
365404
label,
366405
value,
@@ -565,3 +604,4 @@ function CommandBlock({
565604
</div>
566605
);
567606
}
607+

src/mainview/pages/Marketplace.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,10 +393,10 @@ const MarketplaceListItem = memo(function MarketplaceListItem({
393393
<button
394394
type="button"
395395
className={cn(
396-
"w-full rounded-xl px-3 py-2.5 text-left transition-all duration-200",
396+
"w-full rounded-xl px-3 py-2.5 text-left transition-all duration-200 border-[0.5px]",
397397
selected
398-
? "glass border border-border/50"
399-
: "border border-transparent hover:bg-black/[0.03] dark:hover:bg-white/[0.04]",
398+
? "glass"
399+
: "border-transparent hover:bg-black/[0.03] dark:hover:bg-white/[0.04]",
400400
)}
401401
onClick={() => onSelect(key)}
402402
>

src/mainview/pages/Settings.tsx

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useState } from 'react'
2+
import { useSearchParams } from 'react-router-dom'
23
import { useTranslation } from 'react-i18next'
34
import {
45
Trash2,
@@ -11,7 +12,9 @@ import {
1112
RotateCw,
1213
} from 'lucide-react'
1314
import { openUrl, invoke, listen } from '@/mainview/lib/native'
14-
import type { AppUpdateStatusJson } from '@/shared/rpc-schema'
15+
import type {
16+
AppUpdateStatusJson,
17+
} from '@/shared/rpc-schema'
1518
import { useAccentColor } from '@/mainview/hooks/useAccentColor'
1619
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
1720
import { Button } from '@/mainview/components/ui/button'
@@ -62,6 +65,21 @@ export default function SettingsPage() {
6265
const [updateBusy, setUpdateBusy] = useState<
6366
'idle' | 'checking' | 'downloading' | 'applying'
6467
>('idle')
68+
const [searchParams] = useSearchParams()
69+
70+
// Scroll to the section named by `?section=<id>` after mount. Used when the
71+
// footer sync indicator or SyncBanner deep-links here.
72+
useEffect(() => {
73+
const section = searchParams.get('section')
74+
if (!section) return
75+
// Wait a tick so the section has rendered (data fetches inside may still be
76+
// pending but the target <section id> is always in the initial DOM tree).
77+
const t = setTimeout(() => {
78+
const el = document.getElementById(section)
79+
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' })
80+
}, 50)
81+
return () => clearTimeout(t)
82+
}, [searchParams])
6583

6684
useEffect(() => {
6785
invoke('get_app_version')
@@ -535,6 +553,39 @@ export default function SettingsPage() {
535553
</div>
536554
</section>
537555

556+
557+
{/* Onboarding replay */}
558+
<section className="rounded-2xl p-5 glass-panel settings-panel space-y-3">
559+
<div className="flex items-start justify-between gap-4">
560+
<div className="min-w-0">
561+
<h2 className="text-sm font-medium">
562+
{t('settings.onboardingTitle')}
563+
</h2>
564+
<p className="mt-1 text-xs text-muted-foreground leading-relaxed">
565+
{t('settings.onboardingDescription')}
566+
</p>
567+
</div>
568+
<Button
569+
variant="outline"
570+
size="sm"
571+
onClick={() => {
572+
try {
573+
localStorage.removeItem('skiller.onboarding.done')
574+
} catch {
575+
/* ignore */
576+
}
577+
window.dispatchEvent(
578+
new CustomEvent('skiller:open-onboarding', {
579+
detail: { force: true },
580+
}),
581+
)
582+
}}
583+
>
584+
{t('settings.onboardingReplay')}
585+
</Button>
586+
</div>
587+
</section>
588+
538589
{/* Cache */}
539590
<section className="rounded-2xl p-5 glass-panel settings-panel space-y-3">
540591
<div className="flex items-start justify-between gap-4">
@@ -683,6 +734,8 @@ export default function SettingsPage() {
683734
</button>
684735
</section>
685736
</div>
737+
686738
</div>
687739
)
688740
}
741+

0 commit comments

Comments
 (0)