ccpanel 0.1.3 → 0.1.4

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,72 @@ 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() }));
282
374
  app.post("/", async (c) => {
283
- const { path } = z3.object({ path: z3.string().min(1) }).parse(await c.req.json());
375
+ const { path } = z4.object({ path: z4.string().min(1) }).parse(await c.req.json());
284
376
  return c.json({ projects: await deps.projects.add(path) });
285
377
  });
286
378
  app.delete("/", async (c) => {
287
- 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());
288
380
  return c.json({ projects: await deps.projects.remove(path) });
289
381
  });
290
382
  return app;
291
383
  }
292
384
 
293
385
  // src/server/routes/memory.ts
294
- import { Hono as Hono4 } from "hono";
386
+ import { Hono as Hono5 } from "hono";
295
387
  function memoryRoutes(deps) {
296
- const app = new Hono4();
388
+ const app = new Hono5();
297
389
  const ctx = (c) => {
298
390
  const q = ScopeQuerySchema.parse({
299
391
  scope: c.req.query("scope"),
@@ -315,96 +407,164 @@ function memoryRoutes(deps) {
315
407
  }
316
408
 
317
409
  // 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) });
410
+ import { Hono as Hono6 } from "hono";
411
+ import { z as z5 } from "zod";
412
+ var ProviderQuerySchema = z5.object({
413
+ provider: z5.enum(["claude", "codex"]).default("claude")
414
+ });
415
+ var ClaudeQuerySchema = z5.object({ projectPath: z5.string().min(1) });
321
416
  function memoryFilesRoutes(deps) {
322
- const app = new Hono5();
417
+ const app = new Hono6();
323
418
  const ctx = (c) => {
324
- const { projectPath } = QuerySchema.parse({ projectPath: c.req.query("projectPath") });
325
- return { projectPath, paths: resolvePaths({ home: deps.home, projectPath }) };
419
+ const { provider } = ProviderQuerySchema.parse({
420
+ provider: c.req.query("provider") ?? "claude"
421
+ });
422
+ if (provider === "codex") {
423
+ return {
424
+ provider,
425
+ projectPath: void 0,
426
+ paths: resolvePaths({ home: deps.home, provider })
427
+ };
428
+ }
429
+ const { projectPath } = ClaudeQuerySchema.parse({
430
+ projectPath: c.req.query("projectPath")
431
+ });
432
+ return {
433
+ provider,
434
+ projectPath,
435
+ paths: resolvePaths({ home: deps.home, projectPath, provider })
436
+ };
326
437
  };
327
438
  app.get("/", async (c) => {
328
- const { projectPath, paths } = ctx(c);
329
- return c.json(await deps.memoryFiles.overview(paths, projectPath));
439
+ const { provider, projectPath, paths } = ctx(c);
440
+ return c.json(
441
+ provider === "codex" ? await deps.codexMemory.overview(paths) : await deps.memoryFiles.overview(paths, projectPath)
442
+ );
330
443
  });
331
444
  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")));
445
+ const { provider, projectPath, paths } = ctx(c);
446
+ return c.json(
447
+ provider === "codex" ? await deps.codexMemory.read(paths, c.req.param("file")) : await deps.memoryFiles.read(paths, projectPath, c.req.param("file"))
448
+ );
334
449
  });
335
450
  return app;
336
451
  }
337
452
 
338
453
  // 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) });
454
+ import { Hono as Hono7 } from "hono";
455
+ import { z as z6 } from "zod";
456
+ var QuerySchema = z6.object({
457
+ provider: z6.enum(["claude", "codex"]).default("claude"),
458
+ projectPath: z6.string().min(1)
459
+ });
342
460
  function sessionRoutes(deps) {
343
- const app = new Hono6();
461
+ const app = new Hono7();
344
462
  const ctx = (c) => {
345
- const { projectPath } = QuerySchema2.parse({ projectPath: c.req.query("projectPath") });
346
- return { projectPath, paths: resolvePaths({ home: deps.home, projectPath }) };
463
+ const { provider, projectPath } = QuerySchema.parse({
464
+ provider: c.req.query("provider") ?? "claude",
465
+ projectPath: c.req.query("projectPath")
466
+ });
467
+ return {
468
+ provider,
469
+ projectPath,
470
+ paths: resolvePaths({ home: deps.home, projectPath, provider })
471
+ };
347
472
  };
348
473
  app.get("/", async (c) => {
349
- const { projectPath, paths } = ctx(c);
350
- return c.json(await deps.sessions.list(paths, projectPath));
474
+ const { provider, projectPath, paths } = ctx(c);
475
+ return c.json(
476
+ provider === "codex" ? await deps.codexSessions.list(paths, projectPath) : await deps.sessions.list(paths, projectPath)
477
+ );
351
478
  });
352
479
  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")));
480
+ const { provider, projectPath, paths } = ctx(c);
481
+ return c.json(
482
+ provider === "codex" ? await deps.codexSessions.read(paths, projectPath, c.req.param("id")) : await deps.sessions.read(paths, projectPath, c.req.param("id"))
483
+ );
355
484
  });
356
485
  return app;
357
486
  }
358
487
 
359
488
  // 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)
489
+ import { Hono as Hono8 } from "hono";
490
+ import { z as z7 } from "zod";
491
+ var ProviderQuerySchema2 = z7.object({
492
+ provider: z7.enum(["claude", "codex"]).default("claude")
493
+ });
494
+ var EnabledBodySchema = z7.object({
495
+ enabled: z7.boolean(),
496
+ baseMtime: z7.number().optional()
497
+ });
498
+ var ComponentQuerySchema = z7.object({
499
+ type: z7.enum(["skill", "command", "agent", "hook", "mcp"]),
500
+ name: z7.string().min(1)
366
501
  });
