ccpanel 0.2.0 → 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-ENKQJGKM.js → chunk-BRKCF5YR.js} +117 -59
- package/dist/cli.js +70 -14
- package/dist/server/app.js +1 -1
- package/package.json +1 -1
- package/web/dist/assets/{index-Dfwkr7BM.js → index-DSMyz76v.js} +29 -28
- package/web/dist/assets/index-WWAjVQSr.css +1 -0
- package/web/dist/index.html +2 -2
- 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"),
|
|
@@ -259,37 +259,43 @@ var SkillBodySchema = z2.object({
|
|
|
259
259
|
frontmatter: SkillFrontmatterSchema,
|
|
260
260
|
body: z2.string()
|
|
261
261
|
});
|
|
262
|
+
var MoveToDirBodySchema = z2.object({ targetDir: z2.string().min(1) });
|
|
263
|
+
function isVirtualProvider(p) {
|
|
264
|
+
return p === "agents" || p === "custom";
|
|
265
|
+
}
|
|
262
266
|
function skillRoutes(deps) {
|
|
263
267
|
const app = new Hono2();
|
|
264
|
-
const ctx = (c) => {
|
|
268
|
+
const ctx = async (c) => {
|
|
265
269
|
const q = ProviderScopeQuerySchema.parse({
|
|
266
270
|
provider: c.req.query("provider"),
|
|
267
271
|
scope: c.req.query("scope"),
|
|
268
272
|
projectPath: c.req.query("projectPath")
|
|
269
273
|
});
|
|
274
|
+
const customSkillsDir = q.provider === "custom" ? await deps.customSkillsDir.get() ?? void 0 : void 0;
|
|
270
275
|
return {
|
|
271
276
|
q,
|
|
272
277
|
paths: resolvePaths({
|
|
273
278
|
home: deps.home,
|
|
274
279
|
projectPath: q.projectPath,
|
|
275
|
-
provider: q.provider
|
|
280
|
+
provider: q.provider,
|
|
281
|
+
customSkillsDir
|
|
276
282
|
})
|
|
277
283
|
};
|
|
278
284
|
};
|
|
279
285
|
app.get("/", async (c) => {
|
|
280
|
-
const { q, paths } = ctx(c);
|
|
286
|
+
const { q, paths } = await ctx(c);
|
|
281
287
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
282
288
|
});
|
|
283
289
|
app.get("/:name", async (c) => {
|
|
284
|
-
const { q, paths } = ctx(c);
|
|
290
|
+
const { q, paths } = await ctx(c);
|
|
285
291
|
return c.json(await deps.skills.read(paths, q.scope, c.req.param("name")));
|
|
286
292
|
});
|
|
287
293
|
app.get("/:name/files", async (c) => {
|
|
288
|
-
const { q, paths } = ctx(c);
|
|
294
|
+
const { q, paths } = await ctx(c);
|
|
289
295
|
return c.json(await deps.skills.listFiles(paths, q.scope, c.req.param("name")));
|
|
290
296
|
});
|
|
291
297
|
app.get("/:name/files/:filePath{.+}", async (c) => {
|
|
292
|
-
const { q, paths } = ctx(c);
|
|
298
|
+
const { q, paths } = await ctx(c);
|
|
293
299
|
return c.json(
|
|
294
300
|
await deps.skills.readFileRaw(
|
|
295
301
|
paths,
|
|
@@ -300,7 +306,7 @@ function skillRoutes(deps) {
|
|
|
300
306
|
);
|
|
301
307
|
});
|
|
302
308
|
app.put("/:name/files/:filePath{.+}", async (c) => {
|
|
303
|
-
const { q, paths } = ctx(c);
|
|
309
|
+
const { q, paths } = await ctx(c);
|
|
304
310
|
const { content, baseMtime } = SkillFileWriteSchema.parse(await c.req.json());
|
|
305
311
|
await deps.skills.writeFileRaw(
|
|
306
312
|
paths,
|
|
@@ -313,25 +319,25 @@ function skillRoutes(deps) {
|
|
|
313
319
|
return c.json({ ok: true });
|
|
314
320
|
});
|
|
315
321
|
app.post("/", async (c) => {
|
|
316
|
-
const { q, paths } = ctx(c);
|
|
322
|
+
const { q, paths } = await ctx(c);
|
|
317
323
|
const data = SkillBodySchema.parse(await c.req.json());
|
|
318
324
|
await deps.skills.upsert(paths, q.scope, data.name, data.frontmatter, data.body);
|
|
319
325
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
320
326
|
});
|
|
321
327
|
app.put("/:name", async (c) => {
|
|
322
|
-
const { q, paths } = ctx(c);
|
|
328
|
+
const { q, paths } = await ctx(c);
|
|
323
329
|
const data = SkillBodySchema.parse({ ...await c.req.json(), name: c.req.param("name") });
|
|
324
330
|
await deps.skills.upsert(paths, q.scope, data.name, data.frontmatter, data.body);
|
|
325
331
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
326
332
|
});
|
|
327
333
|
app.delete("/:name", async (c) => {
|
|
328
|
-
const { q, paths } = ctx(c);
|
|
334
|
+
const { q, paths } = await ctx(c);
|
|
329
335
|
await deps.skills.remove(paths, q.scope, c.req.param("name"));
|
|
330
336
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
331
337
|
});
|
|
332
338
|
app.post("/:name/toggle", async (c) => {
|
|
333
|
-
const { q, paths } = ctx(c);
|
|
334
|
-
if (q.provider
|
|
339
|
+
const { q, paths } = await ctx(c);
|
|
340
|
+
if (isVirtualProvider(q.provider)) {
|
|
335
341
|
return c.json({ error: "\u516C\u5171 skills \u4E0D\u652F\u6301\u542F\u7528/\u7981\u7528" }, 400);
|
|
336
342
|
}
|
|
337
343
|
const { enabled } = await c.req.json();
|
|
@@ -339,13 +345,22 @@ function skillRoutes(deps) {
|
|
|
339
345
|
return c.json(await deps.skills.list(paths, q.scope));
|
|
340
346
|
});
|
|
341
347
|
app.post("/:name/make-shared", async (c) => {
|
|
342
|
-
const { q } = ctx(c);
|
|
343
|
-
if (q.provider
|
|
348
|
+
const { q } = await ctx(c);
|
|
349
|
+
if (isVirtualProvider(q.provider)) {
|
|
344
350
|
return c.json({ error: "\u8F6C\u516C\u5171\u4EC5\u652F\u6301 claude/codex \u4E0B\u7684\u6280\u80FD" }, 400);
|
|
345
351
|
}
|
|
346
352
|
await deps.sync.makeShared(q.provider, c.req.param("name"));
|
|
347
353
|
return c.json({ ok: true });
|
|
348
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
|
+
});
|
|
349
364
|
return app;
|
|
350
365
|
}
|
|
351
366
|
|
|
@@ -376,31 +391,73 @@ function sharedSkillRoutes(deps) {
|
|
|
376
391
|
return app;
|
|
377
392
|
}
|
|
378
393
|
|
|
379
|
-
// src/server/routes/
|
|
394
|
+
// src/server/routes/custom-skills.ts
|
|
380
395
|
import { Hono as Hono4 } from "hono";
|
|
381
396
|
import { z as z4 } from "zod";
|
|
382
|
-
|
|
397
|
+
var SyncBodySchema2 = z4.object({ target: z4.enum(["claude", "codex"]) });
|
|
398
|
+
var DirBodySchema = z4.object({ path: z4.string().min(1) });
|
|
399
|
+
function customSkillRoutes(deps) {
|
|
383
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();
|
|
384
441
|
app.get("/", async (c) => c.json({ projects: await deps.projects.list() }));
|
|
385
442
|
app.get(
|
|
386
443
|
"/known",
|
|
387
444
|
async (c) => c.json({ projects: await deps.projects.known() })
|
|
388
445
|
);
|
|
389
446
|
app.post("/", async (c) => {
|
|
390
|
-
const { path } =
|
|
447
|
+
const { path } = z5.object({ path: z5.string().min(1) }).parse(await c.req.json());
|
|
391
448
|
return c.json({ projects: await deps.projects.add(path) });
|
|
392
449
|
});
|
|
393
450
|
app.delete("/", async (c) => {
|
|
394
|
-
const { path } =
|
|
451
|
+
const { path } = z5.object({ path: z5.string().min(1) }).parse(await c.req.json());
|
|
395
452
|
return c.json({ projects: await deps.projects.remove(path) });
|
|
396
453
|
});
|
|
397
454
|
return app;
|
|
398
455
|
}
|
|
399
456
|
|
|
400
457
|
// src/server/routes/memory.ts
|
|
401
|
-
import { Hono as
|
|
458
|
+
import { Hono as Hono6 } from "hono";
|
|
402
459
|
function memoryRoutes(deps) {
|
|
403
|
-
const app = new
|
|
460
|
+
const app = new Hono6();
|
|
404
461
|
const ctx = (c) => {
|
|
405
462
|
const q = ScopeQuerySchema.parse({
|
|
406
463
|
scope: c.req.query("scope"),
|
|
@@ -422,14 +479,14 @@ function memoryRoutes(deps) {
|
|
|
422
479
|
}
|
|
423
480
|
|
|
424
481
|
// src/server/routes/memory-files.ts
|
|
425
|
-
import { Hono as
|
|
426
|
-
import { z as
|
|
427
|
-
var ProviderQuerySchema =
|
|
428
|
-
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")
|
|
429
486
|
});
|
|
430
|
-
var ClaudeQuerySchema =
|
|
487
|
+
var ClaudeQuerySchema = z6.object({ projectPath: z6.string().min(1) });
|
|
431
488
|
function memoryFilesRoutes(deps) {
|
|
432
|
-
const app = new
|
|
489
|
+
const app = new Hono7();
|
|
433
490
|
const ctx = (c) => {
|
|
434
491
|
const { provider } = ProviderQuerySchema.parse({
|
|
435
492
|
provider: c.req.query("provider") ?? "claude"
|
|
@@ -466,14 +523,14 @@ function memoryFilesRoutes(deps) {
|
|
|
466
523
|
}
|
|
467
524
|
|
|
468
525
|
// src/server/routes/sessions.ts
|
|
469
|
-
import { Hono as
|
|
470
|
-
import { z as
|
|
471
|
-
var QuerySchema =
|
|
472
|
-
provider:
|
|
473
|
-
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)
|
|
474
531
|
});
|
|
475
532
|
function sessionRoutes(deps) {
|
|
476
|
-
const app = new
|
|
533
|
+
const app = new Hono8();
|
|
477
534
|
const ctx = (c) => {
|
|
478
535
|
const { provider, projectPath } = QuerySchema.parse({
|
|
479
536
|
provider: c.req.query("provider") ?? "claude",
|
|
@@ -501,21 +558,21 @@ function sessionRoutes(deps) {
|
|
|
501
558
|
}
|
|
502
559
|
|
|
503
560
|
// src/server/routes/plugins.ts
|
|
504
|
-
import { Hono as
|
|
505
|
-
import { z as
|
|
506
|
-
var ProviderQuerySchema2 =
|
|
507
|
-
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")
|
|
508
565
|
});
|
|
509
|
-
var EnabledBodySchema =
|
|
510
|
-
enabled:
|
|
511
|
-
baseMtime:
|
|
566
|
+
var EnabledBodySchema = z8.object({
|
|
567
|
+
enabled: z8.boolean(),
|
|
568
|
+
baseMtime: z8.number().optional()
|
|
512
569
|
});
|
|
513
|
-
var ComponentQuerySchema =
|
|
514
|
-
type:
|
|
515
|
-
name:
|
|
570
|
+
var ComponentQuerySchema = z8.object({
|
|
571
|
+
type: z8.enum(["skill", "command", "agent", "hook", "mcp"]),
|
|
572
|
+
name: z8.string().min(1)
|
|
516
573
|
});
|
|
517
574
|
function pluginRoutes(deps) {
|
|
518
|
-
const app = new
|
|
575
|
+
const app = new Hono9();
|
|
519
576
|
const ctx = (c) => {
|
|
520
577
|
const { provider } = ProviderQuerySchema2.parse({
|
|
521
578
|
provider: c.req.query("provider") ?? "claude"
|
|
@@ -564,9 +621,9 @@ function pluginRoutes(deps) {
|
|
|
564
621
|
}
|
|
565
622
|
|
|
566
623
|
// src/server/routes/config-files.ts
|
|
567
|
-
import { Hono as
|
|
624
|
+
import { Hono as Hono10 } from "hono";
|
|
568
625
|
function configFileRoutes(deps) {
|
|
569
|
-
const app = new
|
|
626
|
+
const app = new Hono10();
|
|
570
627
|
const ctx = (c) => {
|
|
571
628
|
const fileId = ConfigFileIdSchema.parse(c.req.param("file"));
|
|
572
629
|
const q = ProviderScopeQuerySchema.parse({
|
|
@@ -595,15 +652,15 @@ function configFileRoutes(deps) {
|
|
|
595
652
|
}
|
|
596
653
|
|
|
597
654
|
// src/server/routes/agent-commands.ts
|
|
598
|
-
import { Hono as
|
|
599
|
-
import { z as
|
|
600
|
-
var CreateSchema =
|
|
601
|
-
var WriteSchema =
|
|
602
|
-
content:
|
|
603
|
-
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()
|
|
604
661
|
});
|
|
605
662
|
function agentCommandRoutes(deps, kind) {
|
|
606
|
-
const app = new
|
|
663
|
+
const app = new Hono11();
|
|
607
664
|
const ctx = (c) => {
|
|
608
665
|
const q = ScopeQuerySchema.parse({
|
|
609
666
|
scope: c.req.query("scope"),
|
|
@@ -640,9 +697,9 @@ function agentCommandRoutes(deps, kind) {
|
|
|
640
697
|
}
|
|
641
698
|
|
|
642
699
|
// src/server/routes/shell-files.ts
|
|
643
|
-
import { Hono as
|
|
700
|
+
import { Hono as Hono12 } from "hono";
|
|
644
701
|
function shellFileRoutes(deps) {
|
|
645
|
-
const app = new
|
|
702
|
+
const app = new Hono12();
|
|
646
703
|
app.get("/:file", async (c) => {
|
|
647
704
|
const fileId = ShellFileIdSchema.parse(c.req.param("file"));
|
|
648
705
|
return c.json(await deps.shellFiles.read(fileId));
|
|
@@ -658,7 +715,7 @@ function shellFileRoutes(deps) {
|
|
|
658
715
|
|
|
659
716
|
// src/server/app.ts
|
|
660
717
|
function createApp(deps) {
|
|
661
|
-
const app = new
|
|
718
|
+
const app = new Hono13();
|
|
662
719
|
app.onError((err, c) => {
|
|
663
720
|
if (err instanceof ZodError) {
|
|
664
721
|
return c.json({ error: "\u6821\u9A8C\u5931\u8D25", issues: err.issues }, 400);
|
|
@@ -677,6 +734,7 @@ function createApp(deps) {
|
|
|
677
734
|
app.route("/api/mcp", mcpRoutes(deps));
|
|
678
735
|
app.route("/api/skills", skillRoutes(deps));
|
|
679
736
|
app.route("/api/shared-skills", sharedSkillRoutes(deps));
|
|
737
|
+
app.route("/api/custom-skills", customSkillRoutes(deps));
|
|
680
738
|
app.route("/api/projects", projectRoutes(deps));
|
|
681
739
|
app.route("/api/memory", memoryRoutes(deps));
|
|
682
740
|
app.route("/api/memory-files", memoryFilesRoutes(deps));
|
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,41 @@ 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
|
+
}
|
|
2027
2063
|
};
|
|
2028
2064
|
|
|
2029
2065
|
// src/core/shell-file-service.ts
|
|
@@ -2063,6 +2099,25 @@ var ShellFileService = class {
|
|
|
2063
2099
|
}
|
|
2064
2100
|
};
|
|
2065
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
|
+
}
|
|
2119
|
+
};
|
|
2120
|
+
|
|
2066
2121
|
// src/cli.ts
|
|
2067
2122
|
function findFreePort(start) {
|
|
2068
2123
|
return new Promise((resolve8, reject) => {
|
|
@@ -2079,14 +2134,14 @@ function findFreePort(start) {
|
|
|
2079
2134
|
async function main() {
|
|
2080
2135
|
const home = homedir();
|
|
2081
2136
|
const store = new ConfigStore();
|
|
2082
|
-
const registryFile =
|
|
2137
|
+
const registryFile = join14(home, ".ccpanel", "ccpanel-projects.json");
|
|
2083
2138
|
const webRoot = fileURLToPath(new URL("../web/dist", import.meta.url));
|
|
2084
2139
|
const app = createApp({
|
|
2085
2140
|
home,
|
|
2086
2141
|
store,
|
|
2087
2142
|
mcp: new McpService(store),
|
|
2088
2143
|
skills: new SkillService(),
|
|
2089
|
-
projects: new ProjectService(store, registryFile,
|
|
2144
|
+
projects: new ProjectService(store, registryFile, join14(home, ".claude.json")),
|
|
2090
2145
|
memory: new MemoryService(),
|
|
2091
2146
|
memoryFiles: new MemoryFilesService(),
|
|
2092
2147
|
sessions: new SessionService(),
|
|
@@ -2098,6 +2153,7 @@ async function main() {
|
|
|
2098
2153
|
agentCommands: new AgentCommandService(),
|
|
2099
2154
|
sync: new SyncService(home),
|
|
2100
2155
|
shellFiles: new ShellFileService(store, home),
|
|
2156
|
+
customSkillsDir: new CustomSkillsDirService(store, home),
|
|
2101
2157
|
registryFile,
|
|
2102
2158
|
webRoot
|
|
2103
2159
|
});
|
package/dist/server/app.js
CHANGED