ccnew 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +107 -0
  2. package/build/icon.ico +0 -0
  3. package/build/icon.png +0 -0
  4. package/core/apply.js +152 -0
  5. package/core/backup.js +53 -0
  6. package/core/constants.js +78 -0
  7. package/core/desktop-service.js +403 -0
  8. package/core/desktop-state.js +1021 -0
  9. package/core/index.js +1468 -0
  10. package/core/paths.js +99 -0
  11. package/core/presets.js +171 -0
  12. package/core/probe.js +70 -0
  13. package/core/routing.js +334 -0
  14. package/core/store.js +218 -0
  15. package/core/utils.js +225 -0
  16. package/core/writers/codex.js +102 -0
  17. package/core/writers/index.js +16 -0
  18. package/core/writers/openclaw.js +93 -0
  19. package/core/writers/opencode.js +91 -0
  20. package/desktop/assets/fml-icon.png +0 -0
  21. package/desktop/assets/march-mark.svg +26 -0
  22. package/desktop/main.js +275 -0
  23. package/desktop/preload.cjs +67 -0
  24. package/desktop/preload.js +49 -0
  25. package/desktop/renderer/app.js +327 -0
  26. package/desktop/renderer/index.html +130 -0
  27. package/desktop/renderer/styles.css +490 -0
  28. package/package.json +111 -0
  29. package/scripts/build-web.mjs +95 -0
  30. package/scripts/desktop-dev.mjs +90 -0
  31. package/scripts/desktop-pack-win.mjs +81 -0
  32. package/scripts/postinstall.mjs +49 -0
  33. package/scripts/prepublish-check.mjs +57 -0
  34. package/scripts/serve-site.mjs +51 -0
  35. package/site/app.js +10 -0
  36. package/site/assets/fml-icon.png +0 -0
  37. package/site/assets/march-mark.svg +26 -0
  38. package/site/index.html +337 -0
  39. package/site/styles.css +840 -0
  40. package/src/App.tsx +1557 -0
  41. package/src/components/layout/app-sidebar.tsx +103 -0
  42. package/src/components/layout/top-toolbar.tsx +44 -0
  43. package/src/components/layout/workspace-tabs.tsx +32 -0
  44. package/src/components/providers/inspector-panel.tsx +84 -0
  45. package/src/components/providers/metric-strip.tsx +26 -0
  46. package/src/components/providers/provider-editor.tsx +87 -0
  47. package/src/components/providers/provider-table.tsx +85 -0
  48. package/src/components/ui/logo-mark.tsx +32 -0
  49. package/src/features/mcp/mcp-view.tsx +45 -0
  50. package/src/features/prompts/prompts-view.tsx +40 -0
  51. package/src/features/providers/providers-view.tsx +40 -0
  52. package/src/features/providers/types.ts +26 -0
  53. package/src/features/skills/skills-view.tsx +44 -0
  54. package/src/hooks/use-control-workspace.ts +235 -0
  55. package/src/index.css +22 -0
  56. package/src/lib/client.ts +726 -0
  57. package/src/lib/query-client.ts +3 -0
  58. package/src/lib/workspace-sections.ts +34 -0
  59. package/src/main.tsx +14 -0
  60. package/src/types.ts +137 -0
  61. package/src/vite-env.d.ts +64 -0
  62. package/src-tauri/README.md +11 -0
