ccpanel 0.1.2 → 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 +20 -78
- package/dist/{chunk-7ROXP6AO.js → chunk-HRPQYUJV.js} +286 -83
- package/dist/cli.js +1085 -148
- package/dist/server/app.js +1 -1
- package/package.json +29 -11
- package/web/dist/assets/index-D8o1BXhX.css +1 -0
- package/web/dist/assets/{index-DoKBz_TC.js → index-DtOjAT6i.js} +29 -29
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-CscUfGaI.css +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/server/app.ts
|
|
2
|
-
import { Hono as
|
|
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
|
-
|
|
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,11 +46,35 @@ 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,
|
|
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
|
|
|
57
|
+
// src/core/errors.ts
|
|
58
|
+
import { stat } from "fs/promises";
|
|
59
|
+
var ConflictError = class extends Error {
|
|
60
|
+
constructor(message = "\u6587\u4EF6\u5DF2\u88AB\u5916\u90E8\u4FEE\u6539\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D\u540E\u518D\u4FDD\u5B58") {
|
|
61
|
+
super(message);
|
|
62
|
+
this.name = "ConflictError";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
async function currentMtime(file) {
|
|
66
|
+
try {
|
|
67
|
+
return (await stat(file)).mtimeMs;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (err.code === "ENOENT") return null;
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function assertNoConflict(file, baseMtime) {
|
|
74
|
+
if (baseMtime === void 0) return;
|
|
75
|
+
if (await currentMtime(file) !== baseMtime) throw new ConflictError();
|
|
76
|
+
}
|
|
77
|
+
|
|
53
78
|
// src/server/routes/mcp.ts
|
|
54
79
|
import { Hono } from "hono";
|
|
55
80
|
|
|
@@ -58,21 +83,36 @@ import { createHash } from "crypto";
|
|
|
58
83
|
import { join, resolve } from "path";
|
|
59
84
|
function resolvePaths(opts) {
|
|
60
85
|
const { home, projectPath } = opts;
|
|
86
|
+
const provider = opts.provider ?? "claude";
|
|
61
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");
|
|
62
92
|
const paths = {
|
|
93
|
+
provider,
|
|
63
94
|
userClaudeJson: join(home, ".claude.json"),
|
|
64
|
-
|
|
95
|
+
userMcpFile: provider === "codex" ? join(codexDir, "config.toml") : join(home, ".claude.json"),
|
|
96
|
+
userSkillsDir,
|
|
65
97
|
userAgentsDir: join(home, ".claude", "agents"),
|
|
66
98
|
userCommandsDir: join(home, ".claude", "commands"),
|
|
67
|
-
userDisabledMcp: join(panelDir, "disabled-mcp.json"),
|
|
68
|
-
userDisabledSkillsDir
|
|
99
|
+
userDisabledMcp: provider === "codex" ? join(panelDir, "codex-disabled-mcp.json") : join(panelDir, "disabled-mcp.json"),
|
|
100
|
+
userDisabledSkillsDir,
|
|
69
101
|
userSettings: join(home, ".claude", "settings.json"),
|
|
70
102
|
userClaudeMd: join(home, ".claude", "CLAUDE.md"),
|
|
71
103
|
userProjectsDir: join(home, ".claude", "projects"),
|
|
72
104
|
pluginsDir: join(home, ".claude", "plugins"),
|
|
73
105
|
installedPluginsJson: join(home, ".claude", "plugins", "installed_plugins.json"),
|
|
74
106
|
knownMarketplacesJson: join(home, ".claude", "plugins", "known_marketplaces.json"),
|
|
75
|
-
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")
|
|
76
116
|
};
|
|
77
117
|
if (projectPath) {
|
|
78
118
|
paths.projectMcpJson = join(projectPath, ".mcp.json");
|
|
@@ -90,17 +130,30 @@ function resolvePaths(opts) {
|
|
|
90
130
|
// src/shared/schemas.ts
|
|
91
131
|
import { z } from "zod";
|
|
92
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
|
+
});
|
|
93
146
|
var StdioMcpServerSchema = z.object({
|
|
94
147
|
type: z.literal("stdio").optional(),
|
|
95
148
|
command: z.string().min(1),
|
|
96
149
|
args: z.array(z.string()).optional(),
|
|
97
150
|
env: z.record(z.string()).optional()
|
|
98
|
-
});
|
|
151
|
+
}).passthrough();
|
|
99
152
|
var RemoteMcpServerSchema = z.object({
|
|
100
153
|
type: z.enum(["sse", "http"]),
|
|
101
154
|
url: z.string().url(),
|
|
102
155
|
headers: z.record(z.string()).optional()
|
|
103
|
-
});
|
|
156
|
+
}).passthrough();
|
|
104
157
|
var McpServerSchema = z.union([
|
|
105
158
|
RemoteMcpServerSchema,
|
|
106
159
|
StdioMcpServerSchema
|
|
@@ -110,10 +163,25 @@ var McpServerInputSchema = z.intersection(
|
|
|
110
163
|
McpServerSchema
|
|
111
164
|
);
|
|
112
165
|
var SkillFrontmatterSchema = z.object({ name: z.string().min(1), description: z.string().min(1) }).passthrough();
|
|
113
|
-
var
|
|
114
|
-
var
|
|
115
|
-
|
|
116
|
-
|
|
166
|
+
var BaseMtimeSchema = z.number().nullable().optional();
|
|
167
|
+
var SkillFileWriteSchema = z.object({
|
|
168
|
+
content: z.string(),
|
|
169
|
+
baseMtime: BaseMtimeSchema
|
|
170
|
+
});
|
|
171
|
+
var MemoryWriteSchema = z.object({
|
|
172
|
+
content: z.string(),
|
|
173
|
+
baseMtime: BaseMtimeSchema
|
|
174
|
+
});
|
|
175
|
+
var ConfigFileIdSchema = z.enum([
|
|
176
|
+
"settings",
|
|
177
|
+
"claude-json",
|
|
178
|
+
"codex-config",
|
|
179
|
+
"codex-agents"
|
|
180
|
+
]);
|
|
181
|
+
var ConfigFileWriteSchema = z.object({
|
|
182
|
+
content: z.string(),
|
|
183
|
+
baseMtime: BaseMtimeSchema
|
|
184
|
+
});
|
|
117
185
|
var ScopeQuerySchema = z.object({
|
|
118
186
|
scope: ScopeSchema,
|
|
119
187
|
projectPath: z.string().optional()
|
|
@@ -126,11 +194,20 @@ var ScopeQuerySchema = z.object({
|
|
|
126
194
|
function mcpRoutes(deps) {
|
|
127
195
|
const app = new Hono();
|
|
128
196
|
const ctx = (c) => {
|
|
129
|
-
const q =
|
|
197
|
+
const q = ProviderScopeQuerySchema.parse({
|
|
198
|
+
provider: c.req.query("provider"),
|
|
130
199
|
scope: c.req.query("scope"),
|
|
131
200
|
projectPath: c.req.query("projectPath")
|
|
132
201
|
});
|
|
133
|
-
|
|
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
|
+
};
|
|
134
211
|
};
|
|
135
212
|
app.get("/", async (c) => {
|
|
136
213
|
const { q, paths } = ctx(c);
|
|
@@ -174,11 +251,19 @@ var SkillBodySchema = z2.object({
|
|
|
174
251
|
function skillRoutes(deps) {
|
|
175
252
|
const app = new Hono2();
|
|
176
253
|
const ctx = (c) => {
|
|
177
|
-
const q =
|
|
254
|
+
const q = ProviderScopeQuerySchema.parse({
|
|
255
|
+
provider: c.req.query("provider"),
|
|
178
256
|
scope: c.req.query("scope"),
|
|
179
257
|
projectPath: c.req.query("projectPath")
|
|
180
258
|
});
|
|
181
|
-
return {
|
|
259
|
+
return {
|
|
260
|
+
q,
|
|
261
|
+
paths: resolvePaths({
|
|
262
|
+
home: deps.home,
|
|
263
|
+
projectPath: q.projectPath,
|
|
264
|
+
provider: q.provider
|
|
265
|
+
})
|
|
266
|
+
};
|
|
182
267
|
};
|
|
183
268
|
app.get("/", async (c) => {
|
|
184
269
|
const { q, paths } = ctx(c);
|
|
@@ -205,13 +290,14 @@ function skillRoutes(deps) {
|
|
|
205
290
|
});
|
|
206
291
|
app.put("/:name/files/:filePath{.+}", async (c) => {
|
|
207
292
|
const { q, paths } = ctx(c);
|
|
208
|
-
const { content } = SkillFileWriteSchema.parse(await c.req.json());
|
|
293
|
+
const { content, baseMtime } = SkillFileWriteSchema.parse(await c.req.json());
|
|
209
294
|
await deps.skills.writeFileRaw(
|
|
210
295
|
paths,
|
|
211
296
|
q.scope,
|
|
212
297
|
c.req.param("name"),
|
|
213
298
|
c.req.param("filePath"),
|
|
214
|
-
content
|
|
299
|
+
content,
|
|
300
|
+
baseMtime
|
|
215
301
|
);
|
|
216
302
|
return c.json({ ok: true });
|
|
217
303
|
});
|
|
@@ -234,34 +320,72 @@ function skillRoutes(deps) {
|
|
|
234
320
|
});
|
|
235
321
|
app.post("/:name/toggle", async (c) => {
|
|
236
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
|
+
}
|
|
237
326
|
const { enabled } = await c.req.json();
|
|
238
327
|
await deps.skills.toggle(paths, q.scope, c.req.param("name"), enabled);
|
|
239
328
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
240
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
|
+
});
|
|
241
338
|
return app;
|
|
242
339
|
}
|
|
243
340
|
|
|
244
|
-
// src/server/routes/
|
|
341
|
+
// src/server/routes/shared-skills.ts
|
|
245
342
|
import { Hono as Hono3 } from "hono";
|
|
246
343
|
import { z as z3 } from "zod";
|
|
247
|
-
|
|
344
|
+
var SyncBodySchema = z3.object({ target: z3.enum(["claude", "codex"]) });
|
|
345
|
+
function sharedSkillRoutes(deps) {
|
|
248
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();
|
|
249
373
|
app.get("/", async (c) => c.json({ projects: await deps.projects.list() }));
|
|
250
374
|
app.post("/", async (c) => {
|
|
251
|
-
const { path } =
|
|
375
|
+
const { path } = z4.object({ path: z4.string().min(1) }).parse(await c.req.json());
|
|
252
376
|
return c.json({ projects: await deps.projects.add(path) });
|
|
253
377
|
});
|
|
254
378
|
app.delete("/", async (c) => {
|
|
255
|
-
const { path } =
|
|
379
|
+
const { path } = z4.object({ path: z4.string().min(1) }).parse(await c.req.json());
|
|
256
380
|
return c.json({ projects: await deps.projects.remove(path) });
|
|
257
381
|
});
|
|
258
382
|
return app;
|
|
259
383
|
}
|
|
260
384
|
|
|
261
385
|
// src/server/routes/memory.ts
|
|
262
|
-
import { Hono as
|
|
386
|
+
import { Hono as Hono5 } from "hono";
|
|
263
387
|
function memoryRoutes(deps) {
|
|
264
|
-
const app = new
|
|
388
|
+
const app = new Hono5();
|
|
265
389
|
const ctx = (c) => {
|
|
266
390
|
const q = ScopeQuerySchema.parse({
|
|
267
391
|
scope: c.req.query("scope"),
|
|
@@ -275,104 +399,172 @@ function memoryRoutes(deps) {
|
|
|
275
399
|
});
|
|
276
400
|
app.put("/", async (c) => {
|
|
277
401
|
const { q, paths } = ctx(c);
|
|
278
|
-
const { content } = MemoryWriteSchema.parse(await c.req.json());
|
|
279
|
-
await deps.memory.write(paths, q.scope, content);
|
|
402
|
+
const { content, baseMtime } = MemoryWriteSchema.parse(await c.req.json());
|
|
403
|
+
await deps.memory.write(paths, q.scope, content, baseMtime);
|
|
280
404
|
return c.json({ ok: true });
|
|
281
405
|
});
|
|
282
406
|
return app;
|
|
283
407
|
}
|
|
284
408
|
|
|
285
409
|
// src/server/routes/memory-files.ts
|
|
286
|
-
import { Hono as
|
|
287
|
-
import { z as
|
|
288
|
-
var
|
|
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) });
|
|
289
416
|
function memoryFilesRoutes(deps) {
|
|
290
|
-
const app = new
|
|
417
|
+
const app = new Hono6();
|
|
291
418
|
const ctx = (c) => {
|
|
292
|
-
const {
|
|
293
|
-
|
|
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
|
+
};
|
|
294
437
|
};
|
|
295
438
|
app.get("/", async (c) => {
|
|
296
|
-
const { projectPath, paths } = ctx(c);
|
|
297
|
-
return c.json(
|
|
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
|
+
);
|
|
298
443
|
});
|
|
299
444
|
app.get("/:file", async (c) => {
|
|
300
|
-
const { projectPath, paths } = ctx(c);
|
|
301
|
-
return c.json(
|
|
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
|
+
);
|
|
302
449
|
});
|
|
303
450
|
return app;
|
|
304
451
|
}
|
|
305
452
|
|
|
306
453
|
// src/server/routes/sessions.ts
|
|
307
|
-
import { Hono as
|
|
308
|
-
import { z as
|
|
309
|
-
var
|
|
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
|
+
});
|
|
310
460
|
function sessionRoutes(deps) {
|
|
311
|
-
const app = new
|
|
461
|
+
const app = new Hono7();
|
|
312
462
|
const ctx = (c) => {
|
|
313
|
-
const { projectPath } =
|
|
314
|
-
|
|
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
|
+
};
|
|
315
472
|
};
|
|
316
473
|
app.get("/", async (c) => {
|
|
317
|
-
const { projectPath, paths } = ctx(c);
|
|
318
|
-
return c.json(
|
|
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
|
+
);
|
|
319
478
|
});
|
|
320
479
|
app.get("/:id", async (c) => {
|
|
321
|
-
const { projectPath, paths } = ctx(c);
|
|
322
|
-
return c.json(
|
|
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
|
+
);
|
|
323
484
|
});
|
|
324
485
|
return app;
|
|
325
486
|
}
|
|
326
487
|
|
|
327
488
|
// src/server/routes/plugins.ts
|
|
328
|
-
import { Hono as
|
|
329
|
-
import { z as
|
|
330
|
-
var
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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)
|
|
334
501
|
});
|
|
335
502
|
function pluginRoutes(deps) {
|
|
336
|
-
const app = new
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
+
});
|
|
343
522
|
app.get("/:id/component", async (c) => {
|
|
523
|
+
const { provider, paths } = ctx(c);
|
|
344
524
|
const q = ComponentQuerySchema.parse({
|
|
345
525
|
type: c.req.query("type"),
|
|
346
526
|
name: c.req.query("name")
|
|
347
527
|
});
|
|
528
|
+
const svc = provider === "codex" ? deps.codexPlugins : deps.plugins;
|
|
348
529
|
return c.json(
|
|
349
|
-
await
|
|
350
|
-
paths(),
|
|
351
|
-
c.req.param("id"),
|
|
352
|
-
q.type,
|
|
353
|
-
q.name
|
|
354
|
-
)
|
|
530
|
+
await svc.readComponent(paths, c.req.param("id"), q.type, q.name)
|
|
355
531
|
);
|
|
356
532
|
});
|
|
357
533
|
app.patch("/:id", async (c) => {
|
|
358
|
-
const {
|
|
359
|
-
|
|
360
|
-
|
|
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));
|
|
361
547
|
});
|
|
362
548
|
return app;
|
|
363
549
|
}
|
|
364
550
|
|
|
365
551
|
// src/server/routes/config-files.ts
|
|
366
|
-
import { Hono as
|
|
552
|
+
import { Hono as Hono9 } from "hono";
|
|
367
553
|
function configFileRoutes(deps) {
|
|
368
|
-
const app = new
|
|
554
|
+
const app = new Hono9();
|
|
369
555
|
const ctx = (c) => {
|
|
370
556
|
const fileId = ConfigFileIdSchema.parse(c.req.param("file"));
|
|
371
|
-
const q =
|
|
557
|
+
const q = ProviderScopeQuerySchema.parse({
|
|
558
|
+
provider: c.req.query("provider"),
|
|
372
559
|
scope: c.req.query("scope"),
|
|
373
560
|
projectPath: c.req.query("projectPath")
|
|
374
561
|
});
|
|
375
|
-
|
|
562
|
+
McpProviderSchema.parse(q.provider);
|
|
563
|
+
return {
|
|
564
|
+
fileId,
|
|
565
|
+
q,
|
|
566
|
+
paths: resolvePaths({ home: deps.home, projectPath: q.projectPath, provider: q.provider })
|
|
567
|
+
};
|
|
376
568
|
};
|
|
377
569
|
app.get("/:file", async (c) => {
|
|
378
570
|
const { fileId, q, paths } = ctx(c);
|
|
@@ -380,20 +572,23 @@ function configFileRoutes(deps) {
|
|
|
380
572
|
});
|
|
381
573
|
app.put("/:file", async (c) => {
|
|
382
574
|
const { fileId, q, paths } = ctx(c);
|
|
383
|
-
const { content } = ConfigFileWriteSchema.parse(await c.req.json());
|
|
384
|
-
await deps.configFiles.write(paths, fileId, q.scope, content);
|
|
575
|
+
const { content, baseMtime } = ConfigFileWriteSchema.parse(await c.req.json());
|
|
576
|
+
await deps.configFiles.write(paths, fileId, q.scope, content, baseMtime);
|
|
385
577
|
return c.json({ ok: true });
|
|
386
578
|
});
|
|
387
579
|
return app;
|
|
388
580
|
}
|
|
389
581
|
|
|
390
582
|
// src/server/routes/agent-commands.ts
|
|
391
|
-
import { Hono as
|
|
392
|
-
import { z as
|
|
393
|
-
var CreateSchema =
|
|
394
|
-
var WriteSchema =
|
|
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()
|
|
589
|
+
});
|
|
395
590
|
function agentCommandRoutes(deps, kind) {
|
|
396
|
-
const app = new
|
|
591
|
+
const app = new Hono10();
|
|
397
592
|
const ctx = (c) => {
|
|
398
593
|
const q = ScopeQuerySchema.parse({
|
|
399
594
|
scope: c.req.query("scope"),
|
|
@@ -417,8 +612,8 @@ function agentCommandRoutes(deps, kind) {
|
|
|
417
612
|
});
|
|
418
613
|
app.put("/:name", async (c) => {
|
|
419
614
|
const { q, paths } = ctx(c);
|
|
420
|
-
const { content } = WriteSchema.parse(await c.req.json());
|
|
421
|
-
await deps.agentCommands.write(paths, kind, q.scope, c.req.param("name"), content);
|
|
615
|
+
const { content, baseMtime } = WriteSchema.parse(await c.req.json());
|
|
616
|
+
await deps.agentCommands.write(paths, kind, q.scope, c.req.param("name"), content, baseMtime);
|
|
422
617
|
return c.json({ ok: true });
|
|
423
618
|
});
|
|
424
619
|
app.delete("/:name", async (c) => {
|
|
@@ -431,7 +626,7 @@ function agentCommandRoutes(deps, kind) {
|
|
|
431
626
|
|
|
432
627
|
// src/server/app.ts
|
|
433
628
|
function createApp(deps) {
|
|
434
|
-
const app = new
|
|
629
|
+
const app = new Hono11();
|
|
435
630
|
app.onError((err, c) => {
|
|
436
631
|
if (err instanceof ZodError) {
|
|
437
632
|
return c.json({ error: "\u6821\u9A8C\u5931\u8D25", issues: err.issues }, 400);
|
|
@@ -442,10 +637,14 @@ function createApp(deps) {
|
|
|
442
637
|
if (err instanceof InvalidJsonError) {
|
|
443
638
|
return c.json({ error: err.message }, 400);
|
|
444
639
|
}
|
|
640
|
+
if (err instanceof ConflictError) {
|
|
641
|
+
return c.json({ error: err.message, code: "conflict" }, 409);
|
|
642
|
+
}
|
|
445
643
|
return c.json({ error: err.message }, 500);
|
|
446
644
|
});
|
|
447
645
|
app.route("/api/mcp", mcpRoutes(deps));
|
|
448
646
|
app.route("/api/skills", skillRoutes(deps));
|
|
647
|
+
app.route("/api/shared-skills", sharedSkillRoutes(deps));
|
|
449
648
|
app.route("/api/projects", projectRoutes(deps));
|
|
450
649
|
app.route("/api/memory", memoryRoutes(deps));
|
|
451
650
|
app.route("/api/memory-files", memoryFilesRoutes(deps));
|
|
@@ -459,8 +658,12 @@ function createApp(deps) {
|
|
|
459
658
|
}
|
|
460
659
|
|
|
461
660
|
export {
|
|
661
|
+
ConfigCorruptError,
|
|
462
662
|
InvalidJsonError,
|
|
463
663
|
ConfigStore,
|
|
664
|
+
ConflictError,
|
|
665
|
+
currentMtime,
|
|
666
|
+
assertNoConflict,
|
|
464
667
|
SkillFrontmatterSchema,
|
|
465
668
|
createApp
|
|
466
669
|
};
|