ccpanel 0.1.3 → 0.1.5

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.
package/README.md CHANGED
@@ -1,78 +1,20 @@
1
- # ccpanel
2
-
3
- 本地图形化管理 Claude Code 配置:MCP 服务器、Skills、子 Agent、Commands、配置文件、Memory、Sessions、Plugins(全局级 + 项目级)。
4
-
5
- ## 使用
6
-
7
- ```bash
8
- npx ccpanel
9
- ```
10
-
11
- 启动后自动打开浏览器(默认 http://localhost:7788)。
12
-
13
- ## 开发
14
-
15
- ```bash
16
- npm install && npm --prefix web install
17
- # 终端 A:后端
18
- npm run dev
19
- # 终端 B:前端
20
- npm --prefix web run dev
21
- ```
22
-
23
- ## 构建
24
-
25
- 修改代码后需重新编译,构建产物供 `npx claude-config-manager` 生产运行:
26
-
27
- ```bash
28
- npm run build # 全量:前端 web/dist + 后端 dist
29
- npm run build:web # 仅前端,产物 web/dist(改动 web/ 下代码时)
30
- npm run build:server # 仅后端,产物 dist/(改动 src/ 下代码时)
31
- ```
32
-
33
- - 改完**前端**:`npm run build:web` 后刷新浏览器即可生效(后端静态托管 `web/dist`,无需重启)。
34
- - 改完**后端**:`npm run build:server`;若用 `npm run dev`(tsx)运行后端,改动后需重启该进程才生效(tsx 不热重载)。
35
- - 开发模式下前端 `npm --prefix web run dev` 自带热更新(HMR),免手动构建。
36
-
37
- ## 测试
38
-
39
- ```bash
40
- npm test
41
- ```
42
-
43
- ## 发布 / 分发
44
-
45
- 让别人也能使用,有两种方式。两者都会自动包含前端产物 `web/dist`,发布前请确保已执行过 `npm run build`(`npm publish` 会通过 `prepublishOnly` 自动构建)。
46
-
47
- ### 方式一:发布到 npm(推荐,别人 `npx` 即用)
48
-
49
- ```bash
50
- npm login # 首次需要 npm 账号
51
- npm publish # prepublishOnly 会自动先 npm run build
52
- ```
53
-
54
- 发布后任何人可直接运行:
55
-
56
- ```bash
57
- npx ccpanel
58
- ```
59
-
60
- > 包名 `ccpanel` 目前在 npm 上可用;如后续被占用,可改用作用域名(如 `@你的用户名/ccpanel`),并以 `npm publish --access public` 发布。
61
-
62
- ### 方式二:分发 tarball(内网 / 小范围,无需发布)
63
-
64
- ```bash
65
- npm run build # 先构建
66
- npm pack # 生成 ccpanel-<version>.tgz
67
- ```
68
-
69
- 把生成的 `.tgz` 发给对方,对方安装运行:
70
-
71
- ```bash
72
- npm install -g ./ccpanel-0.1.0.tgz
73
- ccpanel
74
- # 或免安装直接运行:
75
- npx ./ccpanel-0.1.0.tgz
76
- ```
77
-
78
- > 使用者需 Node.js ≥ 20。工具为本地服务,启动后在 `localhost:7788` 读写本机 `~/.claude` 下的配置。
1
+ # ccpanel
2
+
3
+ 本地图形化管理 Claude Code 与 Codex 配置:MCP 服务器、Skills、子 Agent、Commands、配置文件、Memory、Sessions、Plugins(全局级 + 项目级)。
4
+
5
+ - **Claude**:管理 `~/.claude` 下全部配置(全局级 + 项目级)
6
+ - **Codex**:管理 `~/.codex` 下的 MCP、Skills、插件、配置文件、记忆和会话(配置仅全局级;记忆/会话只读)
7
+ - **公共 Skills**:展示 `~/.agents/skills`,一键同步到 Claude / Codex(创建目录链接),也可把本地技能「转公共」
8
+
9
+ ## 快速开始
10
+
11
+ ```bash
12
+ npx ccpanel
13
+ ```
14
+
15
+ 启动后自动打开浏览器(默认 http://localhost:7788),顶部可切换 Claude / Codex / 公共三个视图。需 Node.js ≥ 20。
16
+
17
+ ## 文档
18
+
19
+ - 技术栈、开发/构建/测试、发布分发:[docs/development.md](docs/development.md)
20
+ - Claude Code / Codex / 公共 Skills 目录结构与 ccpanel 读写范围:[docs/agent-directories.md](docs/agent-directories.md)
@@ -1,5 +1,5 @@
1
1
  // src/server/app.ts
2
- import { Hono as Hono10 } from "hono";
2
+ import { Hono as Hono11 } from "hono";
3
3
  import { serveStatic } from "@hono/node-server/serve-static";
4
4
  import { ZodError } from "zod";
5
5
 
@@ -37,7 +37,8 @@ var ConfigStore = class {
37
37
  throw new ConfigCorruptError(file);
38
38
  }
39
39
  }
40
- async writeJson(file, data) {
40
+ // 原子写 + 写前同目录 .bak 备份(仅当原文件存在)。内容原样落盘。
41
+ async writeText(file, content) {
41
42
  await mkdir(dirname(file), { recursive: true });
42
43
  try {
43
44
  await copyFile(file, file + ".bak");
@@ -45,9 +46,12 @@ var ConfigStore = class {
45
46
  if (err.code !== "ENOENT") throw err;
46
47
  }
47
48
  const tmp = `${file}.${process.pid}.${randomUUID()}.tmp`;
48
- await writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
49
+ await writeFile(tmp, content, "utf8");
49
50
  await rename(tmp, file);
50
51
  }
52
+ async writeJson(file, data) {
53
+ await this.writeText(file, JSON.stringify(data, null, 2) + "\n");
54
+ }
51
55
  };
52
56
 
53
57
  // src/core/errors.ts
@@ -79,21 +83,36 @@ import { createHash } from "crypto";
79
83
  import { join, resolve } from "path";
80
84
  function resolvePaths(opts) {
81
85
  const { home, projectPath } = opts;
86
+ const provider = opts.provider ?? "claude";
82
87
  const panelDir = join(home, ".ccpanel");
88
+ const codexDir = join(home, ".codex");
89
+ const agentsSkillsDir = join(home, ".agents", "skills");
90
+ const userSkillsDir = provider === "codex" ? join(codexDir, "skills") : provider === "agents" ? agentsSkillsDir : join(home, ".claude", "skills");
91
+ const userDisabledSkillsDir = provider === "codex" ? join(panelDir, "codex-disabled-skills") : provider === "agents" ? join(panelDir, "agents-disabled-skills") : join(panelDir, "disabled-skills");
83
92
  const paths = {
93
+ provider,
84
94
  userClaudeJson: join(home, ".claude.json"),
85
- userSkillsDir: join(home, ".claude", "skills"),
95
+ userMcpFile: provider === "codex" ? join(codexDir, "config.toml") : join(home, ".claude.json"),
96
+ userSkillsDir,
86
97
  userAgentsDir: join(home, ".claude", "agents"),
87
98
  userCommandsDir: join(home, ".claude", "commands"),
88
- userDisabledMcp: join(panelDir, "disabled-mcp.json"),
89
- userDisabledSkillsDir: join(panelDir, "disabled-skills"),
99
+ userDisabledMcp: provider === "codex" ? join(panelDir, "codex-disabled-mcp.json") : join(panelDir, "disabled-mcp.json"),
100
+ userDisabledSkillsDir,
90
101
  userSettings: join(home, ".claude", "settings.json"),
91
102
  userClaudeMd: join(home, ".claude", "CLAUDE.md"),
92
103
  userProjectsDir: join(home, ".claude", "projects"),
93
104
  pluginsDir: join(home, ".claude", "plugins"),
94
105
  installedPluginsJson: join(home, ".claude", "plugins", "installed_plugins.json"),
95
106
  knownMarketplacesJson: join(home, ".claude", "plugins", "known_marketplaces.json"),
96
- panelDir
107
+ panelDir,
108
+ agentsSkillsDir,
109
+ codexConfigToml: join(codexDir, "config.toml"),
110
+ codexAgentsMd: join(codexDir, "AGENTS.md"),
111
+ codexPluginsDir: join(codexDir, "plugins"),
112
+ codexMemoriesDir: join(codexDir, "memories"),
113
+ codexMemoriesDb: join(codexDir, "memories_1.sqlite"),
114
+ codexSessionsDir: join(codexDir, "sessions"),
115
+ codexSessionIndex: join(codexDir, "session_index.jsonl")
97
116
  };
98
117
  if (projectPath) {
99
118
  paths.projectMcpJson = join(projectPath, ".mcp.json");
@@ -111,17 +130,30 @@ function resolvePaths(opts) {
111
130
  // src/shared/schemas.ts
112
131
  import { z } from "zod";
113
132
  var ScopeSchema = z.enum(["user", "project"]);
133
+ var ProviderSchema = z.enum(["claude", "codex", "agents"]);
134
+ var McpProviderSchema = z.enum(["claude", "codex"]);
135
+ var ProviderScopeQuerySchema = z.object({
136
+ provider: ProviderSchema.default("claude"),
137
+ scope: ScopeSchema,
138
+ projectPath: z.string().optional()
139
+ }).refine((v) => v.scope === "user" || !!v.projectPath, {
140
+ message: "project scope \u9700\u8981 projectPath",
141
+ path: ["projectPath"]
142
+ }).refine((v) => v.provider === "claude" || v.scope === "user", {
143
+ message: "\u8BE5 provider \u4EC5\u652F\u6301\u7528\u6237\u7EA7\u4F5C\u7528\u57DF\uFF08scope=user\uFF09",
144
+ path: ["provider"]
145
+ });
114
146
  var StdioMcpServerSchema = z.object({
115
147
  type: z.literal("stdio").optional(),
116
148
  command: z.string().min(1),
117
149
  args: z.array(z.string()).optional(),
118
150
  env: z.record(z.string()).optional()
119
- });
151
+ }).passthrough();
120
152
  var RemoteMcpServerSchema = z.object({
121
153
  type: z.enum(["sse", "http"]),
122
154
  url: z.string().url(),
123
155
  headers: z.record(z.string()).optional()
124
- });
156
+ }).passthrough();
125
157
  var McpServerSchema = z.union([
126
158
  RemoteMcpServerSchema,
127
159
  StdioMcpServerSchema
@@ -140,7 +172,12 @@ var MemoryWriteSchema = z.object({
140
172
  content: z.string(),
141
173
  baseMtime: BaseMtimeSchema
142
174
  });
143
- var ConfigFileIdSchema = z.enum(["settings", "claude-json"]);
175
+ var ConfigFileIdSchema = z.enum([
176
+ "settings",
177
+ "claude-json",
178
+ "codex-config",
179
+ "codex-agents"
180
+ ]);
144
181
  var ConfigFileWriteSchema = z.object({
145
182
  content: z.string(),
146
183
  baseMtime: BaseMtimeSchema
@@ -157,11 +194,20 @@ var ScopeQuerySchema = z.object({
157
194
  function mcpRoutes(deps) {
158
195
  const app = new Hono();
159
196
  const ctx = (c) => {
160
- const q = ScopeQuerySchema.parse({
197
+ const q = ProviderScopeQuerySchema.parse({
198
+ provider: c.req.query("provider"),
161
199
  scope: c.req.query("scope"),
162
200
  projectPath: c.req.query("projectPath")
163
201
  });
164
- return { q, paths: resolvePaths({ home: deps.home, projectPath: q.projectPath }) };
202
+ McpProviderSchema.parse(q.provider);
203
+ return {
204
+ q,
205
+ paths: resolvePaths({
206
+ home: deps.home,
207
+ projectPath: q.projectPath,
208
+ provider: q.provider
209
+ })
210
+ };
165
211
  };
166
212
  app.get("/", async (c) => {
167
213
  const { q, paths } = ctx(c);
@@ -205,11 +251,19 @@ var SkillBodySchema = z2.object({
205
251
  function skillRoutes(deps) {
206
252
  const app = new Hono2();
207
253
  const ctx = (c) => {
208
- const q = ScopeQuerySchema.parse({
254
+ const q = ProviderScopeQuerySchema.parse({
255
+ provider: c.req.query("provider"),
209
256
  scope: c.req.query("scope"),
210
257
  projectPath: c.req.query("projectPath")
211
258
  });
212
- return { q, paths: resolvePaths({ home: deps.home, projectPath: q.projectPath }) };
259
+ return {
260
+ q,
261
+ paths: resolvePaths({
262
+ home: deps.home,
263
+ projectPath: q.projectPath,
264
+ provider: q.provider
265
+ })
266
+ };
213
267
  };
214
268
  app.get("/", async (c) => {
215
269
  const { q, paths } = ctx(c);
@@ -266,34 +320,76 @@ function skillRoutes(deps) {
266
320
  });
267
321
  app.post("/:name/toggle", async (c) => {
268
322
  const { q, paths } = ctx(c);
323
+ if (q.provider === "agents") {
324
+ return c.json({ error: "\u516C\u5171 skills \u4E0D\u652F\u6301\u542F\u7528/\u7981\u7528" }, 400);
325
+ }
269
326
  const { enabled } = await c.req.json();
270
327
  await deps.skills.toggle(paths, q.scope, c.req.param("name"), enabled);
271
328
  return c.json(await deps.skills.list(paths, q.scope));
272
329
  });
330
+ app.post("/:name/make-shared", async (c) => {
331
+ const { q } = ctx(c);
332
+ if (q.provider === "agents") {
333
+ return c.json({ error: "\u8F6C\u516C\u5171\u4EC5\u652F\u6301 claude/codex \u4E0B\u7684\u6280\u80FD" }, 400);
334
+ }
335
+ await deps.sync.makeShared(q.provider, c.req.param("name"));
336
+ return c.json({ ok: true });
337
+ });
273
338
  return app;
274
339
  }
275
340
 
276
- // src/server/routes/projects.ts
341
+ // src/server/routes/shared-skills.ts
277
342
  import { Hono as Hono3 } from "hono";
278
343
  import { z as z3 } from "zod";
279
- function projectRoutes(deps) {
344
+ var SyncBodySchema = z3.object({ target: z3.enum(["claude", "codex"]) });
345
+ function sharedSkillRoutes(deps) {
280
346
  const app = new Hono3();
347
+ app.get("/", async (c) => {
348
+ const paths = resolvePaths({ home: deps.home, provider: "agents" });
349
+ const base = await deps.skills.list(paths, "user");
350
+ const withSync = await Promise.all(
351
+ base.map(async (s) => ({ ...s, sync: await deps.sync.status(s.name) }))
352
+ );
353
+ return c.json(withSync);
354
+ });
355
+ app.post("/:name/sync", async (c) => {
356
+ const { target } = SyncBodySchema.parse(await c.req.json());
357
+ await deps.sync.syncTo(c.req.param("name"), target);
358
+ return c.json({ ok: true });
359
+ });
360
+ app.delete("/:name/sync", async (c) => {
361
+ const { target } = SyncBodySchema.parse(await c.req.json());
362
+ await deps.sync.unsync(c.req.param("name"), target);
363
+ return c.json({ ok: true });
364
+ });
365
+ return app;
366
+ }
367
+
368
+ // src/server/routes/projects.ts
369
+ import { Hono as Hono4 } from "hono";
370
+ import { z as z4 } from "zod";
371
+ function projectRoutes(deps) {
372
+ const app = new Hono4();
281
373
  app.get("/", async (c) => c.json({ projects: await deps.projects.list() }));
374
+ app.get(
375
+ "/known",
376
+ async (c) => c.json({ projects: await deps.projects.known() })
377
+ );
282
378
  app.post("/", async (c) => {
283
- const { path } = z3.object({ path: z3.string().min(1) }).parse(await c.req.json());
379
+ const { path } = z4.object({ path: z4.string().min(1) }).parse(await c.req.json());
284
380
  return c.json({ projects: await deps.projects.add(path) });
285
381
  });
286
382
  app.delete("/", async (c) => {
287
- const { path } = z3.object({ path: z3.string().min(1) }).parse(await c.req.json());
383
+ const { path } = z4.object({ path: z4.string().min(1) }).parse(await c.req.json());
288
384
  return c.json({ projects: await deps.projects.remove(path) });
289
385
  });
290
386
  return app;
291
387
  }
292
388
 
293
389
  // src/server/routes/memory.ts
294
- import { Hono as Hono4 } from "hono";
390
+ import { Hono as Hono5 } from "hono";
295
391
  function memoryRoutes(deps) {
296
- const app = new Hono4();
392
+ const app = new Hono5();
297
393
  const ctx = (c) => {
298
394
  const q = ScopeQuerySchema.parse({
299
395
  scope: c.req.query("scope"),
@@ -315,96 +411,164 @@ function memoryRoutes(deps) {
315
411
  }
316
412
 
317
413
  // src/server/routes/memory-files.ts
318
- import { Hono as Hono5 } from "hono";
319
- import { z as z4 } from "zod";
320
- var QuerySchema = z4.object({ projectPath: z4.string().min(1) });
414
+ import { Hono as Hono6 } from "hono";
415
+ import { z as z5 } from "zod";
416
+ var ProviderQuerySchema = z5.object({
417
+ provider: z5.enum(["claude", "codex"]).default("claude")
418
+ });
419
+ var ClaudeQuerySchema = z5.object({ projectPath: z5.string().min(1) });
321
420
  function memoryFilesRoutes(deps) {
322
- const app = new Hono5();
421
+ const app = new Hono6();
323
422
  const ctx = (c) => {
324
- const { projectPath } = QuerySchema.parse({ projectPath: c.req.query("projectPath") });
325
- return { projectPath, paths: resolvePaths({ home: deps.home, projectPath }) };
423
+ const { provider } = ProviderQuerySchema.parse({
424
+ provider: c.req.query("provider") ?? "claude"
425
+ });
426
+ if (provider === "codex") {
427
+ return {
428
+ provider,
429
+ projectPath: void 0,
430
+ paths: resolvePaths({ home: deps.home, provider })
431
+ };
432
+ }
433
+ const { projectPath } = ClaudeQuerySchema.parse({
434
+ projectPath: c.req.query("projectPath")
435
+ });
436
+ return {
437
+ provider,
438
+ projectPath,
439
+ paths: resolvePaths({ home: deps.home, projectPath, provider })
440
+ };
326
441
  };
327
442
  app.get("/", async (c) => {
328
- const { projectPath, paths } = ctx(c);
329
- return c.json(await deps.memoryFiles.overview(paths, projectPath));
443
+ const { provider, projectPath, paths } = ctx(c);
444
+ return c.json(
445
+ provider === "codex" ? await deps.codexMemory.overview(paths) : await deps.memoryFiles.overview(paths, projectPath)
446
+ );
330
447
  });
331
448
  app.get("/:file", async (c) => {
332
- const { projectPath, paths } = ctx(c);
333
- return c.json(await deps.memoryFiles.read(paths, projectPath, c.req.param("file")));
449
+ const { provider, projectPath, paths } = ctx(c);
450
+ return c.json(
451
+ provider === "codex" ? await deps.codexMemory.read(paths, c.req.param("file")) : await deps.memoryFiles.read(paths, projectPath, c.req.param("file"))
452
+ );
334
453
  });
335
454
  return app;
336
455
  }
337
456
 
338
457
  // src/server/routes/sessions.ts
339
- import { Hono as Hono6 } from "hono";
340
- import { z as z5 } from "zod";
341
- var QuerySchema2 = z5.object({ projectPath: z5.string().min(1) });
458
+ import { Hono as Hono7 } from "hono";
459
+ import { z as z6 } from "zod";
460
+ var QuerySchema = z6.object({
461
+ provider: z6.enum(["claude", "codex"]).default("claude"),
462
+ projectPath: z6.string().min(1)
463
+ });
342
464
  function sessionRoutes(deps) {
343
- const app = new Hono6();
465
+ const app = new Hono7();
344
466
  const ctx = (c) => {
345
- const { projectPath } = QuerySchema2.parse({ projectPath: c.req.query("projectPath") });
346
- return { projectPath, paths: resolvePaths({ home: deps.home, projectPath }) };
467
+ const { provider, projectPath } = QuerySchema.parse({
468
+ provider: c.req.query("provider") ?? "claude",
469
+ projectPath: c.req.query("projectPath")
470
+ });
471
+ return {
472
+ provider,
473
+ projectPath,
474
+ paths: resolvePaths({ home: deps.home, projectPath, provider })
475
+ };
347
476
  };
348
477
  app.get("/", async (c) => {
349
- const { projectPath, paths } = ctx(c);
350
- return c.json(await deps.sessions.list(paths, projectPath));
478
+ const { provider, projectPath, paths } = ctx(c);
479
+ return c.json(
480
+ provider === "codex" ? await deps.codexSessions.list(paths, projectPath) : await deps.sessions.list(paths, projectPath)
481
+ );
351
482
  });
352
483
  app.get("/:id", async (c) => {
353
- const { projectPath, paths } = ctx(c);
354
- return c.json(await deps.sessions.read(paths, projectPath, c.req.param("id")));
484
+ const { provider, projectPath, paths } = ctx(c);
485
+ return c.json(
486
+ provider === "codex" ? await deps.codexSessions.read(paths, projectPath, c.req.param("id")) : await deps.sessions.read(paths, projectPath, c.req.param("id"))
487
+ );
355
488
  });
356
489
  return app;
357
490
  }
358
491
 
359
492
  // src/server/routes/plugins.ts
360
- import { Hono as Hono7 } from "hono";
361
- import { z as z6 } from "zod";
362
- var EnabledBodySchema = z6.object({ enabled: z6.boolean() });
363
- var ComponentQuerySchema = z6.object({
364
- type: z6.enum(["skill", "command", "agent", "hook", "mcp"]),
365
- name: z6.string().min(1)
493
+ import { Hono as Hono8 } from "hono";
494
+ import { z as z7 } from "zod";
495
+ var ProviderQuerySchema2 = z7.object({
496
+ provider: z7.enum(["claude", "codex"]).default("claude")
497
+ });
498
+ var EnabledBodySchema = z7.object({
499
+ enabled: z7.boolean(),
500
+ baseMtime: z7.number().optional()
501
+ });
502
+ var ComponentQuerySchema = z7.object({
503
+ type: z7.enum(["skill", "command", "agent", "hook", "mcp"]),
504
+ name: z7.string().min(1)
366
505
  });
367
506
  function pluginRoutes(deps) {
368
- const app = new Hono7();
369
- const paths = () => resolvePaths({ home: deps.home });
370
- app.get("/", async (c) => c.json(await deps.plugins.list(paths())));
371
- app.get(
372
- "/:id",
373
- async (c) => c.json(await deps.plugins.detail(paths(), c.req.param("id")))
374
- );
507
+ const app = new Hono8();
508
+ const ctx = (c) => {
509
+ const { provider } = ProviderQuerySchema2.parse({
510
+ provider: c.req.query("provider") ?? "claude"
511
+ });
512
+ return { provider, paths: resolvePaths({ home: deps.home, provider }) };
513
+ };
514
+ app.get("/", async (c) => {
515
+ const { provider, paths } = ctx(c);
516
+ return c.json(
517
+ provider === "codex" ? await deps.codexPlugins.list(paths) : await deps.plugins.list(paths)
518
+ );
519
+ });
520
+ app.get("/:id", async (c) => {
521
+ const { provider, paths } = ctx(c);
522
+ return c.json(
523
+ provider === "codex" ? await deps.codexPlugins.detail(paths, c.req.param("id")) : await deps.plugins.detail(paths, c.req.param("id"))
524
+ );
525
+ });
375
526
  app.get("/:id/component", async (c) => {
527
+ const { provider, paths } = ctx(c);
376
528
  const q = ComponentQuerySchema.parse({
377
529
  type: c.req.query("type"),
378
530
  name: c.req.query("name")
379
531
  });
532
+ const svc = provider === "codex" ? deps.codexPlugins : deps.plugins;
380
533
  return c.json(
381
- await deps.plugins.readComponent(
382
- paths(),
383
- c.req.param("id"),
384
- q.type,
385
- q.name
386
- )
534
+ await svc.readComponent(paths, c.req.param("id"), q.type, q.name)
387
535
  );
388
536
  });
389
537
  app.patch("/:id", async (c) => {
390
- const { enabled } = EnabledBodySchema.parse(await c.req.json());
391
- await deps.plugins.setEnabled(paths(), c.req.param("id"), enabled);
392
- return c.json(await deps.plugins.list(paths()));
538
+ const { provider, paths } = ctx(c);
539
+ const { enabled, baseMtime } = EnabledBodySchema.parse(await c.req.json());
540
+ if (provider === "codex") {
541
+ await deps.codexPlugins.setEnabled(
542
+ paths,
543
+ c.req.param("id"),
544
+ enabled,
545
+ baseMtime
546
+ );
547
+ return c.json(await deps.codexPlugins.list(paths));
548
+ }
549
+ await deps.plugins.setEnabled(paths, c.req.param("id"), enabled);
550
+ return c.json(await deps.plugins.list(paths));
393
551
  });
394
552
  return app;
395
553
  }
396
554
 
397
555
  // src/server/routes/config-files.ts
398
- import { Hono as Hono8 } from "hono";
556
+ import { Hono as Hono9 } from "hono";
399
557
  function configFileRoutes(deps) {
400
- const app = new Hono8();
558
+ const app = new Hono9();
401
559
  const ctx = (c) => {
402
560
  const fileId = ConfigFileIdSchema.parse(c.req.param("file"));
403
- const q = ScopeQuerySchema.parse({
561
+ const q = ProviderScopeQuerySchema.parse({
562
+ provider: c.req.query("provider"),
404
563
  scope: c.req.query("scope"),
405
564
  projectPath: c.req.query("projectPath")
406
565
  });
407
- return { fileId, q, paths: resolvePaths({ home: deps.home, projectPath: q.projectPath }) };
566
+ McpProviderSchema.parse(q.provider);
567
+ return {
568
+ fileId,
569
+ q,
570
+ paths: resolvePaths({ home: deps.home, projectPath: q.projectPath, provider: q.provider })
571
+ };
408
572
  };
409
573
  app.get("/:file", async (c) => {
410
574
  const { fileId, q, paths } = ctx(c);
@@ -420,15 +584,15 @@ function configFileRoutes(deps) {
420
584
  }
421
585
 
422
586
  // src/server/routes/agent-commands.ts
423
- import { Hono as Hono9 } from "hono";
424
- import { z as z7 } from "zod";
425
- var CreateSchema = z7.object({ name: z7.string().min(1), content: z7.string() });
426
- var WriteSchema = z7.object({
427
- content: z7.string(),
428
- baseMtime: z7.number().nullable().optional()
587
+ import { Hono as Hono10 } from "hono";
588
+ import { z as z8 } from "zod";
589
+ var CreateSchema = z8.object({ name: z8.string().min(1), content: z8.string() });
590
+ var WriteSchema = z8.object({
591
+ content: z8.string(),
592
+ baseMtime: z8.number().nullable().optional()
429
593
  });
430
594
  function agentCommandRoutes(deps, kind) {
431
- const app = new Hono9();
595
+ const app = new Hono10();
432
596
  const ctx = (c) => {
433
597
  const q = ScopeQuerySchema.parse({
434
598
  scope: c.req.query("scope"),
@@ -466,7 +630,7 @@ function agentCommandRoutes(deps, kind) {
466
630
 
467
631
  // src/server/app.ts
468
632
  function createApp(deps) {
469
- const app = new Hono10();
633
+ const app = new Hono11();
470
634
  app.onError((err, c) => {
471
635
  if (err instanceof ZodError) {
472
636
  return c.json({ error: "\u6821\u9A8C\u5931\u8D25", issues: err.issues }, 400);
@@ -484,6 +648,7 @@ function createApp(deps) {
484
648
  });
485
649
  app.route("/api/mcp", mcpRoutes(deps));
486
650
  app.route("/api/skills", skillRoutes(deps));
651
+ app.route("/api/shared-skills", sharedSkillRoutes(deps));
487
652
  app.route("/api/projects", projectRoutes(deps));
488
653
  app.route("/api/memory", memoryRoutes(deps));
489
654
  app.route("/api/memory-files", memoryFilesRoutes(deps));
@@ -497,8 +662,10 @@ function createApp(deps) {
497
662
  }
498
663
 
499
664
  export {
665
+ ConfigCorruptError,
500
666
  InvalidJsonError,
501
667
  ConfigStore,
668
+ ConflictError,
502
669
  currentMtime,
503
670
  assertNoConflict,
504
671
  SkillFrontmatterSchema,