Skip to content

Commit 218cf02

Browse files
committed
修复部分错误
1 parent 3cf7f4d commit 218cf02

30 files changed

Lines changed: 2096 additions & 484 deletions

.claude/settings.local.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
"permissions": {
33
"allow": [
44
"Bash(rm:*)",
5-
"Bash(npx tsc:*)"
5+
"Bash(npx tsc:*)",
6+
"Bash(dir:*)",
7+
"Bash(python:*)"
68
]
79
}
810
}

OneCode.sln.DotSettings.user

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAsyncIteratorMethodBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F24f5857a073841e189d805de9660178ef49910_003Ff2_003Feee2f66b_003FAsyncIteratorMethodBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
3+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACancellationToken_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F24f5857a073841e189d805de9660178ef49910_003F8c_003Fff5638be_003FCancellationToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
24
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultHttpContext_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F854af49af9074fb0805c02bd3e8a575d49910_003F9c_003F7edc0466_003FDefaultHttpContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
3-
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APtyExitedEventArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ff8a1ef1b052f4919822425486707a5e99a00_003F2a_003Fc030d7ae_003FPtyExitedEventArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
5+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AManualResetValueTaskSourceCore_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F24f5857a073841e189d805de9660178ef49910_003F3c_003F233fa7b9_003FManualResetValueTaskSourceCore_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
6+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003APtyExitedEventArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ff8a1ef1b052f4919822425486707a5e99a00_003F2a_003Fc030d7ae_003FPtyExitedEventArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
7+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AValueTask_00601_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F24f5857a073841e189d805de9660178ef49910_003F3c_003F538a0f82_003FValueTask_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

