@daweifu/capability-menu 0.1.2 → 0.1.3
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.en.md +39 -18
- package/README.md +46 -25
- package/cordis.patch.yml +15 -24
- package/lib/client.d.ts +211 -32
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +1510 -158
- package/lib/constants.js +33 -0
- package/lib/constants.js.map +1 -0
- package/lib/index.js +1 -1
- package/lib/locations.js +541 -0
- package/lib/locations.js.map +1 -0
- package/lib/patch-file.js +192 -0
- package/lib/patch-file.js.map +1 -0
- package/lib/policy.js +211 -27
- package/lib/policy.js.map +1 -1
- package/lib/registry.js +256 -38
- package/lib/registry.js.map +1 -1
- package/lib/search.js +10 -2
- package/lib/search.js.map +1 -1
- package/lib/server/remote.js +137 -4
- package/lib/server/remote.js.map +1 -1
- package/lib/types/constants.d.ts +33 -0
- package/lib/types/constants.d.ts.map +1 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/locations.d.ts +142 -0
- package/lib/types/locations.d.ts.map +1 -0
- package/lib/types/patch-file.d.ts +46 -0
- package/lib/types/patch-file.d.ts.map +1 -0
- package/lib/types/policy.d.ts +39 -0
- package/lib/types/policy.d.ts.map +1 -1
- package/lib/types/registry.d.ts +48 -16
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/search.d.ts.map +1 -1
- package/lib/types/server/remote.d.ts +47 -2
- package/lib/types/server/remote.d.ts.map +1 -1
- package/package.json +24 -23
package/lib/client.js
CHANGED
|
@@ -284,7 +284,7 @@ function prefixIssues(path, issues) {
|
|
|
284
284
|
return iss;
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
|
-
function unwrapMessage(message) {
|
|
287
|
+
function unwrapMessage$1(message) {
|
|
288
288
|
return typeof message === "string" ? message : message?.message;
|
|
289
289
|
}
|
|
290
290
|
function attachSchema(issues, start, inst) {
|
|
@@ -299,7 +299,7 @@ function finalizeIssue(iss, ctx, config) {
|
|
|
299
299
|
else iss.schema = iss.inst;
|
|
300
300
|
}
|
|
301
301
|
const schemaError = iss.schema !== iss.inst ? iss.schema?._zod.def?.error : void 0;
|
|
302
|
-
const message = iss.message ? iss.message : unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(schemaError?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config.customError?.(iss)) ?? unwrapMessage(config.localeError?.(iss)) ?? "Invalid input";
|
|
302
|
+
const message = iss.message ? iss.message : unwrapMessage$1(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage$1(schemaError?.(iss)) ?? unwrapMessage$1(ctx?.error?.(iss)) ?? unwrapMessage$1(config.customError?.(iss)) ?? unwrapMessage$1(config.localeError?.(iss)) ?? "Invalid input";
|
|
303
303
|
const { inst: _inst, schema: _schema, continue: _continue, input: _input, ...rest } = iss;
|
|
304
304
|
rest.path ?? (rest.path = []);
|
|
305
305
|
rest.message = message;
|
|
@@ -5190,6 +5190,50 @@ function superRefine(fn, params) {
|
|
|
5190
5190
|
* namespace and exports a `TYPERT_REMOTE` contribution that the browser
|
|
5191
5191
|
* plugin mounts via `ctx.remote.$mount(...)`.
|
|
5192
5192
|
*/
|
|
5193
|
+
const stringRecord$schema = record(string(), string());
|
|
5194
|
+
const mcpLocation$schema = object({
|
|
5195
|
+
id: string().readonly(),
|
|
5196
|
+
serverName: string().readonly(),
|
|
5197
|
+
transport: union([literal("stdio"), literal("streamable-http")]).readonly(),
|
|
5198
|
+
disabled: boolean().readonly(),
|
|
5199
|
+
command: string().optional().readonly(),
|
|
5200
|
+
args: array(string()).optional().readonly(),
|
|
5201
|
+
env: stringRecord$schema.optional().readonly(),
|
|
5202
|
+
cwd: string().optional().readonly(),
|
|
5203
|
+
url: string().optional().readonly(),
|
|
5204
|
+
headers: stringRecord$schema.optional().readonly(),
|
|
5205
|
+
toolCallTimeoutMs: number().optional().readonly()
|
|
5206
|
+
});
|
|
5207
|
+
const skillLocation$schema = object({
|
|
5208
|
+
name: string().readonly(),
|
|
5209
|
+
path: string().readonly(),
|
|
5210
|
+
linked: boolean().readonly(),
|
|
5211
|
+
valid: boolean().readonly(),
|
|
5212
|
+
root: union([literal("user"), literal("project")]).readonly(),
|
|
5213
|
+
entryDir: string().readonly(),
|
|
5214
|
+
target: string().optional().readonly()
|
|
5215
|
+
});
|
|
5216
|
+
const mcpInput$schema = object({
|
|
5217
|
+
serverName: string(),
|
|
5218
|
+
transport: union([literal("stdio"), literal("streamable-http")]),
|
|
5219
|
+
command: string().optional(),
|
|
5220
|
+
args: array(string()).optional(),
|
|
5221
|
+
env: stringRecord$schema.optional(),
|
|
5222
|
+
cwd: string().optional(),
|
|
5223
|
+
url: string().optional(),
|
|
5224
|
+
headers: stringRecord$schema.optional(),
|
|
5225
|
+
toolCallTimeoutMs: number().optional()
|
|
5226
|
+
});
|
|
5227
|
+
const mcpUpdateInput$schema = object({
|
|
5228
|
+
transport: union([literal("stdio"), literal("streamable-http")]),
|
|
5229
|
+
command: string().optional(),
|
|
5230
|
+
args: array(string()).optional(),
|
|
5231
|
+
env: stringRecord$schema.optional(),
|
|
5232
|
+
cwd: string().optional(),
|
|
5233
|
+
url: string().optional(),
|
|
5234
|
+
headers: stringRecord$schema.optional(),
|
|
5235
|
+
toolCallTimeoutMs: number().optional()
|
|
5236
|
+
});
|
|
5193
5237
|
const capabilityRow$schema = object({
|
|
5194
5238
|
id: string().readonly(),
|
|
5195
5239
|
kind: union([literal("tool"), literal("skill")]).readonly(),
|
|
@@ -5257,7 +5301,7 @@ const TYPERT_REMOTE = {
|
|
|
5257
5301
|
},
|
|
5258
5302
|
sourceLocation: {
|
|
5259
5303
|
file: "src/server/remote.ts",
|
|
5260
|
-
line:
|
|
5304
|
+
line: 61,
|
|
5261
5305
|
column: 3
|
|
5262
5306
|
}
|
|
5263
5307
|
},
|
|
@@ -5284,7 +5328,7 @@ const TYPERT_REMOTE = {
|
|
|
5284
5328
|
},
|
|
5285
5329
|
sourceLocation: {
|
|
5286
5330
|
file: "src/server/remote.ts",
|
|
5287
|
-
line:
|
|
5331
|
+
line: 67,
|
|
5288
5332
|
column: 3
|
|
5289
5333
|
}
|
|
5290
5334
|
},
|
|
@@ -5302,7 +5346,25 @@ const TYPERT_REMOTE = {
|
|
|
5302
5346
|
},
|
|
5303
5347
|
sourceLocation: {
|
|
5304
5348
|
file: "src/server/remote.ts",
|
|
5305
|
-
line:
|
|
5349
|
+
line: 73,
|
|
5350
|
+
column: 3
|
|
5351
|
+
}
|
|
5352
|
+
},
|
|
5353
|
+
{
|
|
5354
|
+
id: "@daweifu/capability-menu#capabilityPolicy/refresh",
|
|
5355
|
+
service: "capabilityPolicy",
|
|
5356
|
+
namespace: "capabilityPolicy",
|
|
5357
|
+
method: "refresh",
|
|
5358
|
+
invocation: { kind: "direct" },
|
|
5359
|
+
parameters: [],
|
|
5360
|
+
result: {
|
|
5361
|
+
mode: "strict",
|
|
5362
|
+
typeSymbol: "void",
|
|
5363
|
+
schema: _undefined()
|
|
5364
|
+
},
|
|
5365
|
+
sourceLocation: {
|
|
5366
|
+
file: "src/server/remote.ts",
|
|
5367
|
+
line: 84,
|
|
5306
5368
|
column: 3
|
|
5307
5369
|
}
|
|
5308
5370
|
},
|
|
@@ -5339,7 +5401,7 @@ const TYPERT_REMOTE = {
|
|
|
5339
5401
|
},
|
|
5340
5402
|
sourceLocation: {
|
|
5341
5403
|
file: "src/server/remote.ts",
|
|
5342
|
-
line:
|
|
5404
|
+
line: 85,
|
|
5343
5405
|
column: 3
|
|
5344
5406
|
}
|
|
5345
5407
|
},
|
|
@@ -5375,7 +5437,7 @@ const TYPERT_REMOTE = {
|
|
|
5375
5437
|
},
|
|
5376
5438
|
sourceLocation: {
|
|
5377
5439
|
file: "src/server/remote.ts",
|
|
5378
|
-
line:
|
|
5440
|
+
line: 91,
|
|
5379
5441
|
column: 3
|
|
5380
5442
|
}
|
|
5381
5443
|
},
|
|
@@ -5402,7 +5464,7 @@ const TYPERT_REMOTE = {
|
|
|
5402
5464
|
},
|
|
5403
5465
|
sourceLocation: {
|
|
5404
5466
|
file: "src/server/remote.ts",
|
|
5405
|
-
line:
|
|
5467
|
+
line: 79,
|
|
5406
5468
|
column: 3
|
|
5407
5469
|
}
|
|
5408
5470
|
},
|
|
@@ -5420,7 +5482,284 @@ const TYPERT_REMOTE = {
|
|
|
5420
5482
|
},
|
|
5421
5483
|
sourceLocation: {
|
|
5422
5484
|
file: "src/server/remote.ts",
|
|
5423
|
-
line:
|
|
5485
|
+
line: 104,
|
|
5486
|
+
column: 3
|
|
5487
|
+
}
|
|
5488
|
+
},
|
|
5489
|
+
{
|
|
5490
|
+
id: "@daweifu/capability-menu#capabilityPolicy/listLocations",
|
|
5491
|
+
service: "capabilityPolicy",
|
|
5492
|
+
namespace: "capabilityPolicy",
|
|
5493
|
+
method: "listLocations",
|
|
5494
|
+
invocation: { kind: "direct" },
|
|
5495
|
+
parameters: [],
|
|
5496
|
+
result: {
|
|
5497
|
+
mode: "strict",
|
|
5498
|
+
typeSymbol: "@daweifu/capability-menu#McpLocation[]",
|
|
5499
|
+
schema: array(mcpLocation$schema)
|
|
5500
|
+
},
|
|
5501
|
+
sourceLocation: {
|
|
5502
|
+
file: "src/server/remote.ts",
|
|
5503
|
+
line: 193,
|
|
5504
|
+
column: 3
|
|
5505
|
+
}
|
|
5506
|
+
},
|
|
5507
|
+
{
|
|
5508
|
+
id: "@daweifu/capability-menu#capabilityPolicy/addLocation",
|
|
5509
|
+
service: "capabilityPolicy",
|
|
5510
|
+
namespace: "capabilityPolicy",
|
|
5511
|
+
method: "addLocation",
|
|
5512
|
+
invocation: { kind: "direct" },
|
|
5513
|
+
parameters: [{
|
|
5514
|
+
name: "input",
|
|
5515
|
+
wire: "input",
|
|
5516
|
+
source: "json",
|
|
5517
|
+
codec: {
|
|
5518
|
+
mode: "strict",
|
|
5519
|
+
typeSymbol: "@daweifu/capability-menu#McpInput",
|
|
5520
|
+
schema: mcpInput$schema
|
|
5521
|
+
}
|
|
5522
|
+
}],
|
|
5523
|
+
result: {
|
|
5524
|
+
mode: "strict",
|
|
5525
|
+
typeSymbol: "string",
|
|
5526
|
+
schema: string()
|
|
5527
|
+
},
|
|
5528
|
+
sourceLocation: {
|
|
5529
|
+
file: "src/server/remote.ts",
|
|
5530
|
+
line: 199,
|
|
5531
|
+
column: 3
|
|
5532
|
+
}
|
|
5533
|
+
},
|
|
5534
|
+
{
|
|
5535
|
+
id: "@daweifu/capability-menu#capabilityPolicy/removeLocation",
|
|
5536
|
+
service: "capabilityPolicy",
|
|
5537
|
+
namespace: "capabilityPolicy",
|
|
5538
|
+
method: "removeLocation",
|
|
5539
|
+
invocation: { kind: "direct" },
|
|
5540
|
+
parameters: [{
|
|
5541
|
+
name: "id",
|
|
5542
|
+
wire: "id",
|
|
5543
|
+
source: "json",
|
|
5544
|
+
codec: {
|
|
5545
|
+
mode: "strict",
|
|
5546
|
+
typeSymbol: "string",
|
|
5547
|
+
schema: string()
|
|
5548
|
+
}
|
|
5549
|
+
}],
|
|
5550
|
+
result: {
|
|
5551
|
+
mode: "strict",
|
|
5552
|
+
typeSymbol: "boolean",
|
|
5553
|
+
schema: boolean()
|
|
5554
|
+
},
|
|
5555
|
+
sourceLocation: {
|
|
5556
|
+
file: "src/server/remote.ts",
|
|
5557
|
+
line: 205,
|
|
5558
|
+
column: 3
|
|
5559
|
+
}
|
|
5560
|
+
},
|
|
5561
|
+
{
|
|
5562
|
+
id: "@daweifu/capability-menu#capabilityPolicy/updateLocation",
|
|
5563
|
+
service: "capabilityPolicy",
|
|
5564
|
+
namespace: "capabilityPolicy",
|
|
5565
|
+
method: "updateLocation",
|
|
5566
|
+
invocation: { kind: "direct" },
|
|
5567
|
+
parameters: [{
|
|
5568
|
+
name: "id",
|
|
5569
|
+
wire: "id",
|
|
5570
|
+
source: "json",
|
|
5571
|
+
codec: {
|
|
5572
|
+
mode: "strict",
|
|
5573
|
+
typeSymbol: "string",
|
|
5574
|
+
schema: string()
|
|
5575
|
+
}
|
|
5576
|
+
}, {
|
|
5577
|
+
name: "input",
|
|
5578
|
+
wire: "input",
|
|
5579
|
+
source: "json",
|
|
5580
|
+
codec: {
|
|
5581
|
+
mode: "strict",
|
|
5582
|
+
typeSymbol: "@daweifu/capability-menu#McpUpdateInput",
|
|
5583
|
+
schema: mcpUpdateInput$schema
|
|
5584
|
+
}
|
|
5585
|
+
}],
|
|
5586
|
+
result: {
|
|
5587
|
+
mode: "strict",
|
|
5588
|
+
typeSymbol: "boolean",
|
|
5589
|
+
schema: boolean()
|
|
5590
|
+
},
|
|
5591
|
+
sourceLocation: {
|
|
5592
|
+
file: "src/server/remote.ts",
|
|
5593
|
+
line: 211,
|
|
5594
|
+
column: 3
|
|
5595
|
+
}
|
|
5596
|
+
},
|
|
5597
|
+
{
|
|
5598
|
+
id: "@daweifu/capability-menu#capabilityPolicy/listSkillLocations",
|
|
5599
|
+
service: "capabilityPolicy",
|
|
5600
|
+
namespace: "capabilityPolicy",
|
|
5601
|
+
method: "listSkillLocations",
|
|
5602
|
+
invocation: { kind: "direct" },
|
|
5603
|
+
parameters: [],
|
|
5604
|
+
result: {
|
|
5605
|
+
mode: "strict",
|
|
5606
|
+
typeSymbol: "@daweifu/capability-menu#SkillLocation[]",
|
|
5607
|
+
schema: array(skillLocation$schema)
|
|
5608
|
+
},
|
|
5609
|
+
sourceLocation: {
|
|
5610
|
+
file: "src/server/remote.ts",
|
|
5611
|
+
line: 229,
|
|
5612
|
+
column: 3
|
|
5613
|
+
}
|
|
5614
|
+
},
|
|
5615
|
+
{
|
|
5616
|
+
id: "@daweifu/capability-menu#capabilityPolicy/addSkillLocation",
|
|
5617
|
+
service: "capabilityPolicy",
|
|
5618
|
+
namespace: "capabilityPolicy",
|
|
5619
|
+
method: "addSkillLocation",
|
|
5620
|
+
invocation: { kind: "direct" },
|
|
5621
|
+
parameters: [{
|
|
5622
|
+
name: "dir",
|
|
5623
|
+
wire: "dir",
|
|
5624
|
+
source: "json",
|
|
5625
|
+
codec: {
|
|
5626
|
+
mode: "strict",
|
|
5627
|
+
typeSymbol: "string",
|
|
5628
|
+
schema: string()
|
|
5629
|
+
}
|
|
5630
|
+
}, {
|
|
5631
|
+
name: "projectPath",
|
|
5632
|
+
wire: "projectPath",
|
|
5633
|
+
source: "json",
|
|
5634
|
+
acceptsUndefined: true,
|
|
5635
|
+
codec: {
|
|
5636
|
+
mode: "strict",
|
|
5637
|
+
typeSymbol: "string",
|
|
5638
|
+
schema: string().optional()
|
|
5639
|
+
}
|
|
5640
|
+
}],
|
|
5641
|
+
result: {
|
|
5642
|
+
mode: "strict",
|
|
5643
|
+
typeSymbol: "string",
|
|
5644
|
+
schema: string()
|
|
5645
|
+
},
|
|
5646
|
+
sourceLocation: {
|
|
5647
|
+
file: "src/server/remote.ts",
|
|
5648
|
+
line: 252,
|
|
5649
|
+
column: 3
|
|
5650
|
+
}
|
|
5651
|
+
},
|
|
5652
|
+
{
|
|
5653
|
+
id: "@daweifu/capability-menu#capabilityPolicy/removeSkillLocation",
|
|
5654
|
+
service: "capabilityPolicy",
|
|
5655
|
+
namespace: "capabilityPolicy",
|
|
5656
|
+
method: "removeSkillLocation",
|
|
5657
|
+
invocation: { kind: "direct" },
|
|
5658
|
+
parameters: [{
|
|
5659
|
+
name: "name",
|
|
5660
|
+
wire: "name",
|
|
5661
|
+
source: "json",
|
|
5662
|
+
codec: {
|
|
5663
|
+
mode: "strict",
|
|
5664
|
+
typeSymbol: "string",
|
|
5665
|
+
schema: string()
|
|
5666
|
+
}
|
|
5667
|
+
}, {
|
|
5668
|
+
name: "entryDir",
|
|
5669
|
+
wire: "entryDir",
|
|
5670
|
+
source: "json",
|
|
5671
|
+
acceptsUndefined: true,
|
|
5672
|
+
codec: {
|
|
5673
|
+
mode: "strict",
|
|
5674
|
+
typeSymbol: "string",
|
|
5675
|
+
schema: string().optional()
|
|
5676
|
+
}
|
|
5677
|
+
}],
|
|
5678
|
+
result: {
|
|
5679
|
+
mode: "strict",
|
|
5680
|
+
typeSymbol: "boolean",
|
|
5681
|
+
schema: boolean()
|
|
5682
|
+
},
|
|
5683
|
+
sourceLocation: {
|
|
5684
|
+
file: "src/server/remote.ts",
|
|
5685
|
+
line: 258,
|
|
5686
|
+
column: 3
|
|
5687
|
+
}
|
|
5688
|
+
},
|
|
5689
|
+
{
|
|
5690
|
+
id: "@daweifu/capability-menu#capabilityPolicy/adoptSkillLocation",
|
|
5691
|
+
service: "capabilityPolicy",
|
|
5692
|
+
namespace: "capabilityPolicy",
|
|
5693
|
+
method: "adoptSkillLocation",
|
|
5694
|
+
invocation: { kind: "direct" },
|
|
5695
|
+
parameters: [{
|
|
5696
|
+
name: "name",
|
|
5697
|
+
wire: "name",
|
|
5698
|
+
source: "json",
|
|
5699
|
+
codec: {
|
|
5700
|
+
mode: "strict",
|
|
5701
|
+
typeSymbol: "string",
|
|
5702
|
+
schema: string()
|
|
5703
|
+
}
|
|
5704
|
+
}],
|
|
5705
|
+
result: {
|
|
5706
|
+
mode: "strict",
|
|
5707
|
+
typeSymbol: "string",
|
|
5708
|
+
schema: string()
|
|
5709
|
+
},
|
|
5710
|
+
sourceLocation: {
|
|
5711
|
+
file: "src/server/remote.ts",
|
|
5712
|
+
line: 259,
|
|
5713
|
+
column: 3
|
|
5714
|
+
}
|
|
5715
|
+
},
|
|
5716
|
+
{
|
|
5717
|
+
id: "@daweifu/capability-menu#capabilityPolicy/updateSkillLocation",
|
|
5718
|
+
service: "capabilityPolicy",
|
|
5719
|
+
namespace: "capabilityPolicy",
|
|
5720
|
+
method: "updateSkillLocation",
|
|
5721
|
+
invocation: { kind: "direct" },
|
|
5722
|
+
parameters: [
|
|
5723
|
+
{
|
|
5724
|
+
name: "name",
|
|
5725
|
+
wire: "name",
|
|
5726
|
+
source: "json",
|
|
5727
|
+
codec: {
|
|
5728
|
+
mode: "strict",
|
|
5729
|
+
typeSymbol: "string",
|
|
5730
|
+
schema: string()
|
|
5731
|
+
}
|
|
5732
|
+
},
|
|
5733
|
+
{
|
|
5734
|
+
name: "dir",
|
|
5735
|
+
wire: "dir",
|
|
5736
|
+
source: "json",
|
|
5737
|
+
codec: {
|
|
5738
|
+
mode: "strict",
|
|
5739
|
+
typeSymbol: "string",
|
|
5740
|
+
schema: string()
|
|
5741
|
+
}
|
|
5742
|
+
},
|
|
5743
|
+
{
|
|
5744
|
+
name: "entryDir",
|
|
5745
|
+
wire: "entryDir",
|
|
5746
|
+
source: "json",
|
|
5747
|
+
acceptsUndefined: true,
|
|
5748
|
+
codec: {
|
|
5749
|
+
mode: "strict",
|
|
5750
|
+
typeSymbol: "string",
|
|
5751
|
+
schema: string().optional()
|
|
5752
|
+
}
|
|
5753
|
+
}
|
|
5754
|
+
],
|
|
5755
|
+
result: {
|
|
5756
|
+
mode: "strict",
|
|
5757
|
+
typeSymbol: "boolean",
|
|
5758
|
+
schema: boolean()
|
|
5759
|
+
},
|
|
5760
|
+
sourceLocation: {
|
|
5761
|
+
file: "src/server/remote.ts",
|
|
5762
|
+
line: 264,
|
|
5424
5763
|
column: 3
|
|
5425
5764
|
}
|
|
5426
5765
|
}
|
|
@@ -5433,16 +5772,600 @@ function unwrap(result, what) {
|
|
|
5433
5772
|
if (!result.ok) throw new Error(`${what} failed: ${result.error.code}: ${result.error.message}`);
|
|
5434
5773
|
return result.value;
|
|
5435
5774
|
}
|
|
5436
|
-
/**
|
|
5775
|
+
/**
|
|
5776
|
+
* Unwrap a RemoteResult-like for a user-facing mutation.
|
|
5777
|
+
*
|
|
5778
|
+
* The policy service's messages are already written for the person at the
|
|
5779
|
+
* dialog (Chinese, naming the offending path), so the RPC name and error code
|
|
5780
|
+
* that `unwrap` adds for diagnostics are dropped here: they would surface as
|
|
5781
|
+
* `capabilityPolicy.addSkillLocation failed: <code>: 目录中没有 SKILL.md:…`
|
|
5782
|
+
* in a dialog that is otherwise plain Chinese.
|
|
5783
|
+
*/
|
|
5784
|
+
function unwrapMessage(result) {
|
|
5785
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
5786
|
+
return result.value;
|
|
5787
|
+
}
|
|
5788
|
+
/**
|
|
5789
|
+
* The last successful snapshot, at module scope.
|
|
5790
|
+
*
|
|
5791
|
+
* The section is remounted every time the settings tab is opened, and a cold
|
|
5792
|
+
* `classifyAll` can be slow once per page load (the plugin's mount awaits a full
|
|
5793
|
+
* catalog enumeration before the surface has data). Keeping the previous rows
|
|
5794
|
+
* lets a remount paint them immediately and revalidate behind the user instead
|
|
5795
|
+
* of showing a loading placeholder. This is a view cache only — every read is
|
|
5796
|
+
* still followed by an authoritative one.
|
|
5797
|
+
*/
|
|
5798
|
+
let lastSnapshot;
|
|
5799
|
+
/** The previously loaded snapshot, when this page session has one. */
|
|
5800
|
+
function cachedSnapshot() {
|
|
5801
|
+
return lastSnapshot;
|
|
5802
|
+
}
|
|
5803
|
+
/** Load the classification list from the remote, remembering it for remounts. */
|
|
5437
5804
|
async function loadSnapshot(remote) {
|
|
5438
|
-
|
|
5805
|
+
lastSnapshot = { rows: unwrap(await remote.classifyAll(), "capabilityPolicy.classifyAll") };
|
|
5806
|
+
return lastSnapshot;
|
|
5807
|
+
}
|
|
5808
|
+
//#endregion
|
|
5809
|
+
//#region src/client/LocationModal.tsx
|
|
5810
|
+
/**
|
|
5811
|
+
* 能力来源弹窗:注册与编辑 MCP 服务器 / Skill 目录。
|
|
5812
|
+
*
|
|
5813
|
+
* Two modes, one form implementation:
|
|
5814
|
+
*
|
|
5815
|
+
* - **注册** — opened from the header's 注册能力 button. Carries the two
|
|
5816
|
+
* sub-tabs (MCP servers / skill directories) and opens on the one matching
|
|
5817
|
+
* the main tab the user is on, so one button is context-sensitive. No list of
|
|
5818
|
+
* what is already registered: that lives on the entries themselves, behind
|
|
5819
|
+
* the per-row 编辑 buttons, where it is actually actionable.
|
|
5820
|
+
* - **编辑** — opened from a row's 编辑 button with the entry prefilled.
|
|
5821
|
+
*
|
|
5822
|
+
* Only 注册 / 保存 / 移除 are offered. Temporarily silencing a source is the
|
|
5823
|
+
* exposure policy's job (classify the capability as Disabled), so there is no
|
|
5824
|
+
* second enable switch here.
|
|
5825
|
+
*/
|
|
5826
|
+
const CSS_ID$1 = "capability-menu-location-css";
|
|
5827
|
+
const CSS$1 = `
|
|
5828
|
+
.lm-block{display:flex;flex-direction:column;gap:8px}
|
|
5829
|
+
.lm-btn{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;line-height:20px;padding:0 10px;cursor:pointer;white-space:nowrap}
|
|
5830
|
+
.lm-btn:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-interactive-bg-hover)}
|
|
5831
|
+
.lm-btn--danger:hover{color:#b3261e;border-color:#b3261e}
|
|
5832
|
+
.lm-btn:disabled{opacity:.55;cursor:default}
|
|
5833
|
+
/* Each field is its own two-column grid with a fixed label track.
|
|
5834
|
+
A single form-wide grid looked tidier but was fragile: it needed
|
|
5835
|
+
.lm-field{display:contents}, which turned every hint into a free-floating grid
|
|
5836
|
+
item, and one extra half-width item pushed the following labels into column 2 and
|
|
5837
|
+
their inputs into column 1 — which is exactly how the streamable-http layout got
|
|
5838
|
+
scrambled (that branch has an odd number of items). Per-field grids mean a hint
|
|
5839
|
+
can only ever affect its own field, and a fixed label track (rather than
|
|
5840
|
+
min-width, which sizes per row) keeps every label column identical. */
|
|
5841
|
+
.lm-form{display:flex;flex-direction:column;gap:6px}
|
|
5842
|
+
.lm-field{--lm-label-w:104px;display:grid;grid-template-columns:var(--lm-label-w) 1fr;gap:2px 8px;align-items:start}
|
|
5843
|
+
.lm-label{grid-column:1;min-width:0;overflow-wrap:anywhere;font-size:12px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
|
|
5844
|
+
/* width:100% must come with border-box: the field carries a 1px border plus 8px of
|
|
5845
|
+
padding, which would otherwise overflow the column and clip. */
|
|
5846
|
+
.lm-input{grid-column:2;width:100%;box-sizing:border-box;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:inherit;font:inherit;font-size:12px;line-height:20px;padding:2px 8px}
|
|
5847
|
+
.lm-input:disabled{opacity:.6}
|
|
5848
|
+
textarea.lm-input{resize:vertical;font-family:var(--dsw-font-markdown-code-block-font-family)}
|
|
5849
|
+
/* Lives inside its field, in the content column: it lines up with the box it
|
|
5850
|
+
annotates and takes the caption colour so it does not read as another label. */
|
|
5851
|
+
.lm-hint{grid-column:2;margin:0;font-size:11px;line-height:16px;color:var(--dsw-alias-label-caption)}
|
|
5852
|
+
.lm-error{margin:0;font-size:12px;color:#b3261e;word-break:break-word}
|
|
5853
|
+
.lm-actions{display:flex;gap:8px;justify-content:flex-end;padding:4px 0 0}
|
|
5854
|
+
/* Removal is irreversible, so it takes over the action row for one confirmation
|
|
5855
|
+
step: the message states the consequence, then the buttons act. */
|
|
5856
|
+
.lm-confirm{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 10px;border:1px solid #b3261e;border-radius:6px}
|
|
5857
|
+
.lm-confirm-msg{flex:1 1 auto;margin:0;font-size:12px;line-height:18px;word-break:break-word}
|
|
5858
|
+
.lm-confirm-actions{display:flex;gap:8px;flex-shrink:0}
|
|
5859
|
+
/* The modal shell itself carries no padding (it is shared with the read-only
|
|
5860
|
+
catalog viewer, whose body supplies its own); the form supplies it here. */
|
|
5861
|
+
.lm-body{padding:14px 16px;overflow:auto;flex:1 1 auto;min-height:0}
|
|
5862
|
+
`;
|
|
5863
|
+
if (typeof document !== "undefined" && document.querySelector(`style[data-css-id="${CSS_ID$1}"]`) === null) {
|
|
5864
|
+
const tag = document.createElement("style");
|
|
5865
|
+
tag.dataset.cssId = CSS_ID$1;
|
|
5866
|
+
tag.textContent = CSS$1;
|
|
5867
|
+
document.head.appendChild(tag);
|
|
5868
|
+
}
|
|
5869
|
+
/** Render a key/value map as `Key: Value` lines. */
|
|
5870
|
+
function toLines(record) {
|
|
5871
|
+
if (record === void 0) return "";
|
|
5872
|
+
return Object.entries(record).map(([key, value]) => `${key}: ${value}`).join("\n");
|
|
5873
|
+
}
|
|
5874
|
+
/** Parse `Key: Value` lines into a map; blank lines and lines without `:` are skipped. */
|
|
5875
|
+
function fromLines(text) {
|
|
5876
|
+
const out = {};
|
|
5877
|
+
for (const line of text.split("\n")) {
|
|
5878
|
+
const trimmed = line.trim();
|
|
5879
|
+
if (trimmed.length === 0) continue;
|
|
5880
|
+
const at = trimmed.indexOf(":");
|
|
5881
|
+
if (at <= 0) continue;
|
|
5882
|
+
const key = trimmed.slice(0, at).trim();
|
|
5883
|
+
const value = trimmed.slice(at + 1).trim();
|
|
5884
|
+
if (key.length > 0) out[key] = value;
|
|
5885
|
+
}
|
|
5886
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
5887
|
+
}
|
|
5888
|
+
function LocationModal(props) {
|
|
5889
|
+
const { remote, t, defaultKind = "mcp", editMcp, editSkill, onClose, onChanged } = props;
|
|
5890
|
+
const editing = editMcp !== void 0 || editSkill !== void 0;
|
|
5891
|
+
const [subTab, setSubTab] = (0, react.useState)(editSkill !== void 0 ? "skill" : editMcp !== void 0 ? "mcp" : defaultKind);
|
|
5892
|
+
const [error, setError] = (0, react.useState)(null);
|
|
5893
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
5894
|
+
/**
|
|
5895
|
+
* Which action is waiting for confirmation, if any. Two need one: 移除, and
|
|
5896
|
+
* 保存 on an entry that is a real directory — repointing unlinks the entry
|
|
5897
|
+
* first, which recursively deletes a real directory's contents.
|
|
5898
|
+
*/
|
|
5899
|
+
const [confirm, setConfirm] = (0, react.useState)(null);
|
|
5900
|
+
const [serverName, setServerName] = (0, react.useState)(editMcp?.serverName ?? "");
|
|
5901
|
+
const [transport, setTransport] = (0, react.useState)(editMcp?.transport ?? "streamable-http");
|
|
5902
|
+
const [command, setCommand] = (0, react.useState)(editMcp?.command ?? "");
|
|
5903
|
+
const [args, setArgs] = (0, react.useState)((editMcp?.args ?? []).join(" "));
|
|
5904
|
+
const [cwd, setCwd] = (0, react.useState)(editMcp?.cwd ?? "");
|
|
5905
|
+
const [env, setEnv] = (0, react.useState)(toLines(editMcp?.env));
|
|
5906
|
+
const [url, setUrl] = (0, react.useState)(editMcp?.url ?? "");
|
|
5907
|
+
const [headers, setHeaders] = (0, react.useState)(toLines(editMcp?.headers));
|
|
5908
|
+
const [timeoutSec, setTimeoutSec] = (0, react.useState)(editMcp?.toolCallTimeoutMs === void 0 ? "" : String(Math.round(editMcp.toolCallTimeoutMs / 1e3)));
|
|
5909
|
+
const [skillDir, setSkillDir] = (0, react.useState)(editSkill?.target ?? editSkill?.path ?? "");
|
|
5910
|
+
const [skillRoot, setSkillRoot] = (0, react.useState)(editSkill?.root ?? "user");
|
|
5911
|
+
/** A path inside the project; the server derives the project root from it. */
|
|
5912
|
+
const [projectPath, setProjectPath] = (0, react.useState)("");
|
|
5913
|
+
/**
|
|
5914
|
+
* What the operator sees this entry called. They got here from a row named by
|
|
5915
|
+
* the skill's declared name, so the messages use that and not the entry's own
|
|
5916
|
+
* name — which is only ever handed back to the server, since that is what
|
|
5917
|
+
* addresses the symlink on disk.
|
|
5918
|
+
*/
|
|
5919
|
+
const skillLabel = editSkill?.skillName ?? editSkill?.name ?? "";
|
|
5920
|
+
const title = (0, react.useMemo)(() => {
|
|
5921
|
+
if (editMcp !== void 0) return t("editMcp");
|
|
5922
|
+
if (editSkill !== void 0) return t("editSkillNamed", { name: skillLabel });
|
|
5923
|
+
return t("registerCapability");
|
|
5924
|
+
}, [
|
|
5925
|
+
editMcp,
|
|
5926
|
+
editSkill,
|
|
5927
|
+
skillLabel,
|
|
5928
|
+
t
|
|
5929
|
+
]);
|
|
5930
|
+
/** Run a mutation; on success close and ask the parent to re-pull. */
|
|
5931
|
+
const submit = (0, react.useCallback)(async (action, noticeFor) => {
|
|
5932
|
+
if (busy) return;
|
|
5933
|
+
setBusy(true);
|
|
5934
|
+
try {
|
|
5935
|
+
const changed = await action();
|
|
5936
|
+
if (changed === false) throw new Error(t("entryNotFound"));
|
|
5937
|
+
setError(null);
|
|
5938
|
+
onChanged(noticeFor?.(changed));
|
|
5939
|
+
onClose();
|
|
5940
|
+
} catch (e) {
|
|
5941
|
+
setError(String(e));
|
|
5942
|
+
} finally {
|
|
5943
|
+
setBusy(false);
|
|
5944
|
+
}
|
|
5945
|
+
}, [
|
|
5946
|
+
busy,
|
|
5947
|
+
onChanged,
|
|
5948
|
+
onClose,
|
|
5949
|
+
t
|
|
5950
|
+
]);
|
|
5951
|
+
const submitMcp = (0, react.useCallback)(() => {
|
|
5952
|
+
const trimmedTimeout = timeoutSec.trim();
|
|
5953
|
+
const timeoutMs = trimmedTimeout.length === 0 ? void 0 : Math.round(Number(trimmedTimeout) * 1e3);
|
|
5954
|
+
if (timeoutMs !== void 0 && !Number.isFinite(timeoutMs)) {
|
|
5955
|
+
setError(t("timeoutInvalid"));
|
|
5956
|
+
return;
|
|
5957
|
+
}
|
|
5958
|
+
const parsedEnv = fromLines(env);
|
|
5959
|
+
const parsedHeaders = fromLines(headers);
|
|
5960
|
+
const common = {
|
|
5961
|
+
transport,
|
|
5962
|
+
...transport === "stdio" ? {
|
|
5963
|
+
command: command.trim(),
|
|
5964
|
+
...args.trim().length > 0 ? { args: args.trim().split(/\s+/) } : {},
|
|
5965
|
+
...parsedEnv !== void 0 ? { env: parsedEnv } : {},
|
|
5966
|
+
...cwd.trim().length > 0 ? { cwd: cwd.trim() } : {}
|
|
5967
|
+
} : {
|
|
5968
|
+
url: url.trim(),
|
|
5969
|
+
...parsedHeaders !== void 0 ? { headers: parsedHeaders } : {}
|
|
5970
|
+
},
|
|
5971
|
+
...timeoutMs !== void 0 ? { toolCallTimeoutMs: timeoutMs } : {}
|
|
5972
|
+
};
|
|
5973
|
+
submit(async () => editMcp !== void 0 ? unwrapMessage(await remote.updateLocation(editMcp.id, common)) : unwrapMessage(await remote.addLocation({
|
|
5974
|
+
serverName: serverName.trim(),
|
|
5975
|
+
...common
|
|
5976
|
+
})));
|
|
5977
|
+
}, [
|
|
5978
|
+
submit,
|
|
5979
|
+
remote,
|
|
5980
|
+
editMcp,
|
|
5981
|
+
serverName,
|
|
5982
|
+
transport,
|
|
5983
|
+
command,
|
|
5984
|
+
args,
|
|
5985
|
+
cwd,
|
|
5986
|
+
env,
|
|
5987
|
+
url,
|
|
5988
|
+
headers,
|
|
5989
|
+
timeoutSec,
|
|
5990
|
+
t
|
|
5991
|
+
]);
|
|
5992
|
+
const submitSkill = (0, react.useCallback)(() => {
|
|
5993
|
+
const asked = skillRoot === "project" ? projectPath.trim() : void 0;
|
|
5994
|
+
submit(async () => editSkill !== void 0 ? unwrapMessage(await remote.updateSkillLocation(editSkill.name, skillDir.trim(), editSkill.entryDir)) : unwrapMessage(await remote.addSkillLocation(skillDir.trim(), asked)), (result) => editSkill !== void 0 ? t("skillRepointed", { dir: skillDir.trim() }) : t("skillRegisteredAt", { path: String(result) }));
|
|
5995
|
+
}, [
|
|
5996
|
+
submit,
|
|
5997
|
+
remote,
|
|
5998
|
+
editSkill,
|
|
5999
|
+
skillDir,
|
|
6000
|
+
skillRoot,
|
|
6001
|
+
projectPath,
|
|
6002
|
+
t
|
|
6003
|
+
]);
|
|
6004
|
+
const remove = (0, react.useCallback)(() => {
|
|
6005
|
+
if (editMcp !== void 0) {
|
|
6006
|
+
submit(async () => unwrapMessage(await remote.removeLocation(editMcp.id)));
|
|
6007
|
+
return;
|
|
6008
|
+
}
|
|
6009
|
+
if (editSkill !== void 0) submit(async () => unwrapMessage(await remote.removeSkillLocation(editSkill.name, editSkill.entryDir)));
|
|
6010
|
+
}, [
|
|
6011
|
+
submit,
|
|
6012
|
+
remote,
|
|
6013
|
+
editMcp,
|
|
6014
|
+
editSkill
|
|
6015
|
+
]);
|
|
6016
|
+
/**
|
|
6017
|
+
* What removal actually costs, which differs by target: an MCP row only loses
|
|
6018
|
+
* its config, a linked skill only loses its symlink — but `removeSkill`
|
|
6019
|
+
* recursively deletes a *real* directory in the skill root, so that case has to
|
|
6020
|
+
* say so before the click, not after.
|
|
6021
|
+
*/
|
|
6022
|
+
const removalWarning = (0, react.useMemo)(() => {
|
|
6023
|
+
if (editMcp !== void 0) return t("confirmRemoveMcp", { name: editMcp.serverName });
|
|
6024
|
+
if (editSkill === void 0) return "";
|
|
6025
|
+
return editSkill.linked ? t("confirmRemoveSkillLink", { name: skillLabel }) : t("confirmRemoveSkillDir", { name: skillLabel });
|
|
6026
|
+
}, [
|
|
6027
|
+
editMcp,
|
|
6028
|
+
editSkill,
|
|
6029
|
+
skillLabel,
|
|
6030
|
+
t
|
|
6031
|
+
]);
|
|
6032
|
+
/** Saving needs a confirmation only when it would delete a real directory. */
|
|
6033
|
+
const needsSaveConfirm = editSkill !== void 0 && !editSkill.linked;
|
|
6034
|
+
/** The action row, or the confirmation step that has replaced it. */
|
|
6035
|
+
const renderActions = (onSubmit) => confirm !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6036
|
+
className: "lm-confirm",
|
|
6037
|
+
role: "alert",
|
|
6038
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6039
|
+
className: "lm-confirm-msg",
|
|
6040
|
+
children: confirm === "save" ? t("saveConfirmRealDir", { name: skillLabel }) : removalWarning
|
|
6041
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6042
|
+
className: "lm-confirm-actions",
|
|
6043
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6044
|
+
type: "button",
|
|
6045
|
+
className: "lm-btn",
|
|
6046
|
+
disabled: busy,
|
|
6047
|
+
onClick: () => setConfirm(null),
|
|
6048
|
+
children: t("cancel")
|
|
6049
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6050
|
+
type: "button",
|
|
6051
|
+
className: "lm-btn lm-btn--danger",
|
|
6052
|
+
disabled: busy,
|
|
6053
|
+
onClick: () => {
|
|
6054
|
+
if (confirm === "save") onSubmit();
|
|
6055
|
+
else remove();
|
|
6056
|
+
},
|
|
6057
|
+
children: confirm === "save" ? t("confirmSaveAnyway") : t("confirmRemove")
|
|
6058
|
+
})]
|
|
6059
|
+
})]
|
|
6060
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6061
|
+
className: "lm-actions",
|
|
6062
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6063
|
+
type: "button",
|
|
6064
|
+
className: "lm-btn",
|
|
6065
|
+
disabled: busy,
|
|
6066
|
+
onClick: () => {
|
|
6067
|
+
if (needsSaveConfirm) setConfirm("save");
|
|
6068
|
+
else onSubmit();
|
|
6069
|
+
},
|
|
6070
|
+
children: editing ? t("save") : t("register")
|
|
6071
|
+
}), editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6072
|
+
type: "button",
|
|
6073
|
+
className: "lm-btn lm-btn--danger",
|
|
6074
|
+
disabled: busy,
|
|
6075
|
+
onClick: () => setConfirm("remove"),
|
|
6076
|
+
children: t("remove")
|
|
6077
|
+
})]
|
|
6078
|
+
});
|
|
6079
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6080
|
+
className: "mc-preview-mask",
|
|
6081
|
+
onClick: onClose,
|
|
6082
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6083
|
+
className: "mc-preview",
|
|
6084
|
+
onClick: (e) => e.stopPropagation(),
|
|
6085
|
+
children: [
|
|
6086
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6087
|
+
className: "mc-preview-head",
|
|
6088
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6089
|
+
className: "mc-preview-title",
|
|
6090
|
+
children: title
|
|
6091
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6092
|
+
type: "button",
|
|
6093
|
+
className: "mc-preview-close",
|
|
6094
|
+
onClick: onClose,
|
|
6095
|
+
children: t("previewClose")
|
|
6096
|
+
})]
|
|
6097
|
+
}),
|
|
6098
|
+
!editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6099
|
+
className: "mc-subtabs mc-catalog-tabs",
|
|
6100
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6101
|
+
className: "mc-tab-group",
|
|
6102
|
+
role: "tablist",
|
|
6103
|
+
"aria-label": t("registerCapability"),
|
|
6104
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6105
|
+
type: "button",
|
|
6106
|
+
role: "tab",
|
|
6107
|
+
className: "mc-tab",
|
|
6108
|
+
"aria-selected": subTab === "mcp",
|
|
6109
|
+
"data-active": subTab === "mcp" ? "true" : void 0,
|
|
6110
|
+
onClick: () => setSubTab("mcp"),
|
|
6111
|
+
children: t("mcpServers")
|
|
6112
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6113
|
+
type: "button",
|
|
6114
|
+
role: "tab",
|
|
6115
|
+
className: "mc-tab",
|
|
6116
|
+
"aria-selected": subTab === "skill",
|
|
6117
|
+
"data-active": subTab === "skill" ? "true" : void 0,
|
|
6118
|
+
onClick: () => setSubTab("skill"),
|
|
6119
|
+
children: t("skillDirs")
|
|
6120
|
+
})]
|
|
6121
|
+
})
|
|
6122
|
+
}),
|
|
6123
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6124
|
+
className: "lm-body",
|
|
6125
|
+
children: [error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6126
|
+
className: "lm-error",
|
|
6127
|
+
children: error
|
|
6128
|
+
}), subTab === "mcp" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6129
|
+
className: "lm-block",
|
|
6130
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6131
|
+
className: "lm-form",
|
|
6132
|
+
children: [
|
|
6133
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6134
|
+
className: "lm-field",
|
|
6135
|
+
children: [
|
|
6136
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6137
|
+
className: "lm-label",
|
|
6138
|
+
children: t("transport")
|
|
6139
|
+
}),
|
|
6140
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
6141
|
+
className: "lm-input",
|
|
6142
|
+
value: transport,
|
|
6143
|
+
onChange: (e) => setTransport(e.target.value === "stdio" ? "stdio" : "streamable-http"),
|
|
6144
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6145
|
+
value: "stdio",
|
|
6146
|
+
children: t("transportStdio")
|
|
6147
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6148
|
+
value: "streamable-http",
|
|
6149
|
+
children: t("transportHttp")
|
|
6150
|
+
})]
|
|
6151
|
+
}),
|
|
6152
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6153
|
+
className: "lm-hint",
|
|
6154
|
+
children: transport === "stdio" ? t("transportHintStdio") : t("transportHintHttp")
|
|
6155
|
+
})
|
|
6156
|
+
]
|
|
6157
|
+
}),
|
|
6158
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6159
|
+
className: "lm-field",
|
|
6160
|
+
children: [
|
|
6161
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6162
|
+
className: "lm-label",
|
|
6163
|
+
children: t("serverName")
|
|
6164
|
+
}),
|
|
6165
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6166
|
+
className: "lm-input",
|
|
6167
|
+
value: serverName,
|
|
6168
|
+
disabled: editMcp !== void 0,
|
|
6169
|
+
onChange: (e) => setServerName(e.target.value)
|
|
6170
|
+
}),
|
|
6171
|
+
editMcp !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6172
|
+
className: "lm-hint",
|
|
6173
|
+
children: t("serverNameImmutable")
|
|
6174
|
+
})
|
|
6175
|
+
]
|
|
6176
|
+
}),
|
|
6177
|
+
transport === "stdio" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6178
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6179
|
+
className: "lm-field",
|
|
6180
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6181
|
+
className: "lm-label",
|
|
6182
|
+
children: t("command")
|
|
6183
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6184
|
+
className: "lm-input",
|
|
6185
|
+
value: command,
|
|
6186
|
+
onChange: (e) => setCommand(e.target.value)
|
|
6187
|
+
})]
|
|
6188
|
+
}),
|
|
6189
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6190
|
+
className: "lm-field",
|
|
6191
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6192
|
+
className: "lm-label",
|
|
6193
|
+
children: t("args")
|
|
6194
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6195
|
+
className: "lm-input",
|
|
6196
|
+
value: args,
|
|
6197
|
+
onChange: (e) => setArgs(e.target.value)
|
|
6198
|
+
})]
|
|
6199
|
+
}),
|
|
6200
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6201
|
+
className: "lm-field",
|
|
6202
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6203
|
+
className: "lm-label",
|
|
6204
|
+
children: t("cwd")
|
|
6205
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6206
|
+
className: "lm-input",
|
|
6207
|
+
value: cwd,
|
|
6208
|
+
onChange: (e) => setCwd(e.target.value)
|
|
6209
|
+
})]
|
|
6210
|
+
}),
|
|
6211
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6212
|
+
className: "lm-field",
|
|
6213
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6214
|
+
className: "lm-label",
|
|
6215
|
+
children: t("env")
|
|
6216
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
6217
|
+
className: "lm-input",
|
|
6218
|
+
rows: 3,
|
|
6219
|
+
value: env,
|
|
6220
|
+
onChange: (e) => setEnv(e.target.value)
|
|
6221
|
+
})]
|
|
6222
|
+
})
|
|
6223
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6224
|
+
className: "lm-field",
|
|
6225
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6226
|
+
className: "lm-label",
|
|
6227
|
+
children: t("url")
|
|
6228
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6229
|
+
className: "lm-input",
|
|
6230
|
+
value: url,
|
|
6231
|
+
onChange: (e) => setUrl(e.target.value)
|
|
6232
|
+
})]
|
|
6233
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6234
|
+
className: "lm-field",
|
|
6235
|
+
children: [
|
|
6236
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6237
|
+
className: "lm-label",
|
|
6238
|
+
children: t("headers")
|
|
6239
|
+
}),
|
|
6240
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
6241
|
+
className: "lm-input",
|
|
6242
|
+
rows: 4,
|
|
6243
|
+
value: headers,
|
|
6244
|
+
onChange: (e) => setHeaders(e.target.value)
|
|
6245
|
+
}),
|
|
6246
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6247
|
+
className: "lm-hint",
|
|
6248
|
+
children: t("headersHint")
|
|
6249
|
+
})
|
|
6250
|
+
]
|
|
6251
|
+
})] }),
|
|
6252
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6253
|
+
className: "lm-field",
|
|
6254
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6255
|
+
className: "lm-label",
|
|
6256
|
+
children: t("timeout")
|
|
6257
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6258
|
+
className: "lm-input",
|
|
6259
|
+
value: timeoutSec,
|
|
6260
|
+
placeholder: "60",
|
|
6261
|
+
onChange: (e) => setTimeoutSec(e.target.value)
|
|
6262
|
+
})]
|
|
6263
|
+
}),
|
|
6264
|
+
renderActions(() => void submitMcp())
|
|
6265
|
+
]
|
|
6266
|
+
})
|
|
6267
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6268
|
+
className: "lm-block",
|
|
6269
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6270
|
+
className: "lm-form",
|
|
6271
|
+
children: [
|
|
6272
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6273
|
+
className: "lm-field",
|
|
6274
|
+
children: [
|
|
6275
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6276
|
+
className: "lm-label",
|
|
6277
|
+
children: t("skillRoot")
|
|
6278
|
+
}),
|
|
6279
|
+
editSkill !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6280
|
+
className: "lm-input",
|
|
6281
|
+
value: t(editSkill.root === "project" ? "skillRootProject" : "skillRootUser"),
|
|
6282
|
+
disabled: true
|
|
6283
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
6284
|
+
className: "lm-input",
|
|
6285
|
+
value: skillRoot,
|
|
6286
|
+
onChange: (e) => setSkillRoot(e.target.value === "project" ? "project" : "user"),
|
|
6287
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6288
|
+
value: "user",
|
|
6289
|
+
children: t("skillRootUser")
|
|
6290
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
6291
|
+
value: "project",
|
|
6292
|
+
children: t("skillRootProject")
|
|
6293
|
+
})]
|
|
6294
|
+
}),
|
|
6295
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6296
|
+
className: "lm-hint",
|
|
6297
|
+
children: skillRoot === "project" || editSkill?.root === "project" ? t("skillRootHintProject") : t("skillRootHintUser")
|
|
6298
|
+
})
|
|
6299
|
+
]
|
|
6300
|
+
}),
|
|
6301
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6302
|
+
className: "lm-field",
|
|
6303
|
+
children: [
|
|
6304
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6305
|
+
className: "lm-label",
|
|
6306
|
+
children: t("skillDirPath")
|
|
6307
|
+
}),
|
|
6308
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6309
|
+
className: "lm-input",
|
|
6310
|
+
value: skillDir,
|
|
6311
|
+
onChange: (e) => setSkillDir(e.target.value)
|
|
6312
|
+
}),
|
|
6313
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6314
|
+
className: "lm-hint",
|
|
6315
|
+
children: t("skillDirHint")
|
|
6316
|
+
})
|
|
6317
|
+
]
|
|
6318
|
+
}),
|
|
6319
|
+
editSkill === void 0 && skillRoot === "project" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6320
|
+
className: "lm-field",
|
|
6321
|
+
children: [
|
|
6322
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6323
|
+
className: "lm-label",
|
|
6324
|
+
children: t("skillProjectPath")
|
|
6325
|
+
}),
|
|
6326
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6327
|
+
className: "lm-input",
|
|
6328
|
+
value: projectPath,
|
|
6329
|
+
onChange: (e) => setProjectPath(e.target.value)
|
|
6330
|
+
}),
|
|
6331
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6332
|
+
className: "lm-hint",
|
|
6333
|
+
children: t("skillProjectPathHint")
|
|
6334
|
+
})
|
|
6335
|
+
]
|
|
6336
|
+
}),
|
|
6337
|
+
renderActions(() => void submitSkill())
|
|
6338
|
+
]
|
|
6339
|
+
})
|
|
6340
|
+
})]
|
|
6341
|
+
})
|
|
6342
|
+
]
|
|
6343
|
+
})
|
|
6344
|
+
});
|
|
5439
6345
|
}
|
|
6346
|
+
/**
|
|
6347
|
+
* dsh's source labels for a project's own skill roots — the `project`-prefixed
|
|
6348
|
+
* providers of `@deepseek-ai/dsh-skill-filesystem`, which scan
|
|
6349
|
+
* `<projectRoot>/.dsh/skills` and `<projectRoot>/.agents/skills`. Every other
|
|
6350
|
+
* label (`user-dsh`, `user-agents`, `bundled`, `custom`, `runtime`) is a
|
|
6351
|
+
* user-level root. Shared so the server's location manager and the browser's
|
|
6352
|
+
* 全局 / 项目 grouping agree on what "project scoped" means.
|
|
6353
|
+
*/
|
|
6354
|
+
const PROJECT_SKILL_SOURCES = /* @__PURE__ */ new Set(["project-dsh", "project-agents"]);
|
|
6355
|
+
/**
|
|
6356
|
+
* Source labels for user-level skill roots whose entries this plugin can adopt:
|
|
6357
|
+
* linking the skill's own directory into the user root (where the entry becomes
|
|
6358
|
+
* editable) without touching its content. `user-dsh` is excluded because that
|
|
6359
|
+
* root is already managed, and `bundled` because a packaged skill should not be
|
|
6360
|
+
* shadowed by a user copy.
|
|
6361
|
+
*/
|
|
6362
|
+
const ADOPTABLE_SKILL_SOURCES = /* @__PURE__ */ new Set(["user-agents", "custom"]);
|
|
5440
6363
|
//#endregion
|
|
5441
6364
|
//#region src/client/CapabilitySection.tsx
|
|
5442
6365
|
/**
|
|
5443
6366
|
* ⚠️ VERIFIED AGAINST REAL rc.8 CLIENT API.
|
|
5444
6367
|
*
|
|
5445
|
-
* React section for the
|
|
6368
|
+
* React section for the 能力菜单 settings tab. Follows the real dsh client
|
|
5446
6369
|
* pattern (see `dsh-client-ui-settings-plugins`): two tabs (工具 / Skills)
|
|
5447
6370
|
* under one heading, each listing capabilities with a clickable class chip.
|
|
5448
6371
|
*
|
|
@@ -5482,6 +6405,10 @@ const CSS = `
|
|
|
5482
6405
|
.mc-section{display:flex;flex-direction:column;gap:12px;color:var(--dsw-alias-label-primary)}
|
|
5483
6406
|
.mc-heading{margin:0;font-size:18px;font-weight:600}
|
|
5484
6407
|
.mc-desc{margin:0;color:var(--dsw-alias-label-tertiary);font-size:13px}
|
|
6408
|
+
/* 说明行右侧放只读文档入口:把它从头部的计数行挪出来,计数多(Tools 常驻 ·
|
|
6409
|
+
167)时那一行不再因此折行。 */
|
|
6410
|
+
.mc-desc-row{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
6411
|
+
.mc-desc-row .mc-desc{flex:1 1 auto;min-width:0}
|
|
5485
6412
|
.mc-summary{display:flex;gap:12px;flex-wrap:wrap;justify-content:flex-end;align-items:center;padding-bottom:8px}
|
|
5486
6413
|
.mc-catalog-btn{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;line-height:20px;padding:0 10px;cursor:pointer;white-space:nowrap}
|
|
5487
6414
|
.mc-catalog-btn:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-interactive-bg-hover)}
|
|
@@ -5516,6 +6443,14 @@ body[data-ds-dark-theme] .mc-chip--disabled{color:#b8abad}
|
|
|
5516
6443
|
.mc-tab[data-active=true]:after,.mc-tab:focus-visible:after{background:var(--dsw-alias-label-primary);content:"";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}
|
|
5517
6444
|
.mc-tab:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px;color:var(--dsw-alias-label-primary);border-radius:2px}
|
|
5518
6445
|
.mc-panel{min-width:0;padding-top:12px}
|
|
6446
|
+
/* Skills panel: its first row is the 全局技能/项目技能 sub-tab bar, which sits
|
|
6447
|
+
directly under the main tab bar. It is a second level of the same control, so
|
|
6448
|
+
the two bars have to read as one stack: no panel padding at all, and the
|
|
6449
|
+
sub-tabs keep a token top padding instead of the 7px they share with the
|
|
6450
|
+
primary tabs. Together the label sits ~13px under the main label rather than
|
|
6451
|
+
~20px, with the main bar's rule between them. */
|
|
6452
|
+
.mc-panel--tight{padding-top:0}
|
|
6453
|
+
.mc-panel--tight .mc-subtabs .mc-tab{padding-top:4px}
|
|
5519
6454
|
.mc-panel-inner{display:flex;flex-direction:column;gap:14px}
|
|
5520
6455
|
.mc-group{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden}
|
|
5521
6456
|
.mc-group-header{box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;min-width:0;padding:10px 12px;background:var(--dsw-alias-bg-layer-1);border:0;color:inherit;font:inherit;text-align:left;cursor:pointer}
|
|
@@ -5536,6 +6471,11 @@ body[data-ds-dark-theme] .mc-chip--disabled{color:#b8abad}
|
|
|
5536
6471
|
body[data-ds-dark-theme] .mc-count--resident{color:#96b6d1}
|
|
5537
6472
|
body[data-ds-dark-theme] .mc-count--on-demand{color:#d4b26b}
|
|
5538
6473
|
body[data-ds-dark-theme] .mc-count--disabled{color:#b8abad}
|
|
6474
|
+
/* 「编辑」是动作,不是分类计数:沿用 chip 的尺寸以对齐,但用次要文字色、hover
|
|
6475
|
+
才变蓝加下划线。裸用 .mc-count 时会继承 .mc-section 的 label-primary(浅色
|
|
6476
|
+
主题下近黑),夹在着色的计数 chip 旁会读成一枚没有圆点的黑色 chip。 */
|
|
6477
|
+
.mc-count--action{color:var(--dsw-alias-label-secondary)}
|
|
6478
|
+
.mc-count--action:hover{color:var(--dsw-alias-state-business-primary);text-decoration:underline}
|
|
5539
6479
|
.mc-tools{border-top:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base)}
|
|
5540
6480
|
.mc-tool{display:flex;align-items:center;gap:10px;padding:7px 12px 7px 26px;font-size:13px;line-height:20px;cursor:pointer}
|
|
5541
6481
|
.mc-tool:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
@@ -5547,13 +6487,26 @@ body[data-ds-dark-theme] .mc-count--disabled{color:#b8abad}
|
|
|
5547
6487
|
.mc-tag{font-size:11px;line-height:18px;padding:0 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary)}
|
|
5548
6488
|
.mc-empty{padding:16px;text-align:center;font-size:13px;color:var(--dsw-alias-label-tertiary);border:1px dashed var(--dsw-alias-border-l2);border-radius:8px}
|
|
5549
6489
|
.mc-error{padding:12px;border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;color:var(--dsw-alias-state-error-primary);font-size:13px}
|
|
5550
|
-
.mc-error
|
|
6490
|
+
.mc-error p{margin:0}
|
|
6491
|
+
.mc-error p.mc-error-hint{margin-top:8px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
6492
|
+
.mc-error-actions{display:flex;justify-content:flex-end;margin-top:10px}
|
|
5551
6493
|
.mc-notice{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-secondary);font-size:13px}
|
|
5552
6494
|
.mc-skill{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden;background:var(--dsw-alias-bg-layer-1)}
|
|
5553
6495
|
.mc-skill-row{box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;min-width:0;padding:10px 12px;background:0 0;border:0;color:inherit;font:inherit;text-align:left;cursor:pointer}
|
|
5554
6496
|
.mc-skill-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
5555
6497
|
.mc-skill-name{font-weight:600;font-size:14px;line-height:20px;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
5556
6498
|
.mc-skill-meta{margin-left:auto;display:flex;align-items:center;gap:8px;flex:0 1 auto;min-width:0}
|
|
6499
|
+
/* A row has no room for prose: let a long source label truncate instead of
|
|
6500
|
+
pushing the row's buttons past the right edge. */
|
|
6501
|
+
.mc-source{font-size:11px;line-height:18px;color:var(--dsw-alias-label-caption);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto}
|
|
6502
|
+
/* One sentence to confirm a row action: the shared modal chrome, sized down. */
|
|
6503
|
+
.mc-confirm-dialog{width:min(420px,calc(100vw - 48px))}
|
|
6504
|
+
.mc-confirm-body{display:flex;flex-direction:column;gap:12px;padding:14px 16px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}
|
|
6505
|
+
.mc-confirm-body p{margin:0}
|
|
6506
|
+
/* A directory has no spaces to break at, and the modal is where it can show in
|
|
6507
|
+
full: wrap it instead of truncating it the way a row's 来源 slot must. */
|
|
6508
|
+
.mc-confirm-path{font-family:var(--dsw-font-markdown-code-block-font-family);word-break:break-all}
|
|
6509
|
+
.mc-confirm-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
5557
6510
|
.mc-skill-body{border-top:1px solid var(--dsw-alias-border-l1);padding:8px 12px 12px}
|
|
5558
6511
|
.mc-tree{display:flex;flex-direction:column;gap:2px;font-size:13px;line-height:20px}
|
|
5559
6512
|
.mc-tree-row{display:flex;align-items:center;gap:8px;padding:3px 4px;border-radius:6px;cursor:pointer;min-width:0}
|
|
@@ -5577,10 +6530,31 @@ if (typeof document !== "undefined" && document.querySelector(`style[data-css-id
|
|
|
5577
6530
|
tag.textContent = CSS;
|
|
5578
6531
|
document.head.appendChild(tag);
|
|
5579
6532
|
}
|
|
5580
|
-
/**
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
6533
|
+
/**
|
|
6534
|
+
* dsh's skill source labels, shown on rows this plugin cannot edit — so "why is
|
|
6535
|
+
* there no 编辑 button" has a visible answer. Labels that name one directory are
|
|
6536
|
+
* shown as that path; the rest name a category and go through the dictionary, so
|
|
6537
|
+
* none of dsh's internal labels (`custom`, `bundled`, …) reach the operator raw.
|
|
6538
|
+
*/
|
|
6539
|
+
const SOURCE_PATHS = {
|
|
6540
|
+
"user-dsh": "~/.dsh/skills",
|
|
6541
|
+
"user-agents": "~/.agents/skills",
|
|
6542
|
+
"project-dsh": "<project>/.dsh/skills",
|
|
6543
|
+
"project-agents": "<project>/.agents/skills"
|
|
6544
|
+
};
|
|
6545
|
+
/** Source labels that name no single directory; shown via `t`. */
|
|
6546
|
+
const SOURCE_LABEL_KEYS = {
|
|
6547
|
+
"custom": "sourceCustom",
|
|
6548
|
+
"bundled": "sourceBundled"
|
|
6549
|
+
};
|
|
6550
|
+
/** How to name a skill's source root on a row we cannot manage. */
|
|
6551
|
+
function sourceLabel(source, t) {
|
|
6552
|
+
if (source === void 0) return t("skillUnmanaged");
|
|
6553
|
+
const path = SOURCE_PATHS[source];
|
|
6554
|
+
if (path !== void 0) return path;
|
|
6555
|
+
const key = SOURCE_LABEL_KEYS[source];
|
|
6556
|
+
return key === void 0 ? source : t(key);
|
|
6557
|
+
}
|
|
5584
6558
|
function groupRows(rows) {
|
|
5585
6559
|
const byServer = /* @__PURE__ */ new Map();
|
|
5586
6560
|
const skills = [];
|
|
@@ -5589,7 +6563,7 @@ function groupRows(rows) {
|
|
|
5589
6563
|
skills.push(row);
|
|
5590
6564
|
continue;
|
|
5591
6565
|
}
|
|
5592
|
-
const server = row.server ??
|
|
6566
|
+
const server = row.server ?? "built-in";
|
|
5593
6567
|
const list = byServer.get(server);
|
|
5594
6568
|
if (list === void 0) byServer.set(server, [row]);
|
|
5595
6569
|
else list.push(row);
|
|
@@ -5606,8 +6580,14 @@ function countByClass(rows, cls) {
|
|
|
5606
6580
|
return rows.reduce((n, row) => row.class === cls ? n + 1 : n, 0);
|
|
5607
6581
|
}
|
|
5608
6582
|
function CapabilitySection(props) {
|
|
5609
|
-
const { remote, t, mountError
|
|
5610
|
-
const [state, setState] = (0, react.useState)(
|
|
6583
|
+
const { remote, t, mountError } = props;
|
|
6584
|
+
const [state, setState] = (0, react.useState)(() => {
|
|
6585
|
+
const cached = cachedSnapshot();
|
|
6586
|
+
return cached === void 0 ? { status: "loading" } : {
|
|
6587
|
+
status: "ready",
|
|
6588
|
+
snapshot: cached
|
|
6589
|
+
};
|
|
6590
|
+
});
|
|
5611
6591
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
5612
6592
|
const [notice, setNotice] = (0, react.useState)(null);
|
|
5613
6593
|
const [openServers, setOpenServers] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
@@ -5626,15 +6606,41 @@ function CapabilitySection(props) {
|
|
|
5626
6606
|
snapshot
|
|
5627
6607
|
})));
|
|
5628
6608
|
} catch (e) {
|
|
5629
|
-
setState({
|
|
6609
|
+
setState((prev) => prev.status === "ready" ? prev : {
|
|
5630
6610
|
status: "error",
|
|
5631
6611
|
message: String(e)
|
|
5632
6612
|
});
|
|
6613
|
+
setNotice(String(e));
|
|
5633
6614
|
}
|
|
5634
6615
|
}, [remote, mountError]);
|
|
5635
6616
|
(0, react.useEffect)(() => {
|
|
5636
6617
|
reload();
|
|
5637
6618
|
}, [reload]);
|
|
6619
|
+
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
6620
|
+
/**
|
|
6621
|
+
* Rebuild the host catalog, then re-read the classification list. Used after
|
|
6622
|
+
* registering a new source so the list reflects it without waiting for the
|
|
6623
|
+
* scheduler's debounce window.
|
|
6624
|
+
*/
|
|
6625
|
+
const refreshCatalog = (0, react.useCallback)(async () => {
|
|
6626
|
+
if (refreshing) return;
|
|
6627
|
+
setRefreshing(true);
|
|
6628
|
+
try {
|
|
6629
|
+
if (remote !== void 0) unwrap(await remote.refresh(), "capabilityPolicy.refresh");
|
|
6630
|
+
await reload();
|
|
6631
|
+
setNotice(null);
|
|
6632
|
+
} catch (e) {
|
|
6633
|
+
console.error("[capability-menu] refresh failed:", e);
|
|
6634
|
+
setNotice(t("refreshFailed"));
|
|
6635
|
+
} finally {
|
|
6636
|
+
setRefreshing(false);
|
|
6637
|
+
}
|
|
6638
|
+
}, [
|
|
6639
|
+
refreshing,
|
|
6640
|
+
remote,
|
|
6641
|
+
reload,
|
|
6642
|
+
t
|
|
6643
|
+
]);
|
|
5638
6644
|
const toggleServer = (0, react.useCallback)((server) => {
|
|
5639
6645
|
setOpenServers((prev) => {
|
|
5640
6646
|
const next = new Set(prev);
|
|
@@ -5647,6 +6653,17 @@ function CapabilitySection(props) {
|
|
|
5647
6653
|
const cycleClass = (0, react.useCallback)(async (ids, kind) => {
|
|
5648
6654
|
if (ids.length === 0 || busy) return;
|
|
5649
6655
|
setBusy(true);
|
|
6656
|
+
const from = ids.map((id) => state.status === "ready" ? state.snapshot.rows.find((r) => r.id === id)?.class : void 0).find((c) => c !== void 0) ?? "on-demand";
|
|
6657
|
+
const to = NEXT_CLASS[from];
|
|
6658
|
+
const moved = new Set(ids);
|
|
6659
|
+
setState((prev) => prev.status === "ready" ? {
|
|
6660
|
+
status: "ready",
|
|
6661
|
+
snapshot: { rows: prev.snapshot.rows.map((row) => moved.has(row.id) ? {
|
|
6662
|
+
...row,
|
|
6663
|
+
class: to,
|
|
6664
|
+
classLabel: void 0
|
|
6665
|
+
} : row) }
|
|
6666
|
+
} : prev);
|
|
5650
6667
|
try {
|
|
5651
6668
|
const config = unwrap(await remote.getConfig(), "capabilityPolicy.getConfig");
|
|
5652
6669
|
const key = kind === "skill" ? "skills" : "tools";
|
|
@@ -5660,13 +6677,11 @@ function CapabilitySection(props) {
|
|
|
5660
6677
|
const raw = set && typeof set === "object" && !Array.isArray(set) ? set[cls] : void 0;
|
|
5661
6678
|
lists[cls] = Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
|
|
5662
6679
|
}
|
|
5663
|
-
const from = ids.map((id) => state.status === "ready" ? state.snapshot.rows.find((r) => r.id === id)?.class : void 0).find((c) => c !== void 0) ?? "on-demand";
|
|
5664
|
-
const to = NEXT_CLASS[from];
|
|
5665
6680
|
for (const cls of CLASS_KEYS) lists[cls] = lists[cls].filter((id) => !ids.includes(id));
|
|
5666
6681
|
lists[to] = [...lists[to], ...ids];
|
|
5667
6682
|
const nextLists = {};
|
|
5668
6683
|
for (const cls of CLASS_KEYS) nextLists[cls] = lists[cls];
|
|
5669
|
-
await remote.updateConfig({ [key]: nextLists });
|
|
6684
|
+
unwrap(await remote.updateConfig({ [key]: nextLists }), "capabilityPolicy.updateConfig");
|
|
5670
6685
|
const next = await loadSnapshot(remote);
|
|
5671
6686
|
setState({
|
|
5672
6687
|
status: "ready",
|
|
@@ -5697,7 +6712,22 @@ function CapabilitySection(props) {
|
|
|
5697
6712
|
}),
|
|
5698
6713
|
state.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5699
6714
|
className: "mc-error",
|
|
5700
|
-
children: [
|
|
6715
|
+
children: [
|
|
6716
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: state.message }),
|
|
6717
|
+
state.message.includes("Failed to fetch") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6718
|
+
className: "mc-error-hint",
|
|
6719
|
+
children: t("carrierFailureHint")
|
|
6720
|
+
}),
|
|
6721
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6722
|
+
className: "mc-error-actions",
|
|
6723
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6724
|
+
type: "button",
|
|
6725
|
+
className: "mc-catalog-btn",
|
|
6726
|
+
onClick: () => void reload(),
|
|
6727
|
+
children: t("retry")
|
|
6728
|
+
})
|
|
6729
|
+
})
|
|
6730
|
+
]
|
|
5701
6731
|
}),
|
|
5702
6732
|
notice !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5703
6733
|
className: "mc-notice",
|
|
@@ -5712,16 +6742,19 @@ function CapabilitySection(props) {
|
|
|
5712
6742
|
t,
|
|
5713
6743
|
onTabChange: setActiveTab,
|
|
5714
6744
|
onToggleServer: toggleServer,
|
|
5715
|
-
onCycle: cycleClass
|
|
6745
|
+
onCycle: cycleClass,
|
|
6746
|
+
onRefresh: () => void refreshCatalog(),
|
|
6747
|
+
refreshing,
|
|
6748
|
+
onNotice: setNotice
|
|
5716
6749
|
})
|
|
5717
6750
|
]
|
|
5718
6751
|
});
|
|
5719
6752
|
}
|
|
5720
6753
|
function ReadyBody(props) {
|
|
5721
|
-
const { remote, snapshot, openServers, busy, activeTab, t, onTabChange, onToggleServer, onCycle } = props;
|
|
6754
|
+
const { remote, snapshot, openServers, busy, activeTab, t, onTabChange, onToggleServer, onCycle, onRefresh, refreshing, onNotice } = props;
|
|
5722
6755
|
const { servers, skills } = groupRows(snapshot.rows);
|
|
5723
|
-
const projectSkills = skills.filter((skill) =>
|
|
5724
|
-
const globalSkills = skills.filter((skill) => !
|
|
6756
|
+
const projectSkills = skills.filter((skill) => PROJECT_SKILL_SOURCES.has(skill.source ?? ""));
|
|
6757
|
+
const globalSkills = skills.filter((skill) => !PROJECT_SKILL_SOURCES.has(skill.source ?? ""));
|
|
5725
6758
|
const [skillTab, setSkillTab] = (0, react.useState)("global");
|
|
5726
6759
|
const statRows = activeTab === "tools" ? snapshot.rows.filter((r) => r.kind === "tool") : skillTab === "project" ? projectSkills : globalSkills;
|
|
5727
6760
|
const summary = CLASS_KEYS.map((cls) => ({
|
|
@@ -5758,6 +6791,93 @@ function ReadyBody(props) {
|
|
|
5758
6791
|
/** 能力目录弹层状态:查看三档策略配置 + 按需能力目录文件。 */
|
|
5759
6792
|
const [catalogDocs, setCatalogDocs] = (0, react.useState)(null);
|
|
5760
6793
|
const [catalogTab, setCatalogTab] = (0, react.useState)("policy");
|
|
6794
|
+
/** 注册能力 modal; its default sub-tab follows `activeTab`. */
|
|
6795
|
+
const [registerOpen, setRegisterOpen] = (0, react.useState)(false);
|
|
6796
|
+
/** 编辑 target; at most one is set. */
|
|
6797
|
+
const [editMcp, setEditMcp] = (0, react.useState)(void 0);
|
|
6798
|
+
const [editSkill, setEditSkill] = (0, react.useState)(void 0);
|
|
6799
|
+
/**
|
|
6800
|
+
* Skill directories registered under the skill root. Only those can be
|
|
6801
|
+
* edited: a project or bundled skill has no row to repoint, so its row gets
|
|
6802
|
+
* no 编辑 button rather than a button that always fails.
|
|
6803
|
+
*/
|
|
6804
|
+
const [editableSkills, setEditableSkills] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
6805
|
+
const skillSignature = skills.map((skill) => `${skill.id}\u0000${skill.source ?? ""}`).join("");
|
|
6806
|
+
(0, react.useEffect)(() => {
|
|
6807
|
+
let cancelled = false;
|
|
6808
|
+
(async () => {
|
|
6809
|
+
try {
|
|
6810
|
+
const rows = unwrap(await remote.listSkillLocations(), "capabilityPolicy.listSkillLocations");
|
|
6811
|
+
if (!cancelled) setEditableSkills(new Set(rows.map((row) => row.skillName ?? row.name)));
|
|
6812
|
+
} catch {}
|
|
6813
|
+
})();
|
|
6814
|
+
return () => {
|
|
6815
|
+
cancelled = true;
|
|
6816
|
+
};
|
|
6817
|
+
}, [remote, skillSignature]);
|
|
6818
|
+
/** Open the 编辑 form for the MCP server behind a Tools-tab group header. */
|
|
6819
|
+
const openMcpEdit = (0, react.useCallback)(async (serverName) => {
|
|
6820
|
+
try {
|
|
6821
|
+
const found = unwrap(await remote.listLocations(), "capabilityPolicy.listLocations").find((row) => row.serverName === serverName);
|
|
6822
|
+
if (found === void 0) {
|
|
6823
|
+
onNotice(t("notEditable"));
|
|
6824
|
+
return;
|
|
6825
|
+
}
|
|
6826
|
+
setEditMcp(found);
|
|
6827
|
+
} catch (e) {
|
|
6828
|
+
onNotice(String(e));
|
|
6829
|
+
}
|
|
6830
|
+
}, [
|
|
6831
|
+
remote,
|
|
6832
|
+
t,
|
|
6833
|
+
onNotice
|
|
6834
|
+
]);
|
|
6835
|
+
/**
|
|
6836
|
+
* Adopt a skill that dsh discovered from a user-level root this plugin reads
|
|
6837
|
+
* but does not manage: link its own directory into the user root so it becomes
|
|
6838
|
+
* an editable entry. The content is untouched.
|
|
6839
|
+
*/
|
|
6840
|
+
const adoptSkill = (0, react.useCallback)(async (name) => {
|
|
6841
|
+
try {
|
|
6842
|
+
const entry = unwrap(await remote.adoptSkillLocation(name), "capabilityPolicy.adoptSkillLocation");
|
|
6843
|
+
onNotice(t("skillAdopted", { path: entry }));
|
|
6844
|
+
onRefresh();
|
|
6845
|
+
} catch (e) {
|
|
6846
|
+
onNotice(String(e));
|
|
6847
|
+
}
|
|
6848
|
+
}, [
|
|
6849
|
+
remote,
|
|
6850
|
+
t,
|
|
6851
|
+
onNotice,
|
|
6852
|
+
onRefresh
|
|
6853
|
+
]);
|
|
6854
|
+
/**
|
|
6855
|
+
* Open the 编辑 form for a managed skill entry. `name` is the skill's declared
|
|
6856
|
+
* name, which is what the row and the panel address it by — an entry is
|
|
6857
|
+
* matched on that rather than on its own, possibly different, name. A bare
|
|
6858
|
+
* name can exist in both the user root and a project root, so the row's source
|
|
6859
|
+
* decides which entry the click meant; without it we fall back to the first
|
|
6860
|
+
* match.
|
|
6861
|
+
*/
|
|
6862
|
+
const openSkillEdit = (0, react.useCallback)(async (name, source) => {
|
|
6863
|
+
try {
|
|
6864
|
+
const rows = unwrap(await remote.listSkillLocations(), "capabilityPolicy.listSkillLocations");
|
|
6865
|
+
const wanted = PROJECT_SKILL_SOURCES.has(source ?? "") ? "project" : "user";
|
|
6866
|
+
const named = rows.filter((row) => (row.skillName ?? row.name) === name);
|
|
6867
|
+
const found = named.find((row) => row.root === wanted) ?? named[0];
|
|
6868
|
+
if (found === void 0) {
|
|
6869
|
+
onNotice(t("notEditable"));
|
|
6870
|
+
return;
|
|
6871
|
+
}
|
|
6872
|
+
setEditSkill(found);
|
|
6873
|
+
} catch (e) {
|
|
6874
|
+
onNotice(String(e));
|
|
6875
|
+
}
|
|
6876
|
+
}, [
|
|
6877
|
+
remote,
|
|
6878
|
+
t,
|
|
6879
|
+
onNotice
|
|
6880
|
+
]);
|
|
5761
6881
|
/** Fetch and show the two read-only catalog documents. */
|
|
5762
6882
|
const openCatalogDocs = (0, react.useCallback)(async () => {
|
|
5763
6883
|
setCatalogDocs({ status: "loading" });
|
|
@@ -5779,9 +6899,17 @@ function ReadyBody(props) {
|
|
|
5779
6899
|
className: "mc-heading",
|
|
5780
6900
|
children: t("title")
|
|
5781
6901
|
}),
|
|
5782
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
5783
|
-
className: "mc-desc",
|
|
5784
|
-
children:
|
|
6902
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6903
|
+
className: "mc-desc-row",
|
|
6904
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6905
|
+
className: "mc-desc",
|
|
6906
|
+
children: t("desc")
|
|
6907
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6908
|
+
type: "button",
|
|
6909
|
+
className: "mc-catalog-btn",
|
|
6910
|
+
onClick: () => void openCatalogDocs(),
|
|
6911
|
+
children: t("viewCatalog")
|
|
6912
|
+
})]
|
|
5785
6913
|
}),
|
|
5786
6914
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5787
6915
|
className: "mc-tabs",
|
|
@@ -5808,23 +6936,33 @@ function ReadyBody(props) {
|
|
|
5808
6936
|
})]
|
|
5809
6937
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5810
6938
|
className: "mc-summary",
|
|
5811
|
-
children: [
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
6939
|
+
children: [
|
|
6940
|
+
summary.map(({ cls, count }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6941
|
+
className: `mc-chip mc-chip--${cls}`,
|
|
6942
|
+
children: [
|
|
6943
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6944
|
+
className: `mc-dot mc-dot--${cls}`,
|
|
6945
|
+
"aria-hidden": "true"
|
|
6946
|
+
}),
|
|
6947
|
+
t(CLASS_SHORT_KEYS[cls]),
|
|
6948
|
+
" · ",
|
|
6949
|
+
count
|
|
6950
|
+
]
|
|
6951
|
+
}, cls)),
|
|
6952
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6953
|
+
type: "button",
|
|
6954
|
+
className: "mc-catalog-btn",
|
|
6955
|
+
onClick: () => onRefresh(),
|
|
6956
|
+
disabled: refreshing,
|
|
6957
|
+
children: refreshing ? t("refreshing") : t("refresh")
|
|
6958
|
+
}),
|
|
6959
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6960
|
+
type: "button",
|
|
6961
|
+
className: "mc-catalog-btn",
|
|
6962
|
+
onClick: () => setRegisterOpen(true),
|
|
6963
|
+
children: t("registerCapability")
|
|
6964
|
+
})
|
|
6965
|
+
]
|
|
5828
6966
|
})]
|
|
5829
6967
|
}),
|
|
5830
6968
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -5863,15 +7001,15 @@ function ReadyBody(props) {
|
|
|
5863
7001
|
}),
|
|
5864
7002
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5865
7003
|
className: "mc-server-name",
|
|
5866
|
-
children: server ===
|
|
7004
|
+
children: server === "built-in" ? t("builtInGroup") : server
|
|
5867
7005
|
}),
|
|
5868
7006
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5869
7007
|
className: "mc-server-count",
|
|
5870
7008
|
children: t("toolCount", { count: tools.length })
|
|
5871
7009
|
}),
|
|
5872
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7010
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5873
7011
|
className: "mc-server-meta",
|
|
5874
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7012
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5875
7013
|
className: "mc-counts",
|
|
5876
7014
|
children: counts.filter(({ count }) => count > 0).map(({ cls, count }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5877
7015
|
type: "button",
|
|
@@ -5892,7 +7030,16 @@ function ReadyBody(props) {
|
|
|
5892
7030
|
count
|
|
5893
7031
|
]
|
|
5894
7032
|
}, cls))
|
|
5895
|
-
})
|
|
7033
|
+
}), server !== "built-in" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7034
|
+
type: "button",
|
|
7035
|
+
className: "mc-count mc-count--action",
|
|
7036
|
+
disabled: busy,
|
|
7037
|
+
onClick: (e) => {
|
|
7038
|
+
e.stopPropagation();
|
|
7039
|
+
openMcpEdit(server);
|
|
7040
|
+
},
|
|
7041
|
+
children: t("edit")
|
|
7042
|
+
})]
|
|
5896
7043
|
})
|
|
5897
7044
|
]
|
|
5898
7045
|
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -5943,7 +7090,7 @@ function ReadyBody(props) {
|
|
|
5943
7090
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5944
7091
|
role: "tabpanel",
|
|
5945
7092
|
hidden: activeTab !== "skills",
|
|
5946
|
-
className: "mc-panel",
|
|
7093
|
+
className: "mc-panel mc-panel--tight",
|
|
5947
7094
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5948
7095
|
className: "mc-panel-inner",
|
|
5949
7096
|
children: skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -5978,7 +7125,10 @@ function ReadyBody(props) {
|
|
|
5978
7125
|
remote,
|
|
5979
7126
|
busy,
|
|
5980
7127
|
t,
|
|
5981
|
-
onCycle
|
|
7128
|
+
onCycle,
|
|
7129
|
+
editableSkills,
|
|
7130
|
+
onEditSkill: openSkillEdit,
|
|
7131
|
+
onAdoptSkill: adoptSkill
|
|
5982
7132
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5983
7133
|
className: "mc-empty",
|
|
5984
7134
|
children: t("emptyGlobalSkills")
|
|
@@ -5987,7 +7137,10 @@ function ReadyBody(props) {
|
|
|
5987
7137
|
remote,
|
|
5988
7138
|
busy,
|
|
5989
7139
|
t,
|
|
5990
|
-
onCycle
|
|
7140
|
+
onCycle,
|
|
7141
|
+
editableSkills,
|
|
7142
|
+
onEditSkill: openSkillEdit,
|
|
7143
|
+
onAdoptSkill: adoptSkill
|
|
5991
7144
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5992
7145
|
className: "mc-empty",
|
|
5993
7146
|
children: t("emptyProjectSkills")
|
|
@@ -6035,6 +7188,22 @@ function ReadyBody(props) {
|
|
|
6035
7188
|
]
|
|
6036
7189
|
})
|
|
6037
7190
|
}),
|
|
7191
|
+
(registerOpen || editMcp !== void 0 || editSkill !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LocationModal, {
|
|
7192
|
+
remote,
|
|
7193
|
+
t,
|
|
7194
|
+
defaultKind: activeTab === "skills" ? "skill" : "mcp",
|
|
7195
|
+
...editMcp !== void 0 ? { editMcp } : {},
|
|
7196
|
+
...editSkill !== void 0 ? { editSkill } : {},
|
|
7197
|
+
onClose: () => {
|
|
7198
|
+
setRegisterOpen(false);
|
|
7199
|
+
setEditMcp(void 0);
|
|
7200
|
+
setEditSkill(void 0);
|
|
7201
|
+
},
|
|
7202
|
+
onChanged: (notice) => {
|
|
7203
|
+
onRefresh();
|
|
7204
|
+
if (notice !== void 0) onNotice(notice);
|
|
7205
|
+
}
|
|
7206
|
+
}),
|
|
6038
7207
|
catalogDocs !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6039
7208
|
className: "mc-preview-mask",
|
|
6040
7209
|
onClick: () => setCatalogDocs(null),
|
|
@@ -6108,7 +7277,9 @@ function ReadyBody(props) {
|
|
|
6108
7277
|
] });
|
|
6109
7278
|
}
|
|
6110
7279
|
function SkillList(props) {
|
|
6111
|
-
const { skills, remote, busy, t, onCycle } = props;
|
|
7280
|
+
const { skills, remote, busy, t, onCycle, editableSkills, onEditSkill, onAdoptSkill } = props;
|
|
7281
|
+
/** Skill id whose 纳入管理 is waiting for a confirmation click. */
|
|
7282
|
+
const [confirmAdopt, setConfirmAdopt] = (0, react.useState)(null);
|
|
6112
7283
|
const [openSkill, setOpenSkill] = (0, react.useState)(null);
|
|
6113
7284
|
const [tree, setTree] = (0, react.useState)({
|
|
6114
7285
|
open: {},
|
|
@@ -6277,89 +7448,165 @@ function SkillList(props) {
|
|
|
6277
7448
|
}, relPath);
|
|
6278
7449
|
});
|
|
6279
7450
|
};
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
"
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
7451
|
+
/** The row the 纳入管理 confirmation is for, so the dialog can name it and
|
|
7452
|
+
show the directory the click will link. */
|
|
7453
|
+
const confirmAdoptRow = confirmAdopt === null ? void 0 : skills.find((row) => row.id === confirmAdopt);
|
|
7454
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
7455
|
+
skills.map((skill) => {
|
|
7456
|
+
const open = openSkill === skill.id;
|
|
7457
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7458
|
+
className: "mc-skill",
|
|
7459
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7460
|
+
className: "mc-skill-row",
|
|
7461
|
+
role: "button",
|
|
7462
|
+
tabIndex: 0,
|
|
7463
|
+
"aria-expanded": open,
|
|
7464
|
+
onClick: () => void toggleSkill(skill.id),
|
|
7465
|
+
onKeyDown: (e) => {
|
|
7466
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7467
|
+
e.preventDefault();
|
|
7468
|
+
toggleSkill(skill.id);
|
|
7469
|
+
}
|
|
7470
|
+
},
|
|
7471
|
+
children: [
|
|
7472
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTriangleRightFill14, {
|
|
7473
|
+
size: 12,
|
|
7474
|
+
className: `mc-chevron${open ? " mc-chevron--open" : ""}`
|
|
7475
|
+
}),
|
|
7476
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7477
|
+
className: "mc-skill-name",
|
|
7478
|
+
children: skill.name
|
|
7479
|
+
}),
|
|
7480
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
7481
|
+
className: "mc-skill-meta",
|
|
7482
|
+
children: [
|
|
7483
|
+
skill.mandatory && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7484
|
+
className: "mc-tag",
|
|
7485
|
+
children: t("mandatory")
|
|
7486
|
+
}),
|
|
7487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
7488
|
+
type: "button",
|
|
7489
|
+
className: `mc-count mc-count--${skill.class}`,
|
|
7490
|
+
disabled: busy || skill.mandatory,
|
|
7491
|
+
title: skill.classLabel,
|
|
7492
|
+
onClick: (e) => {
|
|
7493
|
+
e.stopPropagation();
|
|
7494
|
+
onCycle([skill.id], "skill");
|
|
7495
|
+
},
|
|
7496
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7497
|
+
className: `mc-dot mc-dot--${skill.class}`,
|
|
7498
|
+
"aria-hidden": "true"
|
|
7499
|
+
}), t(CLASS_SHORT_KEYS[skill.class])]
|
|
7500
|
+
}),
|
|
7501
|
+
!editableSkills.has(skill.id) && (ADOPTABLE_SKILL_SOURCES.has(skill.source ?? "") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7502
|
+
type: "button",
|
|
7503
|
+
className: "mc-count mc-count--action",
|
|
7504
|
+
disabled: busy,
|
|
7505
|
+
title: t("adoptSkillHint"),
|
|
7506
|
+
onClick: (e) => {
|
|
7507
|
+
e.stopPropagation();
|
|
7508
|
+
setConfirmAdopt(skill.id);
|
|
7509
|
+
},
|
|
7510
|
+
children: t("adoptSkill")
|
|
7511
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7512
|
+
className: "mc-source",
|
|
7513
|
+
title: t("skillSourceHint"),
|
|
7514
|
+
children: t("skillSource", { source: sourceLabel(skill.source, t) })
|
|
7515
|
+
})),
|
|
7516
|
+
editableSkills.has(skill.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7517
|
+
type: "button",
|
|
7518
|
+
className: "mc-count mc-count--action",
|
|
7519
|
+
disabled: busy,
|
|
7520
|
+
onClick: (e) => {
|
|
7521
|
+
e.stopPropagation();
|
|
7522
|
+
onEditSkill(skill.id, skill.source);
|
|
7523
|
+
},
|
|
7524
|
+
children: t("edit")
|
|
7525
|
+
})
|
|
7526
|
+
]
|
|
7527
|
+
})
|
|
7528
|
+
]
|
|
7529
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7530
|
+
className: "mc-skill-body",
|
|
7531
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7532
|
+
className: "mc-tree",
|
|
7533
|
+
children: renderEntries(tree.dirs[`${skill.id}:`], skill.id, "") ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7534
|
+
className: "mc-tree-row",
|
|
7535
|
+
children: "…"
|
|
7536
|
+
})
|
|
6324
7537
|
})
|
|
6325
|
-
]
|
|
6326
|
-
}
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
7538
|
+
})]
|
|
7539
|
+
}, skill.id);
|
|
7540
|
+
}),
|
|
7541
|
+
confirmAdopt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7542
|
+
className: "mc-preview-mask",
|
|
7543
|
+
onClick: () => setConfirmAdopt(null),
|
|
7544
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7545
|
+
className: "mc-preview mc-confirm-dialog",
|
|
7546
|
+
onClick: (e) => e.stopPropagation(),
|
|
7547
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7548
|
+
className: "mc-preview-head",
|
|
7549
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7550
|
+
className: "mc-preview-title",
|
|
7551
|
+
children: t("adoptSkillTitle", { name: confirmAdoptRow?.name ?? confirmAdopt })
|
|
6333
7552
|
})
|
|
6334
|
-
})
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
7553
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7554
|
+
className: "mc-confirm-body",
|
|
7555
|
+
children: [
|
|
7556
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("adoptSkillHint") }),
|
|
7557
|
+
confirmAdoptRow !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7558
|
+
className: "mc-confirm-path",
|
|
7559
|
+
children: t("skillSource", { source: confirmAdoptRow.path ?? sourceLabel(confirmAdoptRow.source, t) })
|
|
7560
|
+
}),
|
|
7561
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7562
|
+
className: "mc-confirm-actions",
|
|
7563
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7564
|
+
type: "button",
|
|
7565
|
+
className: "mc-catalog-btn",
|
|
7566
|
+
onClick: () => setConfirmAdopt(null),
|
|
7567
|
+
children: t("cancel")
|
|
7568
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7569
|
+
type: "button",
|
|
7570
|
+
className: "mc-catalog-btn",
|
|
7571
|
+
onClick: () => {
|
|
7572
|
+
const id = confirmAdopt;
|
|
7573
|
+
setConfirmAdopt(null);
|
|
7574
|
+
onAdoptSkill(id);
|
|
7575
|
+
},
|
|
7576
|
+
children: t("adoptSkill")
|
|
7577
|
+
})]
|
|
7578
|
+
})
|
|
7579
|
+
]
|
|
6353
7580
|
})]
|
|
6354
|
-
})
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
7581
|
+
})
|
|
7582
|
+
}),
|
|
7583
|
+
preview !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7584
|
+
className: "mc-preview-mask",
|
|
7585
|
+
onClick: () => setPreview(null),
|
|
7586
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7587
|
+
className: "mc-preview",
|
|
7588
|
+
onClick: (e) => e.stopPropagation(),
|
|
7589
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7590
|
+
className: "mc-preview-head",
|
|
7591
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7592
|
+
className: "mc-preview-title",
|
|
7593
|
+
children: preview.relPath
|
|
7594
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7595
|
+
type: "button",
|
|
7596
|
+
className: "mc-preview-close",
|
|
7597
|
+
onClick: () => setPreview(null),
|
|
7598
|
+
children: t("previewClose")
|
|
7599
|
+
})]
|
|
7600
|
+
}), preview.content !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
7601
|
+
className: "mc-preview-body",
|
|
7602
|
+
children: preview.content
|
|
7603
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7604
|
+
className: "mc-preview-hint",
|
|
7605
|
+
children: preview.error ?? "…"
|
|
7606
|
+
})]
|
|
7607
|
+
})
|
|
6361
7608
|
})
|
|
6362
|
-
|
|
7609
|
+
] });
|
|
6363
7610
|
}
|
|
6364
7611
|
//#endregion
|
|
6365
7612
|
//#region src/client/index.ts
|
|
@@ -6374,21 +7621,18 @@ const inject = [
|
|
|
6374
7621
|
"locale",
|
|
6375
7622
|
"remote"
|
|
6376
7623
|
];
|
|
6377
|
-
/** Register the
|
|
7624
|
+
/** Register the 能力菜单 section once `settings.section` is on the ledger. */
|
|
6378
7625
|
async function apply(ctx) {
|
|
6379
7626
|
const zh = {
|
|
6380
|
-
nav: "
|
|
6381
|
-
title: "
|
|
7627
|
+
nav: "能力菜单",
|
|
7628
|
+
title: "能力菜单",
|
|
6382
7629
|
desc: "管理工具与技能的 常驻 / 按需 / 禁用 三档分类。",
|
|
6383
7630
|
resident: "Resident(常驻上下文)",
|
|
6384
7631
|
"on-demand": "On-demand(按需发现)",
|
|
6385
7632
|
disabled: "Disabled(禁用)",
|
|
6386
|
-
kind: "类型",
|
|
6387
|
-
class: "分类",
|
|
6388
7633
|
tool: "tool",
|
|
6389
7634
|
skill: "skill",
|
|
6390
7635
|
mandatory: "meta",
|
|
6391
|
-
rules: "规则",
|
|
6392
7636
|
toolsGroup: "Tools",
|
|
6393
7637
|
skillsGroup: "Skills",
|
|
6394
7638
|
builtInGroup: "系统内置",
|
|
@@ -6407,10 +7651,69 @@ async function apply(ctx) {
|
|
|
6407
7651
|
previewClose: "关闭",
|
|
6408
7652
|
detailNotFound: "未找到该工具的详情",
|
|
6409
7653
|
cycleOverridden: "分类未生效:{count} 个能力被更高优先级规则覆盖(如通配规则),可移除对应通配规则后重试",
|
|
6410
|
-
|
|
7654
|
+
refresh: "刷新",
|
|
7655
|
+
refreshing: "刷新中…",
|
|
7656
|
+
refreshFailed: "刷新失败,请查看日志",
|
|
7657
|
+
retry: "重试",
|
|
7658
|
+
carrierFailureHint: "请求未到达服务端:浏览器与 dsh 之间的连接已断开(Failed to fetch 属传输层失败,服务端方法未执行)。若刚重启过 dsh web,请先硬刷新页面(Ctrl/Cmd+Shift+R)再重试。",
|
|
7659
|
+
registerCapability: "注册能力",
|
|
7660
|
+
editMcp: "编辑 MCP 服务器",
|
|
7661
|
+
editSkillNamed: "编辑 Skill 目录:{name}",
|
|
7662
|
+
edit: "编辑",
|
|
7663
|
+
save: "保存",
|
|
7664
|
+
remove: "移除",
|
|
7665
|
+
cancel: "取消",
|
|
7666
|
+
confirmRemove: "确认移除",
|
|
7667
|
+
confirmRemoveMcp: "移除 MCP 服务器「{name}」?其 patch 文件中的配置行(含 headers、环境变量)将被删除,mcp__{name}__* 工具随之消失。",
|
|
7668
|
+
confirmRemoveSkillLink: "移除 Skill「{name}」?仅删除 ~/.dsh/skills 下的软链,源目录不受影响。",
|
|
7669
|
+
confirmRemoveSkillDir: "移除 Skill「{name}」?该项位于 ~/.dsh/skills 下且非软链,将连同文件递归删除,且不可恢复。",
|
|
7670
|
+
confirmSaveAnyway: "仍然保存",
|
|
7671
|
+
saveConfirmRealDir: "「{name}」这个条目是真实目录、不是软链:保存会先把它连同文件递归删除,再改为指向新路径,且不可恢复。",
|
|
7672
|
+
register: "注册",
|
|
7673
|
+
notEditable: "该项未在注册表中(可能是项目技能或内置技能),无法编辑。",
|
|
7674
|
+
entryNotFound: "目标已不存在,可能已被移除。",
|
|
7675
|
+
mcpServers: "MCP 服务器",
|
|
7676
|
+
skillDirs: "Skill 目录",
|
|
7677
|
+
skillDirPath: "技能来源路径",
|
|
7678
|
+
skillRoot: "技能位置",
|
|
7679
|
+
skillRootUser: "全局技能(~/.dsh/skills)",
|
|
7680
|
+
skillRootProject: "项目技能(<项目根>/.dsh/skills)",
|
|
7681
|
+
skillRootHintUser: "所有会话都能看到该技能。",
|
|
7682
|
+
skillRootHintProject: "只对 cwd 落在该项目内的会话可见。",
|
|
7683
|
+
skillProjectPath: "目标项目路径",
|
|
7684
|
+
skillProjectPathHint: "项目内任意一个已存在的路径即可;项目根按 dsh 的规则确定(向上找最近的 .git),技能写进 <项目根>/.dsh/skills。",
|
|
7685
|
+
skillRegisteredAt: "已注册到 {path}",
|
|
7686
|
+
skillRepointed: "已改为指向 {dir}",
|
|
7687
|
+
skillAdopted: "已纳入管理:{path}",
|
|
7688
|
+
skillSource: "来源:{source}",
|
|
7689
|
+
skillSourceHint: "该技能由 dsh 从其它根发现,不在本插件管理的技能目录里,因此没有「编辑」。",
|
|
7690
|
+
skillUnmanaged: "未纳入管理",
|
|
7691
|
+
sourceCustom: "自定义技能目录",
|
|
7692
|
+
sourceBundled: "随 dsh 预置",
|
|
7693
|
+
adoptSkill: "纳入管理",
|
|
7694
|
+
adoptSkillHint: "把它软链进 dsh 的技能根目录(默认 ~/.dsh/skills),内容不动;之后就能编辑与移除了。",
|
|
7695
|
+
adoptSkillTitle: "纳入管理「{name}」?",
|
|
7696
|
+
skillDirHint: "目录内需有 SKILL.md(按 dsh 的 skill 格式校验)。技能名以 SKILL.md 里声明的为准,目录名只决定注册后的软链名,两者不同也可以。",
|
|
7697
|
+
serverName: "serverName",
|
|
7698
|
+
serverNameImmutable: "serverName 不可修改:它构成工具名前缀 mcp__<serverName>__<tool>,并已被既有会话历史与权限规则引用;修改后这些记录将不再匹配。",
|
|
7699
|
+
transport: "传输方式",
|
|
7700
|
+
transportStdio: "stdio(本地子进程)",
|
|
7701
|
+
transportHttp: "streamable-http(HTTP MCP 端点)",
|
|
7702
|
+
transportHintStdio: "由客户端将该 MCP server 作为子进程启动,JSON-RPC 报文经标准输入 / 输出交换。",
|
|
7703
|
+
transportHintHttp: "该 MCP server 作为独立进程运行,可服务多个客户端连接;客户端经单个支持 POST / GET 的 HTTP 端点(MCP endpoint)与其通信。",
|
|
7704
|
+
command: "命令",
|
|
7705
|
+
args: "参数(空格分隔)",
|
|
7706
|
+
cwd: "工作目录",
|
|
7707
|
+
env: "环境变量",
|
|
7708
|
+
url: "URL",
|
|
7709
|
+
headers: "请求头",
|
|
7710
|
+
headersHint: "每行一个 Header,格式 Key: Value;Bearer token 等认证凭据在此填写。",
|
|
7711
|
+
timeout: "超时(秒)",
|
|
7712
|
+
timeoutInvalid: "超时须为数字,单位为秒。",
|
|
7713
|
+
viewCatalog: "策略与目录",
|
|
6411
7714
|
catalogPolicy: "三档策略配置",
|
|
6412
7715
|
catalogOnDemand: "按需能力目录",
|
|
6413
|
-
catalogPolicyNote: "
|
|
7716
|
+
catalogPolicyNote: "实时生成;点选改动会在停手后自动写回 cordis.patch.yml(未列出规则的能力默认常驻)",
|
|
6414
7717
|
catalogDisabled: "按需能力目录未启用(catalogFile 为空)",
|
|
6415
7718
|
catalogUnreadable: "按需能力目录文件读取失败"
|
|
6416
7719
|
};
|
|
@@ -6421,12 +7724,9 @@ async function apply(ctx) {
|
|
|
6421
7724
|
resident: "Resident",
|
|
6422
7725
|
"on-demand": "On-demand",
|
|
6423
7726
|
disabled: "Disabled",
|
|
6424
|
-
kind: "kind",
|
|
6425
|
-
class: "class",
|
|
6426
7727
|
tool: "tool",
|
|
6427
7728
|
skill: "skill",
|
|
6428
7729
|
mandatory: "meta",
|
|
6429
|
-
rules: "rules",
|
|
6430
7730
|
toolsGroup: "Tools",
|
|
6431
7731
|
skillsGroup: "Skills",
|
|
6432
7732
|
builtInGroup: "System built-in",
|
|
@@ -6445,10 +7745,69 @@ async function apply(ctx) {
|
|
|
6445
7745
|
previewClose: "Close",
|
|
6446
7746
|
detailNotFound: "Tool detail not found",
|
|
6447
7747
|
cycleOverridden: "Classification not applied: {count} capability(ies) overridden by a higher-priority rule (e.g. a wildcard). Remove the matching wildcard rule and retry.",
|
|
6448
|
-
|
|
7748
|
+
refresh: "Refresh",
|
|
7749
|
+
refreshing: "Refreshing…",
|
|
7750
|
+
refreshFailed: "Refresh failed; see the log",
|
|
7751
|
+
retry: "Retry",
|
|
7752
|
+
carrierFailureHint: "The request never reached the server: the browser connection to dsh is broken (\"Failed to fetch\" is a transport failure, so no server method ran). If dsh web was just restarted, hard-refresh the page (Ctrl/Cmd+Shift+R) and retry.",
|
|
7753
|
+
registerCapability: "Register capability",
|
|
7754
|
+
editMcp: "Edit MCP server",
|
|
7755
|
+
editSkillNamed: "Edit skill directory: {name}",
|
|
7756
|
+
edit: "Edit",
|
|
7757
|
+
save: "Save",
|
|
7758
|
+
remove: "Remove",
|
|
7759
|
+
cancel: "Cancel",
|
|
7760
|
+
confirmRemove: "Confirm removal",
|
|
7761
|
+
confirmRemoveMcp: "Remove the MCP server \"{name}\"? Its config row in the patch file (headers and environment included) is deleted, and the mcp__{name}__* tools disappear with it.",
|
|
7762
|
+
confirmRemoveSkillLink: "Unregister the skill \"{name}\"? Only the symlink under ~/.dsh/skills is removed; the source directory is left untouched.",
|
|
7763
|
+
confirmRemoveSkillDir: "Remove the skill \"{name}\"? It sits under ~/.dsh/skills and is not a symlink, so it will be deleted recursively with all of its files. This cannot be undone.",
|
|
7764
|
+
confirmSaveAnyway: "Save anyway",
|
|
7765
|
+
saveConfirmRealDir: "The entry \"{name}\" is a real directory, not a symlink: saving deletes it and its files recursively before repointing it, and that cannot be undone.",
|
|
7766
|
+
register: "Register",
|
|
7767
|
+
notEditable: "This entry is not in the registry (a project or bundled skill), so it cannot be edited.",
|
|
7768
|
+
entryNotFound: "The target no longer exists; it may have been removed.",
|
|
7769
|
+
mcpServers: "MCP servers",
|
|
7770
|
+
skillDirs: "Skill directories",
|
|
7771
|
+
skillDirPath: "Skill source path",
|
|
7772
|
+
skillRoot: "Skill location",
|
|
7773
|
+
skillRootUser: "Global (~/.dsh/skills)",
|
|
7774
|
+
skillRootProject: "Project (<projectRoot>/.dsh/skills)",
|
|
7775
|
+
skillRootHintUser: "Visible to every session.",
|
|
7776
|
+
skillRootHintProject: "Visible only to sessions whose cwd sits inside that project.",
|
|
7777
|
+
skillProjectPath: "Target project path",
|
|
7778
|
+
skillProjectPathHint: "Any existing path inside the project; the project root is derived the way dsh derives it (nearest .git above it) and the skill is written under <projectRoot>/.dsh/skills.",
|
|
7779
|
+
skillRegisteredAt: "Registered at {path}",
|
|
7780
|
+
skillRepointed: "Repointed to {dir}",
|
|
7781
|
+
skillAdopted: "Adopted: {path}",
|
|
7782
|
+
skillSource: "Source: {source}",
|
|
7783
|
+
skillSourceHint: "dsh found this skill in another root, not in a skill directory this plugin manages, so there is no Edit button.",
|
|
7784
|
+
skillUnmanaged: "Not managed here",
|
|
7785
|
+
sourceCustom: "custom skill dirs",
|
|
7786
|
+
sourceBundled: "bundled with dsh",
|
|
7787
|
+
adoptSkill: "Adopt",
|
|
7788
|
+
adoptSkillHint: "Link it into dsh's skill root (default ~/.dsh/skills); the content is untouched, and it becomes editable and removable.",
|
|
7789
|
+
adoptSkillTitle: "Adopt \"{name}\"?",
|
|
7790
|
+
skillDirHint: "The directory must hold a SKILL.md in dsh's skill format. The skill name is the one declared in SKILL.md; the directory name only names the link this registers, so the two may differ.",
|
|
7791
|
+
serverName: "serverName",
|
|
7792
|
+
serverNameImmutable: "serverName is immutable: it forms the tool name prefix mcp__<serverName>__<tool> and is referenced by existing session history and permission rules, which stop matching once it changes.",
|
|
7793
|
+
transport: "Transport",
|
|
7794
|
+
transportStdio: "stdio (local subprocess)",
|
|
7795
|
+
transportHttp: "streamable-http (HTTP MCP endpoint)",
|
|
7796
|
+
transportHintStdio: "The client launches the MCP server as a subprocess and exchanges JSON-RPC messages over its standard input and output.",
|
|
7797
|
+
transportHintHttp: "The server runs as an independent process that can handle multiple client connections; the client reaches it over a single HTTP endpoint (the MCP endpoint) supporting POST and GET.",
|
|
7798
|
+
command: "Command",
|
|
7799
|
+
args: "Args (space separated)",
|
|
7800
|
+
cwd: "Working directory",
|
|
7801
|
+
env: "Environment",
|
|
7802
|
+
url: "URL",
|
|
7803
|
+
headers: "Headers",
|
|
7804
|
+
headersHint: "One header per line as Key: Value; credentials such as a Bearer token go here.",
|
|
7805
|
+
timeout: "Timeout (seconds)",
|
|
7806
|
+
timeoutInvalid: "Timeout must be a number of seconds.",
|
|
7807
|
+
viewCatalog: "Policy & catalog",
|
|
6449
7808
|
catalogPolicy: "Policy (effective)",
|
|
6450
7809
|
catalogOnDemand: "On-demand catalog",
|
|
6451
|
-
catalogPolicyNote: "Generated live from the effective policy
|
|
7810
|
+
catalogPolicyNote: "Generated live from the effective policy; clicked changes are written back to cordis.patch.yml once you stop. Capabilities without a rule default to Resident.",
|
|
6452
7811
|
catalogDisabled: "On-demand catalog emission is disabled (catalogFile is empty).",
|
|
6453
7812
|
catalogUnreadable: "Failed to read the on-demand catalog file."
|
|
6454
7813
|
};
|
|
@@ -6474,17 +7833,10 @@ async function apply(ctx) {
|
|
|
6474
7833
|
}
|
|
6475
7834
|
};
|
|
6476
7835
|
const injected = () => {
|
|
6477
|
-
const namespace = remote();
|
|
6478
|
-
const remoteKeys = namespace == null ? void 0 : Object.keys(namespace).filter((k) => [
|
|
6479
|
-
"getConfig",
|
|
6480
|
-
"updateConfig",
|
|
6481
|
-
"classifyAll"
|
|
6482
|
-
].includes(k)).join(",");
|
|
6483
7836
|
return {
|
|
6484
|
-
remote:
|
|
7837
|
+
remote: remote(),
|
|
6485
7838
|
t,
|
|
6486
|
-
...mountError !== void 0 ? { mountError } : {}
|
|
6487
|
-
...remoteKeys !== void 0 ? { remoteKeys } : {}
|
|
7839
|
+
...mountError !== void 0 ? { mountError } : {}
|
|
6488
7840
|
};
|
|
6489
7841
|
};
|
|
6490
7842
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|