367
502
  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
- );
503
+ const app = new Hono8();
504
+ const ctx = (c) => {
505
+ const { provider } = ProviderQuerySchema2.parse({
506
+ provider: c.req.query("provider") ?? "claude"
507
+ });
508
+ return { provider, paths: resolvePaths({ home: deps.home, provider }) };
509
+ };
510
+ app.get("/", async (c) => {
511
+ const { provider, paths } = ctx(c);
512
+ return c.json(
513
+ provider === "codex" ? await deps.codexPlugins.list(paths) : await deps.plugins.list(paths)
514
+ );
515
+ });
516
+ app.get("/:id", async (c) => {
517
+ const { provider, paths } = ctx(c);
518
+ return c.json(
519
+ provider === "codex" ? await deps.codexPlugins.detail(paths, c.req.param("id")) : await deps.plugins.detail(paths, c.req.param("id"))
520
+ );
521
+ });
375
522
  app.get("/:id/component", async (c) => {
523
+ const { provider, paths } = ctx(c);
376
524
  const q = ComponentQuerySchema.parse({
377
525
  type: c.req.query("type"),
378
526
  name: c.req.query("name")
379
527
  });
528
+ const svc = provider === "codex" ? deps.codexPlugins : deps.plugins;
380
529
  return c.json(
381
- await deps.plugins.readComponent(
382
- paths(),
383
- c.req.param("id"),
384
- q.type,
385
- q.name
386
- )
530
+ await svc.readComponent(paths, c.req.param("id"), q.type, q.name)
387
531
  );
388
532
  });
389
533
  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()));
534
+ const { provider, paths } = ctx(c);
535
+ const { enabled, baseMtime } = EnabledBodySchema.parse(await c.req.json());
536
+ if (provider === "codex") {
537
+ await deps.codexPlugins.setEnabled(
538
+ paths,
539
+ c.req.param("id"),
540
+ enabled,
541
+ baseMtime
542
+ );
543
+ return c.json(await deps.codexPlugins.list(paths));
544
+ }
545
+ await deps.plugins.setEnabled(paths, c.req.param("id"), enabled);
546
+ return c.json(await deps.plugins.list(paths));
393
547
  });
394
548
  return app;
395
549
  }
396
550
 
397
551
  // src/server/routes/config-files.ts
398
- import { Hono as Hono8 } from "hono";
552
+ import { Hono as Hono9 } from "hono";
399
553
  function configFileRoutes(deps) {
400
- const app = new Hono8();
554
+ const app = new Hono9();
401
555
  const ctx = (c) => {
402
556
  const fileId = ConfigFileIdSchema.parse(c.req.param("file"));
403
- const q = ScopeQuerySchema.parse({
557
+ const q = ProviderScopeQuerySchema.parse({
558
+ provider: c.req.query("provider"),
404
559
  scope: c.req.query("scope"),
405
560
  projectPath: c.req.query("projectPath")
406
561
  });
407
- return { fileId, q, paths: resolvePaths({ home: deps.home, projectPath: q.projectPath }) };
562
+ McpProviderSchema.parse(q.provider);
563
+ return {
564
+ fileId,
565
+ q,
566
+ paths: resolvePaths({ home: deps.home, projectPath: q.projectPath, provider: q.provider })
567
+ };
408
568
  };
409
569
  app.get("/:file", async (c) => {
410
570
  const { fileId, q, paths } = ctx(c);
@@ -420,15 +580,15 @@ function configFileRoutes(deps) {
420
580
  }
421
581
 
422
582
  // 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()
583
+ import { Hono as Hono10 } from "hono";
584
+ import { z as z8 } from "zod";
585
+ var CreateSchema = z8.object({ name: z8.string().min(1), content: z8.string() });
586
+ var WriteSchema = z8.object({
587
+ content: z8.string(),
588
+ baseMtime: z8.number().nullable().optional()
429
589
  });
430
590
  function agentCommandRoutes(deps, kind) {
431
- const app = new Hono9();
591
+ const app = new Hono10();
432
592
  const ctx = (c) => {
433
593
  const q = ScopeQuerySchema.parse({
434
594
  scope: c.req.query("scope"),
@@ -466,7 +626,7 @@ function agentCommandRoutes(deps, kind) {
466
626
 
467
627
  // src/server/app.ts
468
628
  function createApp(deps) {
469
- const app = new Hono10();
629
+ const app = new Hono11();
470
630
  app.onError((err, c) => {
471
631
  if (err instanceof ZodError) {
472
632
  return c.json({ error: "\u6821\u9A8C\u5931\u8D25", issues: err.issues }, 400);
@@ -484,6 +644,7 @@ function createApp(deps) {
484
644
  });
485
645
  app.route("/api/mcp", mcpRoutes(deps));
486
646
  app.route("/api/skills", skillRoutes(deps));
647
+ app.route("/api/shared-skills", sharedSkillRoutes(deps));
487
648
  app.route("/api/projects", projectRoutes(deps));
488
649
  app.route("/api/memory", memoryRoutes(deps));
489
650
  app.route("/api/memory-files", memoryFilesRoutes(deps));
@@ -497,8 +658,10 @@ function createApp(deps) {
497
658
  }
498
659
 
499
660
  export {
661
+ ConfigCorruptError,
500
662
  InvalidJsonError,
501
663
  ConfigStore,
664
+ ConflictError,
502
665
  currentMtime,
503
666
  assertNoConflict,
504
667
  SkillFrontmatterSchema,