@morehao/dsh-skills-console 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -65
- package/client.js +457 -457
- package/cordis.patch.yml +2 -1
- package/lib/agent-table.json +133 -64
- package/lib/core/agents.js +68 -9
- package/lib/core/exporter.js +137 -0
- package/lib/core/inventory.js +73 -39
- package/lib/core/migrations.js +178 -0
- package/lib/core/paths.js +13 -0
- package/lib/core/policy.js +373 -0
- package/lib/core/remote.js +3 -1
- package/lib/core/roots.js +182 -0
- package/lib/core/service.js +391 -137
- package/lib/core/shadow.js +195 -0
- package/lib/core/skill-md.js +23 -4
- package/lib/core/state.js +293 -42
- package/lib/core/visibility.js +145 -0
- package/lib/index.js +27 -0
- package/lib/routes.js +13 -3
- package/package.json +3 -2
package/cordis.patch.yml
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# dsh-skills-console bundle patch
|
|
2
2
|
#
|
|
3
3
|
# 一个 Host half(lib/index.js)加一个 Web Client half(client.js):
|
|
4
|
-
# Host
|
|
4
|
+
# Host 负责清单扫描 / native installer 安装更新删除 / 软链 / 订阅与更新事务;
|
|
5
|
+
# Client 在设置页渲染「技能控制台」(已安装 / 订阅两个 tab,可切到侧栏独立面板)。
|
|
5
6
|
- insert:
|
|
6
7
|
- id: dsh-skills-console
|
|
7
8
|
name: '@morehao/dsh-skills-console'
|
package/lib/agent-table.json
CHANGED
|
@@ -1,331 +1,400 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "skills CLI agents table",
|
|
3
|
+
"upstream": {
|
|
4
|
+
"name": "skills",
|
|
5
|
+
"version": "1.7.4",
|
|
6
|
+
"from": "dist/cli.mjs"
|
|
7
|
+
},
|
|
3
8
|
"entries": [
|
|
4
9
|
{
|
|
5
10
|
"key": "adal",
|
|
6
11
|
"name": "AdaL",
|
|
7
|
-
"dir": ".adal/skills"
|
|
12
|
+
"dir": ".adal/skills",
|
|
13
|
+
"universal": false
|
|
8
14
|
},
|
|
9
15
|
{
|
|
10
16
|
"key": "aider-desk",
|
|
11
17
|
"name": "AiderDesk",
|
|
12
|
-
"dir": ".aider-desk/skills"
|
|
18
|
+
"dir": ".aider-desk/skills",
|
|
19
|
+
"universal": false
|
|
13
20
|
},
|
|
14
21
|
{
|
|
15
22
|
"key": "amp",
|
|
16
23
|
"name": "Amp",
|
|
17
24
|
"dir": "agents/skills",
|
|
18
|
-
"base": "config"
|
|
25
|
+
"base": "config",
|
|
26
|
+
"universal": true
|
|
19
27
|
},
|
|
20
28
|
{
|
|
21
29
|
"key": "antigravity",
|
|
22
30
|
"name": "Antigravity",
|
|
23
|
-
"dir": ".gemini/antigravity/skills"
|
|
31
|
+
"dir": ".gemini/antigravity/skills",
|
|
32
|
+
"universal": true
|
|
24
33
|
},
|
|
25
34
|
{
|
|
26
35
|
"key": "antigravity-cli",
|
|
27
36
|
"name": "Antigravity CLI",
|
|
28
|
-
"dir": ".gemini/antigravity-cli/skills"
|
|
37
|
+
"dir": ".gemini/antigravity-cli/skills",
|
|
38
|
+
"universal": true
|
|
29
39
|
},
|
|
30
40
|
{
|
|
31
41
|
"key": "astrbot",
|
|
32
42
|
"name": "AstrBot",
|
|
33
|
-
"dir": ".astrbot/data/skills"
|
|
43
|
+
"dir": ".astrbot/data/skills",
|
|
44
|
+
"universal": false
|
|
34
45
|
},
|
|
35
46
|
{
|
|
36
47
|
"key": "augment",
|
|
37
48
|
"name": "Augment",
|
|
38
|
-
"dir": ".augment/skills"
|
|
49
|
+
"dir": ".augment/skills",
|
|
50
|
+
"universal": false
|
|
39
51
|
},
|
|
40
52
|
{
|
|
41
53
|
"key": "autohand-code",
|
|
42
54
|
"name": "Autohand Code CLI",
|
|
43
|
-
"dir": ".autohand/skills"
|
|
55
|
+
"dir": ".autohand/skills",
|
|
56
|
+
"universal": false
|
|
44
57
|
},
|
|
45
58
|
{
|
|
46
59
|
"key": "bob",
|
|
47
60
|
"name": "IBM Bob",
|
|
48
|
-
"dir": ".bob/skills"
|
|
61
|
+
"dir": ".bob/skills",
|
|
62
|
+
"universal": false
|
|
49
63
|
},
|
|
50
64
|
{
|
|
51
65
|
"key": "claude-code",
|
|
52
66
|
"name": "Claude Code",
|
|
53
|
-
"dir": ".claude/skills"
|
|
67
|
+
"dir": ".claude/skills",
|
|
68
|
+
"universal": false
|
|
54
69
|
},
|
|
55
70
|
{
|
|
56
71
|
"key": "codearts-agent",
|
|
57
72
|
"name": "CodeArts Agent",
|
|
58
|
-
"dir": ".codeartsdoer/skills"
|
|
73
|
+
"dir": ".codeartsdoer/skills",
|
|
74
|
+
"universal": false
|
|
59
75
|
},
|
|
60
76
|
{
|
|
61
77
|
"key": "codebuddy",
|
|
62
78
|
"name": "CodeBuddy",
|
|
63
|
-
"dir": ".codebuddy/skills"
|
|
79
|
+
"dir": ".codebuddy/skills",
|
|
80
|
+
"universal": false
|
|
64
81
|
},
|
|
65
82
|
{
|
|
66
83
|
"key": "codemaker",
|
|
67
84
|
"name": "Codemaker",
|
|
68
|
-
"dir": ".codemaker/skills"
|
|
85
|
+
"dir": ".codemaker/skills",
|
|
86
|
+
"universal": false
|
|
69
87
|
},
|
|
70
88
|
{
|
|
71
89
|
"key": "codestudio",
|
|
72
90
|
"name": "Code Studio",
|
|
73
|
-
"dir": ".codestudio/skills"
|
|
91
|
+
"dir": ".codestudio/skills",
|
|
92
|
+
"universal": false
|
|
74
93
|
},
|
|
75
94
|
{
|
|
76
95
|
"key": "command-code",
|
|
77
96
|
"name": "Command Code",
|
|
78
|
-
"dir": ".commandcode/skills"
|
|
97
|
+
"dir": ".commandcode/skills",
|
|
98
|
+
"universal": false
|
|
79
99
|
},
|
|
80
100
|
{
|
|
81
101
|
"key": "continue",
|
|
82
102
|
"name": "Continue",
|
|
83
|
-
"dir": ".continue/skills"
|
|
103
|
+
"dir": ".continue/skills",
|
|
104
|
+
"universal": false
|
|
84
105
|
},
|
|
85
106
|
{
|
|
86
107
|
"key": "cortex",
|
|
87
108
|
"name": "Cortex Code",
|
|
88
|
-
"dir": ".snowflake/cortex/skills"
|
|
109
|
+
"dir": ".snowflake/cortex/skills",
|
|
110
|
+
"universal": false
|
|
89
111
|
},
|
|
90
112
|
{
|
|
91
113
|
"key": "crush",
|
|
92
114
|
"name": "Crush",
|
|
93
115
|
"dir": "crush/skills",
|
|
94
|
-
"base": "config"
|
|
116
|
+
"base": "config",
|
|
117
|
+
"universal": false
|
|
95
118
|
},
|
|
96
119
|
{
|
|
97
120
|
"key": "cursor",
|
|
98
121
|
"name": "Cursor",
|
|
99
|
-
"dir": ".cursor/skills"
|
|
122
|
+
"dir": ".cursor/skills",
|
|
123
|
+
"universal": true
|
|
100
124
|
},
|
|
101
125
|
{
|
|
102
126
|
"key": "deepagents",
|
|
103
127
|
"name": "Deep Agents",
|
|
104
|
-
"dir": ".deepagents/agent/skills"
|
|
128
|
+
"dir": ".deepagents/agent/skills",
|
|
129
|
+
"universal": true
|
|
105
130
|
},
|
|
106
131
|
{
|
|
107
132
|
"key": "devin",
|
|
108
133
|
"name": "Devin for Terminal",
|
|
109
134
|
"dir": "devin/skills",
|
|
110
|
-
"base": "config"
|
|
135
|
+
"base": "config",
|
|
136
|
+
"universal": false
|
|
111
137
|
},
|
|
112
138
|
{
|
|
113
139
|
"key": "droid",
|
|
114
140
|
"name": "Droid",
|
|
115
|
-
"dir": ".factory/skills"
|
|
141
|
+
"dir": ".factory/skills",
|
|
142
|
+
"universal": true
|
|
116
143
|
},
|
|
117
144
|
{
|
|
118
145
|
"key": "firebender",
|
|
119
146
|
"name": "Firebender",
|
|
120
|
-
"dir": ".firebender/skills"
|
|
147
|
+
"dir": ".firebender/skills",
|
|
148
|
+
"universal": true
|
|
121
149
|
},
|
|
122
150
|
{
|
|
123
151
|
"key": "forgecode",
|
|
124
152
|
"name": "ForgeCode",
|
|
125
|
-
"dir": ".forge/skills"
|
|
153
|
+
"dir": ".forge/skills",
|
|
154
|
+
"universal": false
|
|
126
155
|
},
|
|
127
156
|
{
|
|
128
157
|
"key": "gemini-cli",
|
|
129
158
|
"name": "Gemini CLI",
|
|
130
|
-
"dir": ".gemini/skills"
|
|
159
|
+
"dir": ".gemini/skills",
|
|
160
|
+
"universal": true
|
|
131
161
|
},
|
|
132
162
|
{
|
|
133
163
|
"key": "github-copilot",
|
|
134
164
|
"name": "GitHub Copilot",
|
|
135
|
-
"dir": ".copilot/skills"
|
|
165
|
+
"dir": ".copilot/skills",
|
|
166
|
+
"universal": true
|
|
136
167
|
},
|
|
137
168
|
{
|
|
138
169
|
"key": "goose",
|
|
139
170
|
"name": "Goose",
|
|
140
171
|
"dir": "goose/skills",
|
|
141
|
-
"base": "config"
|
|
172
|
+
"base": "config",
|
|
173
|
+
"universal": false
|
|
142
174
|
},
|
|
143
175
|
{
|
|
144
176
|
"key": "grok",
|
|
145
177
|
"name": "Grok Build",
|
|
146
|
-
"dir": ".grok/skills"
|
|
178
|
+
"dir": ".grok/skills",
|
|
179
|
+
"universal": false
|
|
147
180
|
},
|
|
148
181
|
{
|
|
149
182
|
"key": "hermes-agent",
|
|
150
183
|
"name": "Hermes Agent",
|
|
151
|
-
"dir": ".hermes/skills"
|
|
184
|
+
"dir": ".hermes/skills",
|
|
185
|
+
"universal": false
|
|
152
186
|
},
|
|
153
187
|
{
|
|
154
188
|
"key": "iflow-cli",
|
|
155
189
|
"name": "iFlow CLI",
|
|
156
|
-
"dir": ".iflow/skills"
|
|
190
|
+
"dir": ".iflow/skills",
|
|
191
|
+
"universal": false
|
|
157
192
|
},
|
|
158
193
|
{
|
|
159
194
|
"key": "inference-sh",
|
|
160
195
|
"name": "inference.sh",
|
|
161
|
-
"dir": ".inferencesh/skills"
|
|
196
|
+
"dir": ".inferencesh/skills",
|
|
197
|
+
"universal": false
|
|
162
198
|
},
|
|
163
199
|
{
|
|
164
200
|
"key": "jazz",
|
|
165
201
|
"name": "Jazz",
|
|
166
|
-
"dir": ".jazz/skills"
|
|
202
|
+
"dir": ".jazz/skills",
|
|
203
|
+
"universal": false
|
|
167
204
|
},
|
|
168
205
|
{
|
|
169
206
|
"key": "junie",
|
|
170
207
|
"name": "Junie",
|
|
171
|
-
"dir": ".junie/skills"
|
|
208
|
+
"dir": ".junie/skills",
|
|
209
|
+
"universal": false
|
|
172
210
|
},
|
|
173
211
|
{
|
|
174
212
|
"key": "kilo",
|
|
175
213
|
"name": "Kilo Code",
|
|
176
|
-
"dir": ".kilo/skills"
|
|
214
|
+
"dir": ".kilo/skills",
|
|
215
|
+
"universal": true
|
|
177
216
|
},
|
|
178
217
|
{
|
|
179
218
|
"key": "kimchi",
|
|
180
219
|
"name": "Kimchi",
|
|
181
220
|
"dir": "kimchi/harness/skills",
|
|
182
|
-
"base": "config"
|
|
221
|
+
"base": "config",
|
|
222
|
+
"universal": false
|
|
183
223
|
},
|
|
184
224
|
{
|
|
185
225
|
"key": "kiro-cli",
|
|
186
226
|
"name": "Kiro CLI",
|
|
187
|
-
"dir": ".kiro/skills"
|
|
227
|
+
"dir": ".kiro/skills",
|
|
228
|
+
"universal": false
|
|
188
229
|
},
|
|
189
230
|
{
|
|
190
231
|
"key": "kode",
|
|
191
232
|
"name": "Kode",
|
|
192
|
-
"dir": ".kode/skills"
|
|
233
|
+
"dir": ".kode/skills",
|
|
234
|
+
"universal": false
|
|
193
235
|
},
|
|
194
236
|
{
|
|
195
237
|
"key": "lingma",
|
|
196
238
|
"name": "Lingma",
|
|
197
|
-
"dir": ".lingma/skills"
|
|
239
|
+
"dir": ".lingma/skills",
|
|
240
|
+
"universal": false
|
|
198
241
|
},
|
|
199
242
|
{
|
|
200
243
|
"key": "mcpjam",
|
|
201
244
|
"name": "MCPJam",
|
|
202
|
-
"dir": ".mcpjam/skills"
|
|
245
|
+
"dir": ".mcpjam/skills",
|
|
246
|
+
"universal": false
|
|
203
247
|
},
|
|
204
248
|
{
|
|
205
249
|
"key": "minimax-code",
|
|
206
250
|
"name": "MiniMax Code",
|
|
207
|
-
"dir": ".minimax/skills"
|
|
251
|
+
"dir": ".minimax/skills",
|
|
252
|
+
"universal": false
|
|
208
253
|
},
|
|
209
254
|
{
|
|
210
255
|
"key": "mistral-vibe",
|
|
211
256
|
"name": "Mistral Vibe",
|
|
212
|
-
"dir": ".vibe/skills"
|
|
257
|
+
"dir": ".vibe/skills",
|
|
258
|
+
"universal": false
|
|
213
259
|
},
|
|
214
260
|
{
|
|
215
261
|
"key": "moxby",
|
|
216
262
|
"name": "Moxby",
|
|
217
|
-
"dir": ".moxby/skills"
|
|
263
|
+
"dir": ".moxby/skills",
|
|
264
|
+
"universal": false
|
|
218
265
|
},
|
|
219
266
|
{
|
|
220
267
|
"key": "mux",
|
|
221
268
|
"name": "Mux",
|
|
222
|
-
"dir": ".mux/skills"
|
|
269
|
+
"dir": ".mux/skills",
|
|
270
|
+
"universal": false
|
|
223
271
|
},
|
|
224
272
|
{
|
|
225
273
|
"key": "neovate",
|
|
226
274
|
"name": "Neovate",
|
|
227
|
-
"dir": ".neovate/skills"
|
|
275
|
+
"dir": ".neovate/skills",
|
|
276
|
+
"universal": false
|
|
228
277
|
},
|
|
229
278
|
{
|
|
230
279
|
"key": "ona",
|
|
231
280
|
"name": "Ona",
|
|
232
|
-
"dir": ".ona/skills"
|
|
281
|
+
"dir": ".ona/skills",
|
|
282
|
+
"universal": false
|
|
233
283
|
},
|
|
234
284
|
{
|
|
235
285
|
"key": "openclaw",
|
|
236
286
|
"name": "OpenClaw",
|
|
237
|
-
"dir": ".openclaw/skills"
|
|
287
|
+
"dir": ".openclaw/skills",
|
|
288
|
+
"universal": false
|
|
238
289
|
},
|
|
239
290
|
{
|
|
240
291
|
"key": "opencode",
|
|
241
292
|
"name": "OpenCode",
|
|
242
293
|
"dir": "opencode/skills",
|
|
243
|
-
"base": "config"
|
|
294
|
+
"base": "config",
|
|
295
|
+
"universal": true
|
|
244
296
|
},
|
|
245
297
|
{
|
|
246
298
|
"key": "openhands",
|
|
247
299
|
"name": "OpenHands",
|
|
248
|
-
"dir": ".openhands/skills"
|
|
300
|
+
"dir": ".openhands/skills",
|
|
301
|
+
"universal": false
|
|
249
302
|
},
|
|
250
303
|
{
|
|
251
304
|
"key": "pochi",
|
|
252
305
|
"name": "Pochi",
|
|
253
|
-
"dir": ".pochi/skills"
|
|
306
|
+
"dir": ".pochi/skills",
|
|
307
|
+
"universal": false
|
|
254
308
|
},
|
|
255
309
|
{
|
|
256
310
|
"key": "posit-assistant",
|
|
257
311
|
"name": "Posit Assistant",
|
|
258
|
-
"dir": ".posit/assistant/skills"
|
|
312
|
+
"dir": ".posit/assistant/skills",
|
|
313
|
+
"universal": false
|
|
259
314
|
},
|
|
260
315
|
{
|
|
261
316
|
"key": "qoder",
|
|
262
317
|
"name": "Qoder",
|
|
263
|
-
"dir": ".qoder/skills"
|
|
318
|
+
"dir": ".qoder/skills",
|
|
319
|
+
"universal": false
|
|
264
320
|
},
|
|
265
321
|
{
|
|
266
322
|
"key": "qoder-cn",
|
|
267
323
|
"name": "Qoder CN",
|
|
268
|
-
"dir": ".qoder-cn/skills"
|
|
324
|
+
"dir": ".qoder-cn/skills",
|
|
325
|
+
"universal": false
|
|
269
326
|
},
|
|
270
327
|
{
|
|
271
328
|
"key": "qwen-code",
|
|
272
329
|
"name": "Qwen Code",
|
|
273
|
-
"dir": ".qwen/skills"
|
|
330
|
+
"dir": ".qwen/skills",
|
|
331
|
+
"universal": false
|
|
274
332
|
},
|
|
275
333
|
{
|
|
276
334
|
"key": "reasonix",
|
|
277
335
|
"name": "Reasonix",
|
|
278
|
-
"dir": ".reasonix/skills"
|
|
336
|
+
"dir": ".reasonix/skills",
|
|
337
|
+
"universal": false
|
|
279
338
|
},
|
|
280
339
|
{
|
|
281
340
|
"key": "roo",
|
|
282
341
|
"name": "Roo Code",
|
|
283
|
-
"dir": ".roo/skills"
|
|
342
|
+
"dir": ".roo/skills",
|
|
343
|
+
"universal": false
|
|
284
344
|
},
|
|
285
345
|
{
|
|
286
346
|
"key": "rovodev",
|
|
287
347
|
"name": "Rovo Dev",
|
|
288
|
-
"dir": ".rovodev/skills"
|
|
348
|
+
"dir": ".rovodev/skills",
|
|
349
|
+
"universal": false
|
|
289
350
|
},
|
|
290
351
|
{
|
|
291
352
|
"key": "tabnine-cli",
|
|
292
353
|
"name": "Tabnine CLI",
|
|
293
|
-
"dir": ".tabnine/agent/skills"
|
|
354
|
+
"dir": ".tabnine/agent/skills",
|
|
355
|
+
"universal": false
|
|
294
356
|
},
|
|
295
357
|
{
|
|
296
358
|
"key": "terramind",
|
|
297
359
|
"name": "Terramind",
|
|
298
|
-
"dir": ".terramind/skills"
|
|
360
|
+
"dir": ".terramind/skills",
|
|
361
|
+
"universal": false
|
|
299
362
|
},
|
|
300
363
|
{
|
|
301
364
|
"key": "tinycloud",
|
|
302
365
|
"name": "Tinycloud",
|
|
303
|
-
"dir": ".tinycloud/skills"
|
|
366
|
+
"dir": ".tinycloud/skills",
|
|
367
|
+
"universal": false
|
|
304
368
|
},
|
|
305
369
|
{
|
|
306
370
|
"key": "trae",
|
|
307
371
|
"name": "Trae",
|
|
308
|
-
"dir": ".trae/skills"
|
|
372
|
+
"dir": ".trae/skills",
|
|
373
|
+
"universal": false
|
|
309
374
|
},
|
|
310
375
|
{
|
|
311
376
|
"key": "trae-cn",
|
|
312
377
|
"name": "Trae CN",
|
|
313
|
-
"dir": ".trae-cn/skills"
|
|
378
|
+
"dir": ".trae-cn/skills",
|
|
379
|
+
"universal": false
|
|
314
380
|
},
|
|
315
381
|
{
|
|
316
382
|
"key": "windsurf",
|
|
317
383
|
"name": "Windsurf",
|
|
318
|
-
"dir": ".codeium/windsurf/skills"
|
|
384
|
+
"dir": ".codeium/windsurf/skills",
|
|
385
|
+
"universal": false
|
|
319
386
|
},
|
|
320
387
|
{
|
|
321
388
|
"key": "zcode",
|
|
322
389
|
"name": "ZCode",
|
|
323
|
-
"dir": ".zcode/skills"
|
|
390
|
+
"dir": ".zcode/skills",
|
|
391
|
+
"universal": false
|
|
324
392
|
},
|
|
325
393
|
{
|
|
326
394
|
"key": "zencoder",
|
|
327
395
|
"name": "Zencoder",
|
|
328
|
-
"dir": ".zencoder/skills"
|
|
396
|
+
"dir": ".zencoder/skills",
|
|
397
|
+
"universal": false
|
|
329
398
|
}
|
|
330
399
|
]
|
|
331
400
|
}
|
package/lib/core/agents.js
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { projectSkillsDir } from './paths.js';
|
|
5
|
+
import { dshScanRootPaths } from './roots.js';
|
|
5
6
|
|
|
6
7
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
7
8
|
const table = JSON.parse(fs.readFileSync(path.join(here, '..', 'agent-table.json'), 'utf8'));
|
|
@@ -9,6 +10,32 @@ const table = JSON.parse(fs.readFileSync(path.join(here, '..', 'agent-table.json
|
|
|
9
10
|
/** CLI agent 表里拥有独立目录的条目(`.agents/skills` 型的 universal 条目已排除,见 F23)。 */
|
|
10
11
|
export const CLI_AGENT_DIRS = table.entries;
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* 该 agent 是否**也**读 `~/.agents/skills`(共享根)。
|
|
15
|
+
*
|
|
16
|
+
* `'yes'` 表示「不必导出也看得见」;`'no'` 表示确实只读自己的目录;
|
|
17
|
+
* `'unknown'` 表示没验证过。表里的条目都是「有私有目录」的,所以默认 `unknown` ——
|
|
18
|
+
* 有私有目录**不等于**不读共享根:OpenCode / Cursor 都有私有目录,却也都读
|
|
19
|
+
* `~/.agents/skills`,这正是 v1 判断错的地方。要改某一行,先给出可复现的依据。
|
|
20
|
+
*/
|
|
21
|
+
export const SHARED_HOME_VERIFIED = Object.freeze({
|
|
22
|
+
// 权威来源是 `lib/agent-table.json` 的 `universal` 位(由 `npm run sync:agents`
|
|
23
|
+
// 从上游 skills CLI 的 `skillsDir === '.agents/skills'` 生成),这张表只放
|
|
24
|
+
// 表里没有、或需要人工推翻上游判断的条目。加条目时写清依据与日期。
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const TABLE_BY_KEY = new Map(CLI_AGENT_DIRS.map((entry) => [entry.key, entry]));
|
|
28
|
+
|
|
29
|
+
export function sharedHomeOf(key, entry = {}) {
|
|
30
|
+
if (entry.sharedHome === 'yes' || entry.sharedHome === 'no') return entry.sharedHome;
|
|
31
|
+
// 上游把「自己也读 `.agents/skills`」的 agent 标成 universal:安装只进 canonical,
|
|
32
|
+
// 不给它们建链。这一位就是「需不需要导出」的答案;调用方没带 entry 时回表里查。
|
|
33
|
+
const source = typeof entry.universal === 'boolean' ? entry : TABLE_BY_KEY.get(key) || entry;
|
|
34
|
+
if (source.universal === true) return 'yes';
|
|
35
|
+
if (source.universal === false) return 'no';
|
|
36
|
+
return SHARED_HOME_VERIFIED[key] || 'unknown';
|
|
37
|
+
}
|
|
38
|
+
|
|
12
39
|
export class UnknownTargetError extends Error {
|
|
13
40
|
constructor(target) {
|
|
14
41
|
super(`unknown target: ${target}`);
|
|
@@ -18,10 +45,42 @@ export class UnknownTargetError extends Error {
|
|
|
18
45
|
}
|
|
19
46
|
|
|
20
47
|
/**
|
|
21
|
-
* 目标注册表:`dsh-global` / `
|
|
48
|
+
* 目标注册表:`dsh-global` / `project:<abs>` / `agent:<key>` / `custom:<id>`。
|
|
22
49
|
* 发现只做 `lstat` 探测根目录是否存在,不递归;不接受调用方传路径(防穿越)。
|
|
23
50
|
*/
|
|
24
51
|
export function createRegistry({ paths, getState, existsSync = fs.existsSync }) {
|
|
52
|
+
// 用户级 DSH 扫描根(项目级按 projectRoot 现算)。导出资格的唯一判据从这里派生,
|
|
53
|
+
// 不再靠 `kind === 'dsh'` 之类的身份判断。
|
|
54
|
+
const userScanRoots = new Set(dshScanRootPaths(paths));
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 这个目录能不能作为导出目标?不能时给出原因(与 `exportSkills` 的 skip reason 同名)。
|
|
58
|
+
*
|
|
59
|
+
* - `shared-home`:目标就是 canonical 自己(多一层防御,表里已排除 universal 条目);
|
|
60
|
+
* - `dsh-native-root`:目标是 DSH 的扫描根。往这里建链是把可见性伪装成链接,
|
|
61
|
+
* 而扫描根里本来就有真身(direct 模式);导出在这里没有意义;
|
|
62
|
+
* - `shared-root`:该 Agent 自己也读 `~/.agents/skills`,装好就看得见。
|
|
63
|
+
*/
|
|
64
|
+
function exportBlockedFor(dir, { sharedHome = 'unknown', projectRoot = null } = {}) {
|
|
65
|
+
const resolved = path.resolve(dir);
|
|
66
|
+
if (resolved === path.resolve(paths.userAgentsSkills)) return 'shared-home';
|
|
67
|
+
const scanRoots = projectRoot
|
|
68
|
+
? new Set(dshScanRootPaths(paths, { projectRoot }))
|
|
69
|
+
: userScanRoots;
|
|
70
|
+
if (scanRoots.has(resolved)) return 'dsh-native-root';
|
|
71
|
+
if (sharedHome === 'yes') return 'shared-root';
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** 给条目补上导出资格:`exportable` 给 UI/筛选直接用,`exportBlocked` 给导出器当原因。 */
|
|
76
|
+
function withExport(entry, { projectRoot = null } = {}) {
|
|
77
|
+
const exportBlocked = exportBlockedFor(entry.dir, {
|
|
78
|
+
sharedHome: entry.sharedHome ?? 'unknown',
|
|
79
|
+
projectRoot,
|
|
80
|
+
});
|
|
81
|
+
return { ...entry, exportBlocked, exportable: exportBlocked === null };
|
|
82
|
+
}
|
|
83
|
+
|
|
25
84
|
function customEntries() {
|
|
26
85
|
const state = typeof getState === 'function' ? getState() : getState;
|
|
27
86
|
return (state?.agents?.custom || []).filter((item) => item && item.id && item.dir);
|
|
@@ -35,8 +94,9 @@ export function createRegistry({ paths, getState, existsSync = fs.existsSync })
|
|
|
35
94
|
key: 'dsh-global',
|
|
36
95
|
label: 'dsh(全局)',
|
|
37
96
|
dir: paths.dshGlobalSkills,
|
|
38
|
-
|
|
39
|
-
|
|
97
|
+
// DSH 在 direct 模式下必然读共享根(canonical 就是 rank 500);canonical 被挪走时
|
|
98
|
+
// 这一位退回 unknown —— 那种情况本插件不提供可见性兜底(见 /diagnostics 的 warning)。
|
|
99
|
+
sharedHome: paths.canonicalScanned ? 'yes' : 'unknown',
|
|
40
100
|
},
|
|
41
101
|
...CLI_AGENT_DIRS.map((entry) => ({
|
|
42
102
|
target: `agent:${entry.key}`,
|
|
@@ -44,7 +104,7 @@ export function createRegistry({ paths, getState, existsSync = fs.existsSync })
|
|
|
44
104
|
key: entry.key,
|
|
45
105
|
label: entry.name,
|
|
46
106
|
dir: path.join(entry.base === 'config' ? paths.configHome : paths.home, entry.dir),
|
|
47
|
-
|
|
107
|
+
sharedHome: sharedHomeOf(entry.key, entry),
|
|
48
108
|
})),
|
|
49
109
|
...customEntries().map((entry) => ({
|
|
50
110
|
target: `custom:${entry.id}`,
|
|
@@ -52,20 +112,19 @@ export function createRegistry({ paths, getState, existsSync = fs.existsSync })
|
|
|
52
112
|
key: entry.id,
|
|
53
113
|
label: entry.label || entry.id,
|
|
54
114
|
dir: entry.dir,
|
|
55
|
-
|
|
115
|
+
sharedHome: 'unknown',
|
|
56
116
|
})),
|
|
57
117
|
];
|
|
58
118
|
}
|
|
59
119
|
|
|
60
120
|
function projectEntry(projectRoot) {
|
|
61
|
-
return {
|
|
121
|
+
return withExport({
|
|
62
122
|
target: `project:${projectRoot}`,
|
|
63
123
|
kind: 'project',
|
|
64
124
|
key: projectRoot,
|
|
65
125
|
label: path.basename(projectRoot) || projectRoot,
|
|
66
126
|
dir: projectSkillsDir(projectRoot),
|
|
67
|
-
|
|
68
|
-
};
|
|
127
|
+
}, { projectRoot });
|
|
69
128
|
}
|
|
70
129
|
|
|
71
130
|
return {
|
|
@@ -80,6 +139,7 @@ export function createRegistry({ paths, getState, existsSync = fs.existsSync })
|
|
|
80
139
|
seen.add(key);
|
|
81
140
|
return true;
|
|
82
141
|
})
|
|
142
|
+
.map((entry) => withExport(entry))
|
|
83
143
|
.map((entry) => ({ ...entry, exists: existsSync(entry.dir) }));
|
|
84
144
|
},
|
|
85
145
|
|
|
@@ -92,7 +152,6 @@ export function createRegistry({ paths, getState, existsSync = fs.existsSync })
|
|
|
92
152
|
const entry = projectEntry(projectRoot);
|
|
93
153
|
return { ...entry, exists: existsSync(entry.dir) };
|
|
94
154
|
},
|
|
95
|
-
|
|
96
155
|
resolve(target) {
|
|
97
156
|
if (!target || typeof target !== 'string') throw new UnknownTargetError(target);
|
|
98
157
|
if (target === 'dsh-global') return withExists(this.all().find((e) => e.target === 'dsh-global'));
|