@@ -0,0 +1,44 @@
1
+ const skills = [
2
+ { name: "openai-docs", category: "System", status: "Installed" },
3
+ { name: "plugin-creator", category: "System", status: "Installed" },
4
+ { name: "skill-installer", category: "System", status: "Installed" },
5
+ { name: "xianyu-keyword-research", category: "Business", status: "Installed" }
6
+ ];
7
+
8
+ export function SkillsView() {
9
+ return (
10
+ <section className="mt-4 grid min-h-0 flex-1 grid-cols-[1fr_1fr] gap-4">
11
+ <article className="rounded-[24px] border border-white/6 bg-white/[0.025] p-5">
12
+ <div className="text-[11px] uppercase tracking-[0.32em] text-slate-500">Skill Registry</div>
13
+ <h2 className="mt-2 font-['Space_Grotesk'] text-[22px] font-bold tracking-[-0.04em] text-slate-50">
14
+ Installed skills
15
+ </h2>
16
+ <div className="mt-5 space-y-3">
17
+ {skills.map((item) => (
18
+ <div key={item.name} className="flex items-center justify-between rounded-[20px] border border-white/6 bg-white/[0.03] px-4 py-4">
19
+ <div>
20
+ <div className="text-sm font-medium text-slate-100">{item.name}</div>
21
+ <div className="mt-1 text-xs text-slate-500">{item.category}</div>
22
+ </div>
23
+ <div className="rounded-full bg-cyan-400/12 px-2.5 py-1 text-[11px] text-cyan-200">{item.status}</div>
24
+ </div>
25
+ ))}
26
+ </div>
27
+ </article>
28
+
29
+ <article className="rounded-[24px] border border-white/6 bg-white/[0.025] p-5">
30
+ <div className="text-[11px] uppercase tracking-[0.32em] text-slate-500">Skill Runtime</div>
31
+ <h2 className="mt-2 font-['Space_Grotesk'] text-[22px] font-bold tracking-[-0.04em] text-slate-50">
32
+ Load behavior
33
+ </h2>
34
+ <div className="mt-5 space-y-3">
35
+ {["Trigger rules", "Skill path resolution", "Progressive disclosure", "Context hygiene"].map((item) => (
36
+ <div key={item} className="rounded-[18px] border border-white/6 bg-white/[0.03] px-4 py-3 text-sm text-slate-300">
37
+ {item}
38
+ </div>
39
+ ))}
40
+ </div>
41
+ </article>
42
+ </section>
43
+ );
44
+ }
@@ -0,0 +1,235 @@
1
+ import { useEffect, useMemo, useState } from "react";
2
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
+ import { client } from "../lib/client";
4
+ import { workspaceSections, type WorkspaceSectionId } from "../lib/workspace-sections";
5
+ import type { PlatformId, Provider } from "../types";
6
+
7
+ export function useControlWorkspace() {
8
+ const queryClient = useQueryClient();
9
+ const [activePlatform, setActivePlatform] = useState<PlatformId>("codex");
10
+ const [activeSection, setActiveSection] = useState<WorkspaceSectionId>("providers");
11
+ const [editorForm, setEditorForm] = useState({
12
+ name: "fhl",
13
+ baseUrl: "https://www.fhl.mom",
14
+ apiKey: "",
15
+ model: "gpt-5.4"
16
+ });
17
+
18
+ const snapshotQuery = useQuery({
19
+ queryKey: ["snapshot"],
20
+ queryFn: client.getSnapshot
21
+ });
22
+
23
+ const probeQuery = useQuery({
24
+ queryKey: ["probe", activePlatform],
25
+ queryFn: () => client.probePlatform(activePlatform),
26
+ enabled: false
27
+ });
28
+
29
+ useEffect(() => {
30
+ if (probeQuery.data?.snapshot) {
31
+ queryClient.setQueryData(["snapshot"], probeQuery.data.snapshot);
32
+ }
33
+ }, [probeQuery.data, queryClient]);
34
+
35
+ const saveMutation = useMutation({
36
+ mutationFn: client.saveProvider,
37
+ onSuccess: (data) => {
38
+ queryClient.setQueryData(["snapshot"], data);
39
+ setEditorForm((current) => ({ ...current, apiKey: "" }));
40
+ }
41
+ });
42
+
43
+ const activateMutation = useMutation({
44
+ mutationFn: client.activateProvider,
45
+ onSuccess: (data) => {
46
+ queryClient.setQueryData(["snapshot"], data);
47
+ }
48
+ });
49
+
50
+ const probeCandidateMutation = useMutation({
51
+ mutationFn: client.probeCandidate
52
+ });
53
+
54
+ const openPathMutation = useMutation({
55
+ mutationFn: client.openPath
56
+ });
57
+
58
+ const toggleMcpMutation = useMutation({
59
+ mutationFn: client.toggleMcpServer,
60
+ onSuccess: (data) => {
61
+ queryClient.setQueryData(["snapshot"], data);
62
+ }
63
+ });
64
+
65
+ const upsertMcpMutation = useMutation({
66
+ mutationFn: client.upsertMcp,
67
+ onSuccess: (data) => {
68
+ queryClient.setQueryData(["snapshot"], data);
69
+ }
70
+ });
71
+
72
+ const deleteMcpMutation = useMutation({
73
+ mutationFn: client.deleteMcp,
74
+ onSuccess: (data) => {
75
+ queryClient.setQueryData(["snapshot"], data);
76
+ }
77
+ });
78
+
79
+ const togglePromptMutation = useMutation({
80
+ mutationFn: client.togglePrompt,
81
+ onSuccess: (data) => {
82
+ queryClient.setQueryData(["snapshot"], data);
83
+ }
84
+ });
85
+
86
+ const upsertPromptMutation = useMutation({
87
+ mutationFn: client.upsertPrompt,
88
+ onSuccess: (data) => {
89
+ queryClient.setQueryData(["snapshot"], data);
90
+ }
91
+ });
92
+
93
+ const deletePromptMutation = useMutation({
94
+ mutationFn: client.deletePrompt,
95
+ onSuccess: (data) => {
96
+ queryClient.setQueryData(["snapshot"], data);
97
+ }
98
+ });
99
+
100
+ const upsertSkillMutation = useMutation({
101
+ mutationFn: client.upsertSkill,
102
+ onSuccess: (data) => {
103
+ queryClient.setQueryData(["snapshot"], data);
104
+ }
105
+ });
106
+
107
+ const deleteSkillMutation = useMutation({
108
+ mutationFn: client.deleteSkill,
109
+ onSuccess: (data) => {
110
+ queryClient.setQueryData(["snapshot"], data);
111
+ }
112
+ });
113
+
114
+ const toggleSkillRepoMutation = useMutation({
115
+ mutationFn: client.toggleSkillRepo,
116
+ onSuccess: (data) => {
117
+ queryClient.setQueryData(["snapshot"], data);
118
+ }
119
+ });
120
+
121
+ const savePresetMutation = useMutation({
122
+ mutationFn: client.savePreset,
123
+ onSuccess: (data) => {
124
+ queryClient.setQueryData(["snapshot"], data);
125
+ }
126
+ });
127
+
128
+ const deletePresetMutation = useMutation({
129
+ mutationFn: client.deletePreset,
130
+ onSuccess: (data) => {
131
+ queryClient.setQueryData(["snapshot"], data);
132
+ }
133
+ });
134
+
135
+ const applyPresetMutation = useMutation({
136
+ mutationFn: client.applyPreset,
137
+ onSuccess: (data) => {
138
+ queryClient.setQueryData(["snapshot"], data);
139
+ }
140
+ });
141
+
142
+ const importPresetsMutation = useMutation({
143
+ mutationFn: client.importPresets,
144
+ onSuccess: () => {
145
+ queryClient.invalidateQueries({ queryKey: ["snapshot"] });
146
+ }
147
+ });
148
+
149
+ const exportPresetsMutation = useMutation({
150
+ mutationFn: client.exportPresets
151
+ });
152
+
153
+ const updateRoutingMutation = useMutation({
154
+ mutationFn: client.updateRouting,
155
+ onSuccess: (data) => {
156
+ queryClient.setQueryData(["snapshot"], data);
157
+ }
158
+ });
159
+
160
+ const snapshot = snapshotQuery.data;
161
+ const platform = snapshot?.platforms.find((item) => item.id === activePlatform) || snapshot?.platforms[0];
162
+
163
+ useEffect(() => {
164
+ if (!platform) {
165
+ return;
166
+ }
167
+
168
+ const activeProvider = platform.providers.find((item) => item.isActive);
169
+ setEditorForm({
170
+ name: activeProvider?.name || "fhl",
171
+ baseUrl: activeProvider?.baseUrl || (platform.id === "openclaw" ? "https://www.fhl.mom/v1" : "https://www.fhl.mom"),
172
+ apiKey: "",
173
+ model: activeProvider?.model || (snapshot?.models[0] ?? "gpt-5.4")
174
+ });
175
+ }, [platform, snapshot?.models]);
176
+
177
+ const metrics = useMemo(() => {
178
+ if (!platform) {
179
+ return [];
180
+ }
181
+
182
+ return [
183
+ { label: "当前客户端", value: platform.label, hint: "已选择工作区" },
184
+ { label: "已保存服务商", value: `${platform.providerCount}`, hint: "可切换路由" },
185
+ { label: "当前路由", value: platform.currentProviderName || "无", hint: "正在生效" },
186
+ { label: "目标文件", value: `${platform.targetFiles.length}`, hint: "关联本地配置文件" }
187
+ ];
188
+ }, [platform]);
189
+
190
+ const activeSectionMeta = workspaceSections.find((item) => item.id === activeSection) || workspaceSections[0];
191
+
192
+ function openProvider(provider: Provider) {
193
+ setEditorForm({
194
+ name: provider.name,
195
+ baseUrl: provider.baseUrl,
196
+ apiKey: "",
197
+ model: provider.model
198
+ });
199
+ }
200
+
201
+ return {
202
+ activePlatform,
203
+ setActivePlatform,
204
+ activeSection,
205
+ setActiveSection,
206
+ activeSectionMeta,
207
+ editorForm,
208
+ setEditorForm,
209
+ snapshot,
210
+ platform,
211
+ metrics,
212
+ snapshotQuery,
213
+ probeQuery,
214
+ saveMutation,
215
+ activateMutation,
216
+ probeCandidateMutation,
217
+ openPathMutation,
218
+ toggleMcpMutation,
219
+ upsertMcpMutation,
220
+ deleteMcpMutation,
221
+ togglePromptMutation,
222
+ upsertPromptMutation,
223
+ deletePromptMutation,
224
+ upsertSkillMutation,
225
+ deleteSkillMutation,
226
+ toggleSkillRepoMutation,
227
+ savePresetMutation,
228
+ deletePresetMutation,
229
+ applyPresetMutation,
230
+ importPresetsMutation,
231
+ exportPresetsMutation,
232
+ updateRoutingMutation,
233
+ openProvider
234
+ };
235
+ }
package/src/index.css ADDED
@@ -0,0 +1,22 @@
1
+ @import "tailwindcss";
2
+
3
+ :root {
4
+ color: #0f172a;
5
+ background:
6
+ radial-gradient(circle at top left, rgba(37, 99, 235, 0.05), transparent 18%),
7
+ linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
8
+ font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
9
+ }
10
+
11
+ body {
12
+ margin: 0;
13
+ min-width: 320px;
14
+ min-height: 100vh;
15
+ background: transparent;
16
+ -webkit-font-smoothing: antialiased;
17
+ -moz-osx-font-smoothing: grayscale;
18
+ }
19
+
20
+ #root {
21
+ min-height: 100vh;
22
+ }