ccpanel 0.1.7 → 0.3.0
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/dist/{chunk-LZFMCC5M.js → chunk-BRKCF5YR.js} +144 -57
- package/dist/cli.js +108 -14
- package/dist/server/app.js +1 -1
- package/package.json +1 -1
- package/web/dist/assets/index-DSMyz76v.js +86 -0
- package/web/dist/assets/index-WWAjVQSr.css +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-4HCcippd.js +0 -85
- package/web/dist/assets/index-B5vT_l-U.css +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/server/app.ts
|
|
2
|
-
import { Hono as
|
|
2
|
+
import { Hono as Hono13 } from "hono";
|
|
3
3
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
4
4
|
import { ZodError } from "zod";
|
|
5
5
|
|
|
@@ -87,8 +87,8 @@ function resolvePaths(opts) {
|
|
|
87
87
|
const panelDir = join(home, ".ccpanel");
|
|
88
88
|
const codexDir = join(home, ".codex");
|
|
89
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");
|
|
90
|
+
const userSkillsDir = provider === "codex" ? join(codexDir, "skills") : provider === "agents" ? agentsSkillsDir : provider === "custom" ? opts.customSkillsDir ?? "" : join(home, ".claude", "skills");
|
|
91
|
+
const userDisabledSkillsDir = provider === "codex" ? join(panelDir, "codex-disabled-skills") : provider === "agents" ? join(panelDir, "agents-disabled-skills") : provider === "custom" ? join(panelDir, "custom-disabled-skills") : join(panelDir, "disabled-skills");
|
|
92
92
|
const paths = {
|
|
93
93
|
provider,
|
|
94
94
|
userClaudeJson: join(home, ".claude.json"),
|
|
@@ -130,7 +130,7 @@ function resolvePaths(opts) {
|
|
|
130
130
|
// src/shared/schemas.ts
|
|
131
131
|
import { z } from "zod";
|
|
132
132
|
var ScopeSchema = z.enum(["user", "project"]);
|
|
133
|
-
var ProviderSchema = z.enum(["claude", "codex", "agents"]);
|
|
133
|
+
var ProviderSchema = z.enum(["claude", "codex", "agents", "custom"]);
|
|
134
134
|
var McpProviderSchema = z.enum(["claude", "codex"]);
|
|
135
135
|
var ProviderScopeQuerySchema = z.object({
|
|
136
136
|
provider: ProviderSchema.default("claude"),
|
|
@@ -182,6 +182,17 @@ var ConfigFileWriteSchema = z.object({
|
|
|
182
182
|
content: z.string(),
|
|
183
183
|
baseMtime: BaseMtimeSchema
|
|
184
184
|
});
|
|
185
|
+
var ShellFileIdSchema = z.enum([
|
|
186
|
+
"bashrc",
|
|
187
|
+
"bash-profile",
|
|
188
|
+
"zshrc",
|
|
189
|
+
"zprofile",
|
|
190
|
+
"profile"
|
|
191
|
+
]);
|
|
192
|
+
var ShellFileWriteSchema = z.object({
|
|
193
|
+
content: z.string(),
|
|
194
|
+
baseMtime: BaseMtimeSchema
|
|
195
|
+
});
|
|
185
196
|
var ScopeQuerySchema = z.object({
|
|
186
197
|
scope: ScopeSchema,
|
|
187
198
|
projectPath: z.string().optional()
|
|
@@ -248,37 +259,43 @@ var SkillBodySchema = z2.object({
|
|
|
248
259
|
frontmatter: SkillFrontmatterSchema,
|
|
249
260
|
body: z2.string()
|
|
250
261
|
});
|
|
262
|
+
var MoveToDirBodySchema = z2.object({ targetDir: z2.string().min(1) });
|
|
263
|
+
function isVirtualProvider(p) {
|
|
264
|
+
return p === "agents" || p === "custom";
|
|
265
|
+
}
|
|
251
266
|
function skillRoutes(deps) {
|
|
252
267
|
const app = new Hono2();
|
|
253
|
-
const ctx = (c) => {
|
|
268
|
+
const ctx = async (c) => {
|
|
254
269
|
const q = ProviderScopeQuerySchema.parse({
|
|
255
270
|
provider: c.req.query("provider"),
|
|
256
271
|
scope: c.req.query("scope"),
|
|
257
272
|
projectPath: c.req.query("projectPath")
|
|
258
273
|
});
|
|
274
|
+
const customSkillsDir = q.provider === "custom" ? await deps.customSkillsDir.get() ?? void 0 : void 0;
|
|
259
275
|
return {
|
|
260
276
|
q,
|
|
261
277
|
paths: resolvePaths({
|
|
262
278
|
home: deps.home,
|
|
263
279
|
projectPath: q.projectPath,
|
|
264
|
-
provider: q.provider
|
|
280
|
+
provider: q.provider,
|
|
281
|
+
customSkillsDir
|
|
265
282
|
})
|
|
266
283
|
};
|
|
267
284
|
};
|
|
268
285
|
app.get("/", async (c) => {
|
|
269
|
-
const { q, paths } = ctx(c);
|
|
286
|
+
const { q, paths } = await ctx(c);
|
|
270
287
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
271
288
|
});
|
|
272
289
|
app.get("/:name", async (c) => {
|
|
273
|
-
const { q, paths } = ctx(c);
|
|
290
|
+
const { q, paths } = await ctx(c);
|
|
274
291
|
return c.json(await deps.skills.read(paths, q.scope, c.req.param("name")));
|
|
275
292
|
});
|
|
276
293
|
app.get("/:name/files", async (c) => {
|
|
277
|
-
const { q, paths } = ctx(c);
|
|
294
|
+
const { q, paths } = await ctx(c);
|
|
278
295
|
return c.json(await deps.skills.listFiles(paths, q.scope, c.req.param("name")));
|
|
279
296
|
});
|
|
280
297
|
app.get("/:name/files/:filePath{.+}", async (c) => {
|
|
281
|
-
const { q, paths } = ctx(c);
|
|
298
|
+
const { q, paths } = await ctx(c);
|
|
282
299
|
return c.json(
|
|
283
300
|
await deps.skills.readFileRaw(
|
|
284
301
|
paths,
|
|
@@ -289,7 +306,7 @@ function skillRoutes(deps) {
|
|
|
289
306
|
);
|
|
290
307
|
});
|
|
291
308
|
app.put("/:name/files/:filePath{.+}", async (c) => {
|
|
292
|
-
const { q, paths } = ctx(c);
|
|
309
|
+
const { q, paths } = await ctx(c);
|
|
293
310
|
const { content, baseMtime } = SkillFileWriteSchema.parse(await c.req.json());
|
|
294
311
|
await deps.skills.writeFileRaw(
|
|
295
312
|
paths,
|
|
@@ -302,25 +319,25 @@ function skillRoutes(deps) {
|
|
|
302
319
|
return c.json({ ok: true });
|
|
303
320
|
});
|
|
304
321
|
app.post("/", async (c) => {
|
|
305
|
-
const { q, paths } = ctx(c);
|
|
322
|
+
const { q, paths } = await ctx(c);
|
|
306
323
|
const data = SkillBodySchema.parse(await c.req.json());
|
|
307
324
|
await deps.skills.upsert(paths, q.scope, data.name, data.frontmatter, data.body);
|
|
308
325
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
309
326
|
});
|
|
310
327
|
app.put("/:name", async (c) => {
|
|
311
|
-
const { q, paths } = ctx(c);
|
|
328
|
+
const { q, paths } = await ctx(c);
|
|
312
329
|
const data = SkillBodySchema.parse({ ...await c.req.json(), name: c.req.param("name") });
|
|
313
330
|
await deps.skills.upsert(paths, q.scope, data.name, data.frontmatter, data.body);
|
|
314
331
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
315
332
|
});
|
|
316
333
|
app.delete("/:name", async (c) => {
|
|
317
|
-
const { q, paths } = ctx(c);
|
|
334
|
+
const { q, paths } = await ctx(c);
|
|
318
335
|
await deps.skills.remove(paths, q.scope, c.req.param("name"));
|
|
319
336
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
320
337
|
});
|
|
321
338
|
app.post("/:name/toggle", async (c) => {
|
|
322
|
-
const { q, paths } = ctx(c);
|
|
323
|
-
if (q.provider
|
|
339
|
+
const { q, paths } = await ctx(c);
|
|
340
|
+
if (isVirtualProvider(q.provider)) {
|
|
324
341
|
return c.json({ error: "\u516C\u5171 skills \u4E0D\u652F\u6301\u542F\u7528/\u7981\u7528" }, 400);
|
|
325
342
|
}
|
|
326
343
|
const { enabled } = await c.req.json();
|
|
@@ -328,13 +345,22 @@ function skillRoutes(deps) {
|
|
|
328
345
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
329
346
|
});
|
|
330
347
|
app.post("/:name/make-shared", async (c) => {
|
|
331
|
-
const { q } = ctx(c);
|
|
332
|
-
if (q.provider
|
|
348
|
+
const { q } = await ctx(c);
|
|
349
|
+
if (isVirtualProvider(q.provider)) {
|
|
333
350
|
return c.json({ error: "\u8F6C\u516C\u5171\u4EC5\u652F\u6301 claude/codex \u4E0B\u7684\u6280\u80FD" }, 400);
|
|
334
351
|
}
|
|
335
352
|
await deps.sync.makeShared(q.provider, c.req.param("name"));
|
|
336
353
|
return c.json({ ok: true });
|
|
337
354
|
});
|
|
355
|
+
app.post("/:name/move-to-dir", async (c) => {
|
|
356
|
+
const { q } = await ctx(c);
|
|
357
|
+
if (isVirtualProvider(q.provider)) {
|
|
358
|
+
return c.json({ error: "\u540C\u6B65\u5230\u76EE\u5F55\u4EC5\u652F\u6301 claude/codex \u4E0B\u7684\u6280\u80FD" }, 400);
|
|
359
|
+
}
|
|
360
|
+
const { targetDir } = MoveToDirBodySchema.parse(await c.req.json());
|
|
361
|
+
await deps.sync.linkToDirectory(q.provider, c.req.param("name"), targetDir);
|
|
362
|
+
return c.json({ ok: true });
|
|
363
|
+
});
|
|
338
364
|
return app;
|
|
339
365
|
}
|
|
340
366
|
|
|
@@ -365,31 +391,73 @@ function sharedSkillRoutes(deps) {
|
|
|
365
391
|
return app;
|
|
366
392
|
}
|
|
367
393
|
|
|
368
|
-
// src/server/routes/
|
|
394
|
+
// src/server/routes/custom-skills.ts
|
|
369
395
|
import { Hono as Hono4 } from "hono";
|
|
370
396
|
import { z as z4 } from "zod";
|
|
371
|
-
|
|
397
|
+
var SyncBodySchema2 = z4.object({ target: z4.enum(["claude", "codex"]) });
|
|
398
|
+
var DirBodySchema = z4.object({ path: z4.string().min(1) });
|
|
399
|
+
function customSkillRoutes(deps) {
|
|
372
400
|
const app = new Hono4();
|
|
401
|
+
app.get("/dir", async (c) => {
|
|
402
|
+
return c.json({ path: await deps.customSkillsDir.get() });
|
|
403
|
+
});
|
|
404
|
+
app.put("/dir", async (c) => {
|
|
405
|
+
const { path } = DirBodySchema.parse(await c.req.json());
|
|
406
|
+
await deps.customSkillsDir.set(path);
|
|
407
|
+
return c.json({ ok: true });
|
|
408
|
+
});
|
|
409
|
+
app.get("/", async (c) => {
|
|
410
|
+
const dir = await deps.customSkillsDir.get();
|
|
411
|
+
if (!dir) return c.json([]);
|
|
412
|
+
const paths = resolvePaths({ home: deps.home, provider: "custom", customSkillsDir: dir });
|
|
413
|
+
const base = await deps.skills.list(paths, "user");
|
|
414
|
+
const withSync = await Promise.all(
|
|
415
|
+
base.map(async (s) => ({ ...s, sync: await deps.sync.status(s.name, dir) }))
|
|
416
|
+
);
|
|
417
|
+
return c.json(withSync);
|
|
418
|
+
});
|
|
419
|
+
app.post("/:name/sync", async (c) => {
|
|
420
|
+
const dir = await deps.customSkillsDir.get();
|
|
421
|
+
if (!dir) return c.json({ error: "\u5C1A\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 skills \u76EE\u5F55" }, 400);
|
|
422
|
+
const { target } = SyncBodySchema2.parse(await c.req.json());
|
|
423
|
+
await deps.sync.syncTo(c.req.param("name"), target, dir);
|
|
424
|
+
return c.json({ ok: true });
|
|
425
|
+
});
|
|
426
|
+
app.delete("/:name/sync", async (c) => {
|
|
427
|
+
const dir = await deps.customSkillsDir.get();
|
|
428
|
+
if (!dir) return c.json({ error: "\u5C1A\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 skills \u76EE\u5F55" }, 400);
|
|
429
|
+
const { target } = SyncBodySchema2.parse(await c.req.json());
|
|
430
|
+
await deps.sync.unsync(c.req.param("name"), target, dir);
|
|
431
|
+
return c.json({ ok: true });
|
|
432
|
+
});
|
|
433
|
+
return app;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/server/routes/projects.ts
|
|
437
|
+
import { Hono as Hono5 } from "hono";
|
|
438
|
+
import { z as z5 } from "zod";
|
|
439
|
+
function projectRoutes(deps) {
|
|
440
|
+
const app = new Hono5();
|
|
373
441
|
app.get("/", async (c) => c.json({ projects: await deps.projects.list() }));
|
|
374
442
|
app.get(
|
|
375
443
|
"/known",
|
|
376
444
|
async (c) => c.json({ projects: await deps.projects.known() })
|
|
377
445
|
);
|
|
378
446
|
app.post("/", async (c) => {
|
|
379
|
-
const { path } =
|
|
447
|
+
const { path } = z5.object({ path: z5.string().min(1) }).parse(await c.req.json());
|
|
380
448
|
return c.json({ projects: await deps.projects.add(path) });
|
|
381
449
|
});
|
|
382
450
|
app.delete("/", async (c) => {
|
|
383
|
-
const { path } =
|
|
451
|
+
const { path } = z5.object({ path: z5.string().min(1) }).parse(await c.req.json());
|
|
384
452
|
return c.json({ projects: await deps.projects.remove(path) });
|
|
385
453
|
});
|
|
386
454
|
return app;
|
|
387
455
|
}
|
|
388
456
|
|
|
389
457
|
// src/server/routes/memory.ts
|
|
390
|
-
import { Hono as
|
|
458
|
+
import { Hono as Hono6 } from "hono";
|
|
391
459
|
function memoryRoutes(deps) {
|
|
392
|
-
const app = new
|
|
460
|
+
const app = new Hono6();
|
|
393
461
|
const ctx = (c) => {
|
|
394
462
|
const q = ScopeQuerySchema.parse({
|
|
395
463
|
scope: c.req.query("scope"),
|
|
@@ -411,14 +479,14 @@ function memoryRoutes(deps) {
|
|
|
411
479
|
}
|
|
412
480
|
|
|
413
481
|
// src/server/routes/memory-files.ts
|
|
414
|
-
import { Hono as
|
|
415
|
-
import { z as
|
|
416
|
-
var ProviderQuerySchema =
|
|
417
|
-
provider:
|
|
482
|
+
import { Hono as Hono7 } from "hono";
|
|
483
|
+
import { z as z6 } from "zod";
|
|
484
|
+
var ProviderQuerySchema = z6.object({
|
|
485
|
+
provider: z6.enum(["claude", "codex"]).default("claude")
|
|
418
486
|
});
|
|
419
|
-
var ClaudeQuerySchema =
|
|
487
|
+
var ClaudeQuerySchema = z6.object({ projectPath: z6.string().min(1) });
|
|
420
488
|
function memoryFilesRoutes(deps) {
|
|
421
|
-
const app = new
|
|
489
|
+
const app = new Hono7();
|
|
422
490
|
const ctx = (c) => {
|
|
423
491
|
const { provider } = ProviderQuerySchema.parse({
|
|
424
492
|
provider: c.req.query("provider") ?? "claude"
|
|
@@ -455,14 +523,14 @@ function memoryFilesRoutes(deps) {
|
|
|
455
523
|
}
|
|
456
524
|
|
|
457
525
|
// src/server/routes/sessions.ts
|
|
458
|
-
import { Hono as
|
|
459
|
-
import { z as
|
|
460
|
-
var QuerySchema =
|
|
461
|
-
provider:
|
|
462
|
-
projectPath:
|
|
526
|
+
import { Hono as Hono8 } from "hono";
|
|
527
|
+
import { z as z7 } from "zod";
|
|
528
|
+
var QuerySchema = z7.object({
|
|
529
|
+
provider: z7.enum(["claude", "codex"]).default("claude"),
|
|
530
|
+
projectPath: z7.string().min(1)
|
|
463
531
|
});
|
|
464
532
|
function sessionRoutes(deps) {
|
|
465
|
-
const app = new
|
|
533
|
+
const app = new Hono8();
|
|
466
534
|
const ctx = (c) => {
|
|
467
535
|
const { provider, projectPath } = QuerySchema.parse({
|
|
468
536
|
provider: c.req.query("provider") ?? "claude",
|
|
@@ -490,21 +558,21 @@ function sessionRoutes(deps) {
|
|
|
490
558
|
}
|
|
491
559
|
|
|
492
560
|
// src/server/routes/plugins.ts
|
|
493
|
-
import { Hono as
|
|
494
|
-
import { z as
|
|
495
|
-
var ProviderQuerySchema2 =
|
|
496
|
-
provider:
|
|
561
|
+
import { Hono as Hono9 } from "hono";
|
|
562
|
+
import { z as z8 } from "zod";
|
|
563
|
+
var ProviderQuerySchema2 = z8.object({
|
|
564
|
+
provider: z8.enum(["claude", "codex"]).default("claude")
|
|
497
565
|
});
|
|
498
|
-
var EnabledBodySchema =
|
|
499
|
-
enabled:
|
|
500
|
-
baseMtime:
|
|
566
|
+
var EnabledBodySchema = z8.object({
|
|
567
|
+
enabled: z8.boolean(),
|
|
568
|
+
baseMtime: z8.number().optional()
|
|
501
569
|
});
|
|
502
|
-
var ComponentQuerySchema =
|
|
503
|
-
type:
|
|
504
|
-
name:
|
|
570
|
+
var ComponentQuerySchema = z8.object({
|
|
571
|
+
type: z8.enum(["skill", "command", "agent", "hook", "mcp"]),
|
|
572
|
+
name: z8.string().min(1)
|
|
505
573
|
});
|
|
506
574
|
function pluginRoutes(deps) {
|
|
507
|
-
const app = new
|
|
575
|
+
const app = new Hono9();
|
|
508
576
|
const ctx = (c) => {
|
|
509
577
|
const { provider } = ProviderQuerySchema2.parse({
|
|
510
578
|
provider: c.req.query("provider") ?? "claude"
|
|
@@ -553,9 +621,9 @@ function pluginRoutes(deps) {
|
|
|
553
621
|
}
|
|
554
622
|
|
|
555
623
|
// src/server/routes/config-files.ts
|
|
556
|
-
import { Hono as
|
|
624
|
+
import { Hono as Hono10 } from "hono";
|
|
557
625
|
function configFileRoutes(deps) {
|
|
558
|
-
const app = new
|
|
626
|
+
const app = new Hono10();
|
|
559
627
|
const ctx = (c) => {
|
|
560
628
|
const fileId = ConfigFileIdSchema.parse(c.req.param("file"));
|
|
561
629
|
const q = ProviderScopeQuerySchema.parse({
|
|
@@ -584,15 +652,15 @@ function configFileRoutes(deps) {
|
|
|
584
652
|
}
|
|
585
653
|
|
|
586
654
|
// src/server/routes/agent-commands.ts
|
|
587
|
-
import { Hono as
|
|
588
|
-
import { z as
|
|
589
|
-
var CreateSchema =
|
|
590
|
-
var WriteSchema =
|
|
591
|
-
content:
|
|
592
|
-
baseMtime:
|
|
655
|
+
import { Hono as Hono11 } from "hono";
|
|
656
|
+
import { z as z9 } from "zod";
|
|
657
|
+
var CreateSchema = z9.object({ name: z9.string().min(1), content: z9.string() });
|
|
658
|
+
var WriteSchema = z9.object({
|
|
659
|
+
content: z9.string(),
|
|
660
|
+
baseMtime: z9.number().nullable().optional()
|
|
593
661
|
});
|
|
594
662
|
function agentCommandRoutes(deps, kind) {
|
|
595
|
-
const app = new
|
|
663
|
+
const app = new Hono11();
|
|
596
664
|
const ctx = (c) => {
|
|
597
665
|
const q = ScopeQuerySchema.parse({
|
|
598
666
|
scope: c.req.query("scope"),
|
|
@@ -628,9 +696,26 @@ function agentCommandRoutes(deps, kind) {
|
|
|
628
696
|
return app;
|
|
629
697
|
}
|
|
630
698
|
|
|
699
|
+
// src/server/routes/shell-files.ts
|
|
700
|
+
import { Hono as Hono12 } from "hono";
|
|
701
|
+
function shellFileRoutes(deps) {
|
|
702
|
+
const app = new Hono12();
|
|
703
|
+
app.get("/:file", async (c) => {
|
|
704
|
+
const fileId = ShellFileIdSchema.parse(c.req.param("file"));
|
|
705
|
+
return c.json(await deps.shellFiles.read(fileId));
|
|
706
|
+
});
|
|
707
|
+
app.put("/:file", async (c) => {
|
|
708
|
+
const fileId = ShellFileIdSchema.parse(c.req.param("file"));
|
|
709
|
+
const { content, baseMtime } = ShellFileWriteSchema.parse(await c.req.json());
|
|
710
|
+
await deps.shellFiles.write(fileId, content, baseMtime);
|
|
711
|
+
return c.json({ ok: true });
|
|
712
|
+
});
|
|
713
|
+
return app;
|
|
714
|
+
}
|
|
715
|
+
|
|
631
716
|
// src/server/app.ts
|
|
632
717
|
function createApp(deps) {
|
|
633
|
-
const app = new
|
|
718
|
+
const app = new Hono13();
|
|
634
719
|
app.onError((err, c) => {
|
|
635
720
|
if (err instanceof ZodError) {
|
|
636
721
|
return c.json({ error: "\u6821\u9A8C\u5931\u8D25", issues: err.issues }, 400);
|
|
@@ -649,12 +734,14 @@ function createApp(deps) {
|
|
|
649
734
|
app.route("/api/mcp", mcpRoutes(deps));
|
|
650
735
|
app.route("/api/skills", skillRoutes(deps));
|
|
651
736
|
app.route("/api/shared-skills", sharedSkillRoutes(deps));
|
|
737
|
+
app.route("/api/custom-skills", customSkillRoutes(deps));
|
|
652
738
|
app.route("/api/projects", projectRoutes(deps));
|
|
653
739
|
app.route("/api/memory", memoryRoutes(deps));
|
|
654
740
|
app.route("/api/memory-files", memoryFilesRoutes(deps));
|
|
655
741
|
app.route("/api/sessions", sessionRoutes(deps));
|
|
656
742
|
app.route("/api/plugins", pluginRoutes(deps));
|
|
657
743
|
app.route("/api/config-files", configFileRoutes(deps));
|
|
744
|
+
app.route("/api/shell-files", shellFileRoutes(deps));
|
|
658
745
|
app.route("/api/agents", agentCommandRoutes(deps, "agents"));
|
|
659
746
|
app.route("/api/commands", agentCommandRoutes(deps, "commands"));
|
|
660
747
|
app.use("/*", serveStatic({ root: deps.webRoot ?? "./web/dist" }));
|
package/dist/cli.js
CHANGED
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
assertNoConflict,
|
|
9
9
|
createApp,
|
|
10
10
|
currentMtime
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-BRKCF5YR.js";
|
|
12
12
|
|
|
13
13
|
// src/cli.ts
|
|
14
14
|
import { homedir, networkInterfaces } from "os";
|
|
15
|
-
import { join as
|
|
15
|
+
import { join as join14 } from "path";
|
|
16
16
|
import { createServer } from "net";
|
|
17
17
|
import { fileURLToPath } from "url";
|
|
18
18
|
import { realpathSync } from "fs";
|
|
@@ -1914,7 +1914,7 @@ var AgentCommandService = class {
|
|
|
1914
1914
|
|
|
1915
1915
|
// src/core/sync-service.ts
|
|
1916
1916
|
import { cp as cp2, lstat, mkdir as mkdir5, readlink as readlink2, rm as rm3, rmdir, stat as stat9, symlink, unlink } from "fs/promises";
|
|
1917
|
-
import { dirname as dirname5, join as join11, resolve as resolve7 } from "path";
|
|
1917
|
+
import { dirname as dirname5, isAbsolute as isAbsolute5, join as join11, resolve as resolve7 } from "path";
|
|
1918
1918
|
var SyncService = class {
|
|
1919
1919
|
agentsSkillsDir;
|
|
1920
1920
|
targets;
|
|
@@ -1943,7 +1943,7 @@ var SyncService = class {
|
|
|
1943
1943
|
const raw = await readlink2(p).catch(() => void 0);
|
|
1944
1944
|
return raw === void 0 ? void 0 : resolve7(dirname5(p), raw);
|
|
1945
1945
|
}
|
|
1946
|
-
async stateFor(targetDir, name) {
|
|
1946
|
+
async stateFor(targetDir, name, sourceDir) {
|
|
1947
1947
|
const p = join11(targetDir, name);
|
|
1948
1948
|
try {
|
|
1949
1949
|
await lstat(p);
|
|
@@ -1951,21 +1951,22 @@ var SyncService = class {
|
|
|
1951
1951
|
return "none";
|
|
1952
1952
|
}
|
|
1953
1953
|
const target = await this.linkTargetOf(p);
|
|
1954
|
-
if (target !== void 0 && isSameLink(target, join11(
|
|
1954
|
+
if (target !== void 0 && isSameLink(target, join11(sourceDir, name))) {
|
|
1955
1955
|
return "linked";
|
|
1956
1956
|
}
|
|
1957
1957
|
return "conflict";
|
|
1958
1958
|
}
|
|
1959
|
-
|
|
1959
|
+
// sourceDir 缺省为 ~/.agents/skills(原「公共」目录);传入其他目录可复用同一套逻辑管理自定义公共目录。
|
|
1960
|
+
async status(name, sourceDir = this.agentsSkillsDir) {
|
|
1960
1961
|
assertSafeName(name);
|
|
1961
1962
|
return {
|
|
1962
|
-
claude: await this.stateFor(this.targets.claude, name),
|
|
1963
|
-
codex: await this.stateFor(this.targets.codex, name)
|
|
1963
|
+
claude: await this.stateFor(this.targets.claude, name, sourceDir),
|
|
1964
|
+
codex: await this.stateFor(this.targets.codex, name, sourceDir)
|
|
1964
1965
|
};
|
|
1965
1966
|
}
|
|
1966
|
-
async syncTo(name, target) {
|
|
1967
|
+
async syncTo(name, target, sourceDir = this.agentsSkillsDir) {
|
|
1967
1968
|
assertSafeName(name);
|
|
1968
|
-
const src = join11(
|
|
1969
|
+
const src = join11(sourceDir, name);
|
|
1969
1970
|
try {
|
|
1970
1971
|
if (!(await stat9(src)).isDirectory()) throw new Error();
|
|
1971
1972
|
} catch {
|
|
@@ -1981,11 +1982,11 @@ var SyncService = class {
|
|
|
1981
1982
|
await mkdir5(this.targets[target], { recursive: true });
|
|
1982
1983
|
await symlink(src, dest, "junction");
|
|
1983
1984
|
}
|
|
1984
|
-
async unsync(name, target) {
|
|
1985
|
+
async unsync(name, target, sourceDir = this.agentsSkillsDir) {
|
|
1985
1986
|
assertSafeName(name);
|
|
1986
1987
|
const dest = join11(this.targets[target], name);
|
|
1987
1988
|
const linkTarget = await this.linkTargetOf(dest);
|
|
1988
|
-
if (linkTarget === void 0 || !isSameLink(linkTarget, join11(
|
|
1989
|
+
if (linkTarget === void 0 || !isSameLink(linkTarget, join11(sourceDir, name))) {
|
|
1989
1990
|
throw new Error(`\u300C${name}\u300D\u4E0D\u662F\u6307\u5411\u516C\u5171\u76EE\u5F55\u7684\u94FE\u63A5\uFF0C\u62D2\u7EDD\u5220\u9664`);
|
|
1990
1991
|
}
|
|
1991
1992
|
await this.removeLink(dest);
|
|
@@ -2024,6 +2025,97 @@ var SyncService = class {
|
|
|
2024
2025
|
throw err;
|
|
2025
2026
|
}
|
|
2026
2027
|
}
|
|
2028
|
+
// 把 provider 下的 skill 移动到用户指定的任意目录,并在原路径创建指回它的链接。
|
|
2029
|
+
async linkToDirectory(provider, name, targetDir) {
|
|
2030
|
+
assertSafeName(name);
|
|
2031
|
+
if (!isAbsolute5(targetDir)) throw new Error("\u76EE\u6807\u76EE\u5F55\u987B\u4E3A\u7EDD\u5BF9\u8DEF\u5F84");
|
|
2032
|
+
const src = join11(this.targets[provider], name);
|
|
2033
|
+
let st;
|
|
2034
|
+
try {
|
|
2035
|
+
st = await lstat(src);
|
|
2036
|
+
} catch {
|
|
2037
|
+
throw new Error(`\u672A\u627E\u5230 skill\u300C${name}\u300D\uFF08\u987B\u4E3A\u542F\u7528\u72B6\u6001\uFF09`);
|
|
2038
|
+
}
|
|
2039
|
+
if (st.isSymbolicLink()) {
|
|
2040
|
+
throw new Error(`\u300C${name}\u300D\u5DF2\u7ECF\u662F\u94FE\u63A5\uFF0C\u65E0\u6CD5\u518D\u6B21\u540C\u6B65`);
|
|
2041
|
+
}
|
|
2042
|
+
const dest = join11(resolve7(targetDir), name);
|
|
2043
|
+
if (resolve7(dest) === resolve7(src)) {
|
|
2044
|
+
throw new Error("\u76EE\u6807\u76EE\u5F55\u4E0D\u80FD\u4E0E\u6280\u80FD\u5F53\u524D\u6240\u5728\u76EE\u5F55\u76F8\u540C");
|
|
2045
|
+
}
|
|
2046
|
+
try {
|
|
2047
|
+
await lstat(dest);
|
|
2048
|
+
throw new ConflictError(`\u76EE\u6807\u76EE\u5F55\u5DF2\u5B58\u5728\u540C\u540D\u6761\u76EE\u300C${name}\u300D`);
|
|
2049
|
+
} catch (err) {
|
|
2050
|
+
if (err instanceof ConflictError) throw err;
|
|
2051
|
+
}
|
|
2052
|
+
await mkdir5(resolve7(targetDir), { recursive: true });
|
|
2053
|
+
await cp2(src, dest, { recursive: true });
|
|
2054
|
+
await rm3(src, { recursive: true, force: true });
|
|
2055
|
+
try {
|
|
2056
|
+
await symlink(dest, src, "junction");
|
|
2057
|
+
} catch (err) {
|
|
2058
|
+
await cp2(dest, src, { recursive: true });
|
|
2059
|
+
await rm3(dest, { recursive: true, force: true });
|
|
2060
|
+
throw err;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
};
|
|
2064
|
+
|
|
2065
|
+
// src/core/shell-file-service.ts
|
|
2066
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
2067
|
+
import { join as join12 } from "path";
|
|
2068
|
+
var FILE_NAMES = {
|
|
2069
|
+
bashrc: ".bashrc",
|
|
2070
|
+
"bash-profile": ".bash_profile",
|
|
2071
|
+
zshrc: ".zshrc",
|
|
2072
|
+
zprofile: ".zprofile",
|
|
2073
|
+
profile: ".profile"
|
|
2074
|
+
};
|
|
2075
|
+
var ShellFileService = class {
|
|
2076
|
+
constructor(store, home) {
|
|
2077
|
+
this.store = store;
|
|
2078
|
+
this.home = home;
|
|
2079
|
+
}
|
|
2080
|
+
store;
|
|
2081
|
+
home;
|
|
2082
|
+
path(fileId) {
|
|
2083
|
+
return join12(this.home, FILE_NAMES[fileId]);
|
|
2084
|
+
}
|
|
2085
|
+
// 文件不存在视为「尚未创建」,返回空串与 null mtime(与 ConfigFileService 一致)。
|
|
2086
|
+
async read(fileId) {
|
|
2087
|
+
const file = this.path(fileId);
|
|
2088
|
+
try {
|
|
2089
|
+
return { content: await readFile12(file, "utf8"), mtime: await currentMtime(file) };
|
|
2090
|
+
} catch (err) {
|
|
2091
|
+
if (err.code === "ENOENT") return { content: "", mtime: null };
|
|
2092
|
+
throw err;
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
async write(fileId, content, baseMtime) {
|
|
2096
|
+
const file = this.path(fileId);
|
|
2097
|
+
await assertNoConflict(file, baseMtime);
|
|
2098
|
+
await this.store.writeText(file, content);
|
|
2099
|
+
}
|
|
2100
|
+
};
|
|
2101
|
+
|
|
2102
|
+
// src/core/custom-skills-dir-service.ts
|
|
2103
|
+
import { isAbsolute as isAbsolute6, join as join13 } from "path";
|
|
2104
|
+
var CustomSkillsDirService = class {
|
|
2105
|
+
constructor(store, home) {
|
|
2106
|
+
this.store = store;
|
|
2107
|
+
this.file = join13(home, ".ccpanel", "custom-skills-dir.json");
|
|
2108
|
+
}
|
|
2109
|
+
store;
|
|
2110
|
+
file;
|
|
2111
|
+
async get() {
|
|
2112
|
+
const data = await this.store.readJson(this.file);
|
|
2113
|
+
return data?.path ?? null;
|
|
2114
|
+
}
|
|
2115
|
+
async set(path) {
|
|
2116
|
+
if (!isAbsolute6(path)) throw new Error("\u76EE\u5F55\u987B\u4E3A\u7EDD\u5BF9\u8DEF\u5F84");
|
|
2117
|
+
await this.store.writeJson(this.file, { path });
|
|
2118
|
+
}
|
|
2027
2119
|
};
|
|
2028
2120
|
|
|
2029
2121
|
// src/cli.ts
|
|
@@ -2042,14 +2134,14 @@ function findFreePort(start) {
|
|
|
2042
2134
|
async function main() {
|
|
2043
2135
|
const home = homedir();
|
|
2044
2136
|
const store = new ConfigStore();
|
|
2045
|
-
const registryFile =
|
|
2137
|
+
const registryFile = join14(home, ".ccpanel", "ccpanel-projects.json");
|
|
2046
2138
|
const webRoot = fileURLToPath(new URL("../web/dist", import.meta.url));
|
|
2047
2139
|
const app = createApp({
|
|
2048
2140
|
home,
|
|
2049
2141
|
store,
|
|
2050
2142
|
mcp: new McpService(store),
|
|
2051
2143
|
skills: new SkillService(),
|
|
2052
|
-
projects: new ProjectService(store, registryFile,
|
|
2144
|
+
projects: new ProjectService(store, registryFile, join14(home, ".claude.json")),
|
|
2053
2145
|
memory: new MemoryService(),
|
|
2054
2146
|
memoryFiles: new MemoryFilesService(),
|
|
2055
2147
|
sessions: new SessionService(),
|
|
@@ -2060,6 +2152,8 @@ async function main() {
|
|
|
2060
2152
|
configFiles: new ConfigFileService(store),
|
|
2061
2153
|
agentCommands: new AgentCommandService(),
|
|
2062
2154
|
sync: new SyncService(home),
|
|
2155
|
+
shellFiles: new ShellFileService(store, home),
|
|
2156
|
+
customSkillsDir: new CustomSkillsDirService(store, home),
|
|
2063
2157
|
registryFile,
|
|
2064
2158
|
webRoot
|
|
2065
2159
|
});
|
package/dist/server/app.js
CHANGED