docs/skill-registry-spec.zh-CN.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# OneCode 技能市场与注册表方案(简化版优先)
2+
3+
## 0. 简化版优先级(当前阶段)
4+
- 以 GitHub API 读取本仓库 `skills/` 目录与统一 `skills/index.json` 作为唯一数据源。
5+
- 不建设独立 API 服务,OneCode 直接对接 GitHub API。
6+
- OneCode 内置 UI 提供远端浏览与本地安装管理(覆盖 Codex 与 ClaudeCode)。
7+
- 无人工审核,发布即生效;以风险提示与下架标记治理。
8+
9+
## 1. 目标与原则
10+
- 面向公开社区与企业用户,统一技能分发入口。
11+
- 不涉及商业化与付费流程。
12+
- 完全兼容 `SKILL.md`,不要求新增强制文件。
13+
- 使用 GitHub API 获取索引与 `SKILL.md` 内容。
14+
- OneCode 内置 UI 完成搜索、下载与覆盖安装。
15+
16+
## 2. 范围与非目标
17+
范围包含:
18+
- 本仓库 `skills/` 目录与统一 JSON 索引。
19+
- OneCode UI 的市场浏览与本地技能管理。
20+
- GitHub 贡献流程(PR/Release)作为发布方式。
21+
- 风险提示、举报与下架标记。
22+
23+
非目标:
24+
- 独立 Registry 服务与自建账号体系。
25+
- 付费或订阅体系。
26+
- 人工审核与内容审批。
27+
- ClaudeCode 官方安装逻辑的集成方案。
28+
29+
## 3. 数据源与目录结构(GitHub)
30+
- 根目录新增 `skills/` 目录作为配置入口。
31+
- 统一索引文件:`skills/index.json`
32+
- 推荐目录结构:`skills/{owner}/{skill}/`,避免重名冲突。
33+
- `SKILL.md` 与安装包文件必须位于本仓库 `skills/{owner}/{skill}/` 下。
34+
35+
建议的索引字段(示意):
36+
```json
37+
{
38+
"version": 1,
39+
"generatedAt": "2026-01-07",
40+
"skills": [
41+
{
42+
"slug": "owner/skill",
43+
"name": "Skill Name",
44+
"summary": "Short description",
45+
"visibility": "public",
46+
"tags": ["cli", "productivity"],
47+
"services": {
48+
"codex": { "compatible": true },
49+
"claudecode": { "compatible": true }
50+
},
51+
"skillMd": {
52+
"path": "skills/owner/skill/SKILL.md"
53+
},
54+
"package": {
55+
"path": "skills/owner/skill/skill.zip",
56+
"sha256": "..."
57+
},
58+
"version": "1.2.0",
59+
"buildId": "20260107.1",
60+
"status": "active",
61+
"updatedAt": "2026-01-07T10:00:00Z"
62+
}
63+
]
64+
}
65+
```
66+
67+
## 4. 可见性与访问规则
68+
- public:可搜索、可浏览、可安装(含未登录用户)。
69+
- org:仅组织成员可见与安装,不进入公共搜索。
70+
- unlisted:仅发布者中心可见;不可搜索、不可访问、不可安装。
71+
72+
说明:unlisted 不进入公共索引;org 技能建议通过组织私有索引或私有仓库提供。
73+
74+
## 5. 发布与版本策略(GitHub 贡献)
75+
- 发布通过更新 `skills/index.json` 与对应文件完成。
76+
- 允许覆盖同版本;保留 `buildId` 与更新时间。
77+
- 版本状态:`active``yanked`(下架,不可安装但保留历史)。
78+
- 版本页需提示“此版本已更新”并显示更新时间。
79+
80+
## 6. OneCode 安装体验(简化版)
81+
- 市场内搜索/浏览 -> 详情页 -> 选择版本 -> 安装。
82+
- 同名技能直接覆盖安装;安装失败则回滚或保留旧版本。
83+
- 安装前展示风险提示标签(不阻塞)。
84+
- 本地记录来源、版本、构建指纹与安装时间。
85+
- 更新提示包含两类:新版本与同版本更新。
86+
- 支持从本地 zip/tar 导入技能包。
87+
- 必须支持离线安装(仅依赖本地导入包)。
88+
89+
## 7. 内容展示与发现
90+
- 详情页主体渲染 `SKILL.md` 内容。
91+
- 可选解析 front matter 作为标题、标签、兼容性信息。
92+
- 发现渠道仅对 public 开放:搜索、分类、趋势、最近更新。
93+
- org 技能仅在组织内可见;unlisted 不出现。
94+
95+
## 8. 组织与企业能力
96+
- 组织以 GitHub Organization 为准,成员关系以 GitHub 为准。
97+
- 组织成员可见 org 技能;发布权限由 GitHub 权限控制。
98+
- 组织邀请可通过 GitHub 的邮件邀请完成。
99+
- 组织主页展示 public 与 org 技能。
100+
101+
## 9. 风险提示与治理
102+
- 自动扫描生成风险提示(外联、脚本执行等)。
103+
- 举报入口可触发风险标识与下架流程。
104+
- 可信标识:GitHub 认证发布者、组织验证。
105+
- 无人工审核,不阻塞发布。
106+
107+
## 10. 统计与隐私
108+
- 全局统计以 GitHub 可用指标为准(如 release 下载量)。
109+
- 本地安装统计仅保存在客户端,不上传个人敏感信息。
110+
111+
## 11. 关键用户旅程
112+
- 未登录用户:搜索 public -> 安装 -> 使用。
113+
- 发布者:通过 GitHub 提交更新 -> 版本上线。
114+
- 组织:成员加入 -> 浏览 org 技能 -> 安装与更新。
115+
116+
## 12. 字段校验规则(简化版)
117+
- `skills/index.json` 必填:`version`(整数)、`generatedAt`(日期或时间)、`skills`(数组)。
118+
- `slug` 需符合 `owner/skill` 形式,建议只允许字母、数字、`-``_``.`
119+
- `visibility` 取值限定为 `public``org``unlisted`
120+
- `skillMd.path` 必填,且必须位于 `skills/{owner}/{skill}/SKILL.md`
121+
- `package.path` 必填,且必须位于 `skills/{owner}/{skill}/`,仅允许 `zip``tar.gz`
122+
- `package.sha256` 必填,用于安装前校验。
123+
- `version` 必填,建议语义化;`buildId``updatedAt` 必填。
124+
- `status` 取值限定为 `active``yanked`
125+
126+
## 13. 同版本覆盖策略细则
127+
- 允许覆盖同版本,但必须更新 `buildId``updatedAt`
128+
- 覆盖同版本时需更新 `package.sha256`,并提示“此版本已更新”。
129+
- 客户端若检测 `version` 相同但 `buildId` 不同,视为“同版本更新”。
130+
- `yanked` 版本不可安装;若恢复为 `active`,需更新 `buildId``updatedAt`
131+
132+
## 14. UI 字段清单(简化版)
133+
- 列表:名称、简介、标签、可见性、兼容服务(Codex/ClaudeCode)、版本、更新时间、状态。
134+
- 详情:`SKILL.md` 渲染、版本列表、`buildId`、更新时间、风险提示、安装按钮。
135+
- 已安装信息:来源(Codex/ClaudeCode)、已装版本与 `buildId`、安装时间、是否有更新。
136+
- 导入入口:本地压缩包导入与离线安装提示。
137+
138+
## 15. `skills/index.json` 最小示例
139+
```json
140+
{
141+
"version": 1,
142+
"generatedAt": "2026-01-07",
143+
"skills": [
144+
{
145+
"slug": "onecode/hello-skill",
146+
"name": "Hello Skill",
147+
"summary": "A minimal example skill",
148+
"visibility": "public",
149+
"tags": ["example"],
150+
"services": {
151+
"codex": { "compatible": true },
152+
"claudecode": { "compatible": true }
153+
},
154+
"skillMd": {
155+
"path": "skills/onecode/hello-skill/SKILL.md"
156+
},
157+
"package": {
158+
"path": "skills/onecode/hello-skill/skill.zip",
159+
"sha256": "REPLACE_WITH_SHA256"
160+
},
161+
"version": "1.0.0",
162+
"buildId": "20260107.1",
163+
"status": "active",
164+
"updatedAt": "2026-01-07T10:00:00Z"
165+
}
166+
]
167+
}
168+
```
169+
170+
## 16. 目录树样例(本仓库)
171+
```
172+
skills/
173+
index.json
174+
onecode/
175+
hello-skill/
176+
SKILL.md
177+
skill.zip
178+
```
179+
180+
## 17. OneCode 本地技能管理交互与状态流转
181+
交互流程(简化版):
182+
- 入口:OneCode -> Skills。
183+
- 顶部过滤:All / Codex / ClaudeCode。
184+
- 列表页:显示本地已安装与远端可安装技能。
185+
- 详情页:渲染 `SKILL.md`,提供安装/覆盖/卸载/导入。
186+
- 导入:选择本地 zip/tar -> 校验 `sha256`(如可用)-> 解压 -> 覆盖安装。
187+
188+
状态流转(简化版):
189+
- NotInstalled -> Installed(安装或导入成功)。
190+
- Installed -> UpdateAvailable(检测到新版本或同版本更新)。
191+
- UpdateAvailable -> Installed(更新完成)。
192+
- Installed -> NotInstalled(卸载成功)。
193+
- Installed -> InstallFailed(校验或解压失败,保留旧版本)。

skills/index.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"version": 1,
3+
"generatedAt": "2026-01-07",
4+
"skills": []
5+
}

src/OneCode.Win/FloatingBallForm.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,18 @@ private async Task StopAppAsync()
124124
return;
125125
}
126126

127-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
128-
await app.StopAsync(cts.Token);
127+
// 使用 Task.WhenAny 来避免卡死,如果超时就强制结束
128+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
129+
var stopTask = app.StopAsync(cts.Token);
130+
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(3));
131+
132+
var completedTask = await Task.WhenAny(stopTask, timeoutTask);
133+
134+
if (completedTask == timeoutTask)
135+
{
136+
// 超时则直接 Dispose 不等待 StopAsync 完成
137+
}
138+
129139
await app.DisposeAsync();
130140
app = null;
131141
isRunning = false;
@@ -143,14 +153,28 @@ private async Task StopAppAsync()
143153

144154
private async Task ShutdownAsync()
145155
{
156+
// 先停止应用(如果正在运行)
146157
if (isRunning)
147158
{
148159
try
149160
{
150-
await StopAppAsync();
161+
// 直接执行停止逻辑,不经过 StopAppAsync 的状态检查
162+
// 因为此时我们无论如何都要关闭
163+
if (app != null)
164+
{
165+
// 快速停止,不等待优雅关闭
166+
var stopTask = app.StopAsync();
167+
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2));
168+
await Task.WhenAny(stopTask, timeoutTask);
169+
170+
await app.DisposeAsync();
171+
app = null;
172+
}
173+
isRunning = false;
151174
}
152175
catch
153176
{
177+
// 忽略错误,确保退出流程继续
154178
}
155179
}
156180

web/src/App.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { AboutSection } from '@/pages/settings/AboutSection'
1717
import { api } from '@/api/client'
1818
import { ThemeTogglerButton } from '@animate-ui/components-buttons-theme-toggler'
1919
import { Database, Settings } from 'lucide-react'
20+
import { LogoBubble } from '@/components/LogoBubble'
2021

2122
function MaskIcon({ src, className }: { src: string; className?: string }) {
2223
return (
@@ -145,6 +146,7 @@ export default function App() {
145146
<div className="h-screen overflow-hidden bg-background text-foreground">
146147
<div className="flex h-full w-full">
147148
<aside className="flex w-16 shrink-0 flex-col items-center border-r bg-card px-2 py-4">
149+
<LogoBubble />
148150
<nav className="flex flex-col items-center gap-2">
149151
<NavIconLink
150152
to="/code"
@@ -194,7 +196,7 @@ export default function App() {
194196
<Route path="/code" element={<CodePage />} />
195197
<Route path="/node" element={<NodeInstallPage />} />
196198
<Route path="/codex" element={<ToolPage tool="codex" title="Codex" />} />
197-
<Route path="/claude" element={<CodePage mode="claude" />} />
199+
<Route path="/claude" element={<CodePage />} />
198200
<Route
199201
path="/claude/tool"
200202
element={

0 commit comments

Comments
 (0)