skillspp 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/background-executor.js +311 -1507
- package/dist/background-executor.js.map +4 -4
- package/dist/cli.js +48 -144
- package/dist/cli.js.map +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ../../packages/core/src/runtime/background-tasks.ts
|
|
2
|
-
import
|
|
2
|
+
import fs13 from "node:fs";
|
|
3
3
|
import os7 from "node:os";
|
|
4
|
-
import
|
|
4
|
+
import path14 from "node:path";
|
|
5
5
|
|
|
6
6
|
// ../../packages/core/src/runtime/agents.ts
|
|
7
7
|
import fs from "node:fs";
|
|
@@ -12,264 +12,198 @@ var STANDARD_AGENTS = {
|
|
|
12
12
|
displayName: "Universal",
|
|
13
13
|
projectSkillsDir: ".agents/skills",
|
|
14
14
|
globalSkillsDir: ".agents/skills",
|
|
15
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
16
|
-
globalPluginsDir: ".agents/plugins/cache",
|
|
17
15
|
installMarkers: [".agents"]
|
|
18
16
|
},
|
|
19
17
|
adal: {
|
|
20
18
|
displayName: "AdaL",
|
|
21
19
|
projectSkillsDir: ".adal/skills",
|
|
22
20
|
globalSkillsDir: ".adal/skills",
|
|
23
|
-
projectPluginsDir: ".adal/plugins/cache",
|
|
24
|
-
globalPluginsDir: ".adal/plugins/cache",
|
|
25
21
|
installMarkers: [".adal"]
|
|
26
22
|
},
|
|
27
23
|
antigravity: {
|
|
28
24
|
displayName: "Antigravity",
|
|
29
25
|
projectSkillsDir: ".agent/skills",
|
|
30
26
|
globalSkillsDir: ".gemini/antigravity/skills",
|
|
31
|
-
projectPluginsDir: ".agent/plugins/cache",
|
|
32
|
-
globalPluginsDir: ".gemini/antigravity/plugins/cache",
|
|
33
27
|
installMarkers: [".gemini/antigravity"]
|
|
34
28
|
},
|
|
35
29
|
augment: {
|
|
36
30
|
displayName: "Augment",
|
|
37
31
|
projectSkillsDir: ".augment/skills",
|
|
38
32
|
globalSkillsDir: ".augment/skills",
|
|
39
|
-
projectPluginsDir: ".augment/plugins/cache",
|
|
40
|
-
globalPluginsDir: ".augment/plugins/cache",
|
|
41
33
|
installMarkers: [".augment"]
|
|
42
34
|
},
|
|
43
35
|
"claude-code": {
|
|
44
36
|
displayName: "Claude Code",
|
|
45
37
|
projectSkillsDir: ".claude/skills",
|
|
46
38
|
globalSkillsDir: ".claude/skills",
|
|
47
|
-
projectPluginsDir: ".claude/plugins/cache",
|
|
48
|
-
globalPluginsDir: ".claude/plugins/cache",
|
|
49
39
|
installMarkers: [".claude"]
|
|
50
40
|
},
|
|
51
41
|
"cortex-code": {
|
|
52
42
|
displayName: "Cortex Code",
|
|
53
43
|
projectSkillsDir: ".cortex/skills",
|
|
54
44
|
globalSkillsDir: ".cortex/skills",
|
|
55
|
-
projectPluginsDir: ".cortex/plugins/cache",
|
|
56
|
-
globalPluginsDir: ".cortex/plugins/cache",
|
|
57
45
|
installMarkers: [".cortex"]
|
|
58
46
|
},
|
|
59
47
|
crush: {
|
|
60
48
|
displayName: "Crush",
|
|
61
49
|
projectSkillsDir: ".crush/skills",
|
|
62
50
|
globalSkillsDir: ".crush/skills",
|
|
63
|
-
projectPluginsDir: ".crush/plugins/cache",
|
|
64
|
-
globalPluginsDir: ".crush/plugins/cache",
|
|
65
51
|
installMarkers: [".crush"]
|
|
66
52
|
},
|
|
67
53
|
droid: {
|
|
68
54
|
displayName: "Droid",
|
|
69
55
|
projectSkillsDir: ".factory/skills",
|
|
70
56
|
globalSkillsDir: ".factory/skills",
|
|
71
|
-
projectPluginsDir: ".factory/plugins/cache",
|
|
72
|
-
globalPluginsDir: ".factory/plugins/cache",
|
|
73
57
|
installMarkers: [".factory"]
|
|
74
58
|
},
|
|
75
59
|
goose: {
|
|
76
60
|
displayName: "Goose",
|
|
77
61
|
projectSkillsDir: ".goose/skills",
|
|
78
62
|
globalSkillsDir: ".config/goose/skills",
|
|
79
|
-
projectPluginsDir: ".goose/plugins/cache",
|
|
80
|
-
globalPluginsDir: ".config/goose/plugins/cache",
|
|
81
63
|
installMarkers: [".config/goose"]
|
|
82
64
|
},
|
|
83
65
|
"iflow-cli": {
|
|
84
66
|
displayName: "iFlow CLI",
|
|
85
67
|
projectSkillsDir: ".iflow/skills",
|
|
86
68
|
globalSkillsDir: ".iflow/skills",
|
|
87
|
-
projectPluginsDir: ".iflow/plugins/cache",
|
|
88
|
-
globalPluginsDir: ".iflow/plugins/cache",
|
|
89
69
|
installMarkers: [".iflow"]
|
|
90
70
|
},
|
|
91
71
|
junie: {
|
|
92
72
|
displayName: "Junie",
|
|
93
73
|
projectSkillsDir: ".junie/skills",
|
|
94
74
|
globalSkillsDir: ".junie/skills",
|
|
95
|
-
projectPluginsDir: ".junie/plugins/cache",
|
|
96
|
-
globalPluginsDir: ".junie/plugins/cache",
|
|
97
75
|
installMarkers: [".junie"]
|
|
98
76
|
},
|
|
99
77
|
"kiro-cli": {
|
|
100
78
|
displayName: "Kiro CLI",
|
|
101
79
|
projectSkillsDir: ".kiro/skills",
|
|
102
80
|
globalSkillsDir: ".kiro/skills",
|
|
103
|
-
projectPluginsDir: ".kiro/plugins/cache",
|
|
104
|
-
globalPluginsDir: ".kiro/plugins/cache",
|
|
105
81
|
installMarkers: [".kiro"]
|
|
106
82
|
},
|
|
107
83
|
kode: {
|
|
108
84
|
displayName: "Kode",
|
|
109
85
|
projectSkillsDir: ".kode/skills",
|
|
110
86
|
globalSkillsDir: ".kode/skills",
|
|
111
|
-
projectPluginsDir: ".kode/plugins/cache",
|
|
112
|
-
globalPluginsDir: ".kode/plugins/cache",
|
|
113
87
|
installMarkers: [".kode"]
|
|
114
88
|
},
|
|
115
89
|
openclaw: {
|
|
116
90
|
displayName: "OpenClaw",
|
|
117
91
|
projectSkillsDir: "skills",
|
|
118
92
|
globalSkillsDir: ".openclaw/skills",
|
|
119
|
-
projectPluginsDir: "plugins/cache",
|
|
120
|
-
globalPluginsDir: ".openclaw/plugins/cache",
|
|
121
93
|
installMarkers: [".openclaw"]
|
|
122
94
|
},
|
|
123
95
|
openhands: {
|
|
124
96
|
displayName: "OpenHands",
|
|
125
97
|
projectSkillsDir: ".openhands/skills",
|
|
126
98
|
globalSkillsDir: ".openhands/skills",
|
|
127
|
-
projectPluginsDir: ".openhands/plugins/cache",
|
|
128
|
-
globalPluginsDir: ".openhands/plugins/cache",
|
|
129
99
|
installMarkers: [".openhands"]
|
|
130
100
|
},
|
|
131
101
|
"mistral-vibe": {
|
|
132
102
|
displayName: "Mistral Vibe",
|
|
133
103
|
projectSkillsDir: ".vibe/skills",
|
|
134
104
|
globalSkillsDir: ".vibe/skills",
|
|
135
|
-
projectPluginsDir: ".vibe/plugins/cache",
|
|
136
|
-
globalPluginsDir: ".vibe/plugins/cache",
|
|
137
105
|
installMarkers: [".vibe"]
|
|
138
106
|
},
|
|
139
107
|
neovate: {
|
|
140
108
|
displayName: "Neovate",
|
|
141
109
|
projectSkillsDir: ".neovate/skills",
|
|
142
110
|
globalSkillsDir: ".neovate/skills",
|
|
143
|
-
projectPluginsDir: ".neovate/plugins/cache",
|
|
144
|
-
globalPluginsDir: ".neovate/plugins/cache",
|
|
145
111
|
installMarkers: [".neovate"]
|
|
146
112
|
},
|
|
147
113
|
pochi: {
|
|
148
114
|
displayName: "Pochi",
|
|
149
115
|
projectSkillsDir: ".pochi/skills",
|
|
150
116
|
globalSkillsDir: ".pochi/skills",
|
|
151
|
-
projectPluginsDir: ".pochi/plugins/cache",
|
|
152
|
-
globalPluginsDir: ".pochi/plugins/cache",
|
|
153
117
|
installMarkers: [".pochi"]
|
|
154
118
|
},
|
|
155
119
|
qoder: {
|
|
156
120
|
displayName: "Qoder",
|
|
157
121
|
projectSkillsDir: ".qoder/skills",
|
|
158
122
|
globalSkillsDir: ".qoder/skills",
|
|
159
|
-
projectPluginsDir: ".qoder/plugins/cache",
|
|
160
|
-
globalPluginsDir: ".qoder/plugins/cache",
|
|
161
123
|
installMarkers: [".qoder"]
|
|
162
124
|
},
|
|
163
125
|
"qwen-code": {
|
|
164
126
|
displayName: "Qwen Code",
|
|
165
127
|
projectSkillsDir: ".qwen/skills",
|
|
166
128
|
globalSkillsDir: ".qwen/skills",
|
|
167
|
-
projectPluginsDir: ".qwen/plugins/cache",
|
|
168
|
-
globalPluginsDir: ".qwen/plugins/cache",
|
|
169
129
|
installMarkers: [".qwen"]
|
|
170
130
|
},
|
|
171
131
|
roo: {
|
|
172
132
|
displayName: "Roo Code",
|
|
173
133
|
projectSkillsDir: ".roo/skills",
|
|
174
134
|
globalSkillsDir: ".roo/skills",
|
|
175
|
-
projectPluginsDir: ".roo/plugins/cache",
|
|
176
|
-
globalPluginsDir: ".roo/plugins/cache",
|
|
177
135
|
installMarkers: [".roo"]
|
|
178
136
|
},
|
|
179
137
|
trae: {
|
|
180
138
|
displayName: "Trae",
|
|
181
139
|
projectSkillsDir: ".trae/skills",
|
|
182
140
|
globalSkillsDir: ".trae/skills",
|
|
183
|
-
projectPluginsDir: ".trae/plugins/cache",
|
|
184
|
-
globalPluginsDir: ".trae/plugins/cache",
|
|
185
141
|
installMarkers: [".trae"]
|
|
186
142
|
},
|
|
187
143
|
"trae-cn": {
|
|
188
144
|
displayName: "Trae CN",
|
|
189
145
|
projectSkillsDir: ".trae/skills",
|
|
190
146
|
globalSkillsDir: ".trae/skills",
|
|
191
|
-
projectPluginsDir: ".trae/plugins/cache",
|
|
192
|
-
globalPluginsDir: ".trae/plugins/cache",
|
|
193
147
|
installMarkers: [".trae"]
|
|
194
148
|
},
|
|
195
149
|
windsurf: {
|
|
196
150
|
displayName: "Windsurf",
|
|
197
151
|
projectSkillsDir: ".windsurf/skills",
|
|
198
152
|
globalSkillsDir: ".codeium/windsurf/skills",
|
|
199
|
-
projectPluginsDir: ".windsurf/plugins/cache",
|
|
200
|
-
globalPluginsDir: ".codeium/windsurf/plugins/cache",
|
|
201
153
|
installMarkers: [".windsurf", ".codeium/windsurf"]
|
|
202
154
|
},
|
|
203
155
|
zencoder: {
|
|
204
156
|
displayName: "Zencoder",
|
|
205
157
|
projectSkillsDir: ".zencoder/skills",
|
|
206
158
|
globalSkillsDir: ".zencoder/skills",
|
|
207
|
-
projectPluginsDir: ".zencoder/plugins/cache",
|
|
208
|
-
globalPluginsDir: ".zencoder/plugins/cache",
|
|
209
159
|
installMarkers: [".zencoder"]
|
|
210
160
|
},
|
|
211
161
|
continue: {
|
|
212
162
|
displayName: "Continue",
|
|
213
163
|
projectSkillsDir: ".continue/skills",
|
|
214
164
|
globalSkillsDir: ".continue/skills",
|
|
215
|
-
projectPluginsDir: ".continue/plugins/cache",
|
|
216
|
-
globalPluginsDir: ".continue/plugins/cache",
|
|
217
165
|
installMarkers: [".continue"]
|
|
218
166
|
},
|
|
219
167
|
codebuddy: {
|
|
220
168
|
displayName: "CodeBuddy",
|
|
221
169
|
projectSkillsDir: ".codebuddy/skills",
|
|
222
170
|
globalSkillsDir: ".codebuddy/skills",
|
|
223
|
-
projectPluginsDir: ".codebuddy/plugins/cache",
|
|
224
|
-
globalPluginsDir: ".codebuddy/plugins/cache",
|
|
225
171
|
installMarkers: [".codebuddy"]
|
|
226
172
|
},
|
|
227
173
|
"command-code": {
|
|
228
174
|
displayName: "Command Code",
|
|
229
175
|
projectSkillsDir: ".commandcode/skills",
|
|
230
176
|
globalSkillsDir: ".commandcode/skills",
|
|
231
|
-
projectPluginsDir: ".commandcode/plugins/cache",
|
|
232
|
-
globalPluginsDir: ".commandcode/plugins/cache",
|
|
233
177
|
installMarkers: [".commandcode"]
|
|
234
178
|
},
|
|
235
179
|
kilo: {
|
|
236
180
|
displayName: "Kilo Code",
|
|
237
181
|
projectSkillsDir: ".kilocode/skills",
|
|
238
182
|
globalSkillsDir: ".kilocode/skills",
|
|
239
|
-
projectPluginsDir: ".kilocode/plugins/cache",
|
|
240
|
-
globalPluginsDir: ".kilocode/plugins/cache",
|
|
241
183
|
installMarkers: [".kilocode"]
|
|
242
184
|
},
|
|
243
185
|
mcpjam: {
|
|
244
186
|
displayName: "MCPJam",
|
|
245
187
|
projectSkillsDir: ".mcpjam/skills",
|
|
246
188
|
globalSkillsDir: ".mcpjam/skills",
|
|
247
|
-
projectPluginsDir: ".mcpjam/plugins/cache",
|
|
248
|
-
globalPluginsDir: ".mcpjam/plugins/cache",
|
|
249
189
|
installMarkers: [".mcpjam"]
|
|
250
190
|
},
|
|
251
191
|
mux: {
|
|
252
192
|
displayName: "Mux",
|
|
253
193
|
projectSkillsDir: ".mux/skills",
|
|
254
194
|
globalSkillsDir: ".mux/skills",
|
|
255
|
-
projectPluginsDir: ".mux/plugins/cache",
|
|
256
|
-
globalPluginsDir: ".mux/plugins/cache",
|
|
257
195
|
installMarkers: [".mux"]
|
|
258
196
|
},
|
|
259
197
|
pi: {
|
|
260
198
|
displayName: "Pi",
|
|
261
199
|
projectSkillsDir: ".pi/skills",
|
|
262
200
|
globalSkillsDir: ".pi/agent/skills",
|
|
263
|
-
projectPluginsDir: ".pi/plugins/cache",
|
|
264
|
-
globalPluginsDir: ".pi/agent/plugins/cache",
|
|
265
201
|
installMarkers: [".pi"]
|
|
266
202
|
},
|
|
267
203
|
replit: {
|
|
268
204
|
displayName: "Replit",
|
|
269
205
|
projectSkillsDir: ".agents/skills",
|
|
270
206
|
globalSkillsDir: ".config/agents/skills",
|
|
271
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
272
|
-
globalPluginsDir: ".config/agents/plugins/cache",
|
|
273
207
|
installMarkers: [".config/agents"]
|
|
274
208
|
}
|
|
275
209
|
};
|
|
@@ -279,64 +213,48 @@ var AGENTS = {
|
|
|
279
213
|
displayName: "Codex",
|
|
280
214
|
projectSkillsDir: ".agents/skills",
|
|
281
215
|
globalSkillsDir: ".codex/skills",
|
|
282
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
283
|
-
globalPluginsDir: ".codex/plugins/cache",
|
|
284
216
|
installMarkers: [".codex"]
|
|
285
217
|
},
|
|
286
218
|
cursor: {
|
|
287
219
|
displayName: "Cursor",
|
|
288
220
|
projectSkillsDir: ".agents/skills",
|
|
289
221
|
globalSkillsDir: ".cursor/skills",
|
|
290
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
291
|
-
globalPluginsDir: ".cursor/plugins/cache",
|
|
292
222
|
installMarkers: [".cursor"]
|
|
293
223
|
},
|
|
294
224
|
"gemini-cli": {
|
|
295
225
|
displayName: "Gemini CLI",
|
|
296
226
|
projectSkillsDir: ".agents/skills",
|
|
297
227
|
globalSkillsDir: ".gemini/skills",
|
|
298
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
299
|
-
globalPluginsDir: ".gemini/plugins/cache",
|
|
300
228
|
installMarkers: [".gemini"]
|
|
301
229
|
},
|
|
302
230
|
"github-copilot": {
|
|
303
231
|
displayName: "GitHub Copilot",
|
|
304
232
|
projectSkillsDir: ".agents/skills",
|
|
305
233
|
globalSkillsDir: ".copilot/skills",
|
|
306
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
307
|
-
globalPluginsDir: ".copilot/plugins/cache",
|
|
308
234
|
installMarkers: [".copilot"]
|
|
309
235
|
},
|
|
310
236
|
amp: {
|
|
311
237
|
displayName: "Amp",
|
|
312
238
|
projectSkillsDir: ".agents/skills",
|
|
313
239
|
globalSkillsDir: ".config/agents/skills",
|
|
314
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
315
|
-
globalPluginsDir: ".config/agents/plugins/cache",
|
|
316
240
|
installMarkers: [".config/agents"]
|
|
317
241
|
},
|
|
318
242
|
opencode: {
|
|
319
243
|
displayName: "OpenCode",
|
|
320
244
|
projectSkillsDir: ".agents/skills",
|
|
321
245
|
globalSkillsDir: ".config/opencode/skills",
|
|
322
|
-
projectPluginsDir: ".agents/plugins/cache",
|
|
323
|
-
globalPluginsDir: ".config/opencode/plugins/cache",
|
|
324
246
|
installMarkers: [".config/opencode"]
|
|
325
247
|
},
|
|
326
248
|
windsurf: {
|
|
327
249
|
displayName: "Windsurf",
|
|
328
250
|
projectSkillsDir: ".windsurf/skills",
|
|
329
251
|
globalSkillsDir: ".codeium/windsurf/skills",
|
|
330
|
-
projectPluginsDir: ".windsurf/plugins/cache",
|
|
331
|
-
globalPluginsDir: ".codeium/windsurf/plugins/cache",
|
|
332
252
|
installMarkers: [".windsurf", ".codeium/windsurf"]
|
|
333
253
|
},
|
|
334
254
|
cline: {
|
|
335
255
|
displayName: "Cline",
|
|
336
256
|
projectSkillsDir: ".cline/skills",
|
|
337
257
|
globalSkillsDir: ".cline/skills",
|
|
338
|
-
projectPluginsDir: ".cline/plugins/cache",
|
|
339
|
-
globalPluginsDir: ".cline/plugins/cache",
|
|
340
258
|
installMarkers: [".cline"]
|
|
341
259
|
}
|
|
342
260
|
};
|
|
@@ -369,11 +287,6 @@ function getAgentSkillsDir(agent, globalInstall, cwd) {
|
|
|
369
287
|
const base = globalInstall ? os.homedir() : cwd;
|
|
370
288
|
return path.join(base, relative);
|
|
371
289
|
}
|
|
372
|
-
function getAgentPluginsDir(agent, globalInstall, cwd) {
|
|
373
|
-
const relative = globalInstall ? AGENTS[agent].globalPluginsDir : AGENTS[agent].projectPluginsDir;
|
|
374
|
-
const base = globalInstall ? os.homedir() : cwd;
|
|
375
|
-
return path.join(base, relative);
|
|
376
|
-
}
|
|
377
290
|
function detectInstalledAgents(cwd = process.cwd()) {
|
|
378
291
|
const found = [];
|
|
379
292
|
for (const agent of Object.keys(AGENTS)) {
|
|
@@ -909,27 +822,6 @@ var SKILL_CONFIG = {
|
|
|
909
822
|
};
|
|
910
823
|
}
|
|
911
824
|
};
|
|
912
|
-
var PLUGIN_CONFIG = {
|
|
913
|
-
kind: "plugins",
|
|
914
|
-
displayLabel: "well-known plugins",
|
|
915
|
-
indexPath: "/.well-known/plugins/index.json",
|
|
916
|
-
entryLabel: "plugin",
|
|
917
|
-
requireDescription: false,
|
|
918
|
-
missingManifestMessage: (name) => `Well-known plugin '${name}' is missing plugin.json`,
|
|
919
|
-
hasRequiredManifest(filePath) {
|
|
920
|
-
return filePath.split("/").at(-1)?.toLowerCase() === "plugin.json";
|
|
921
|
-
},
|
|
922
|
-
buildRemoteResult({ entry, files, sourceUrl }) {
|
|
923
|
-
return {
|
|
924
|
-
name: entry.name,
|
|
925
|
-
description: entry.description || "",
|
|
926
|
-
installName: entry.name,
|
|
927
|
-
sourceUrl,
|
|
928
|
-
sourceType: "well-known",
|
|
929
|
-
files
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
};
|
|
933
825
|
var SecureWellKnownProvider = class {
|
|
934
826
|
id = "well-known";
|
|
935
827
|
displayName = "Secure Well-Known Skills";
|
|
@@ -955,9 +847,6 @@ var SecureWellKnownProvider = class {
|
|
|
955
847
|
async fetchAllSkills(url, options = {}) {
|
|
956
848
|
return this.fetchAllResources(url, options, SKILL_CONFIG);
|
|
957
849
|
}
|
|
958
|
-
async fetchAllPlugins(url, options = {}) {
|
|
959
|
-
return this.fetchAllResources(url, options, PLUGIN_CONFIG);
|
|
960
|
-
}
|
|
961
850
|
async fetchAllResources(url, options, config) {
|
|
962
851
|
const normalized = this.normalizeOptions(options);
|
|
963
852
|
const budget = { remaining: normalized.maxDownloadBytes };
|
|
@@ -1249,33 +1138,6 @@ var HttpCatalogProvider = class {
|
|
|
1249
1138
|
}
|
|
1250
1139
|
});
|
|
1251
1140
|
}
|
|
1252
|
-
async fetchAllPlugins(url, options = {}) {
|
|
1253
|
-
return this.fetchAllResources(url, options, {
|
|
1254
|
-
kind: "plugins",
|
|
1255
|
-
indexLabel: "catalog plugins",
|
|
1256
|
-
resolveIndexUrl(parsed) {
|
|
1257
|
-
return parsed.pathname.endsWith(".json") ? parsed.toString() : new URL(
|
|
1258
|
-
"plugins/index.json",
|
|
1259
|
-
parsed.toString().endsWith("/") ? parsed.toString() : `${parsed.toString()}/`
|
|
1260
|
-
).toString();
|
|
1261
|
-
},
|
|
1262
|
-
requireDescription: false,
|
|
1263
|
-
missingManifestMessage: (name) => `Catalog plugin '${name}' is missing plugin.json`,
|
|
1264
|
-
hasRequiredManifest(filePath) {
|
|
1265
|
-
return filePath.split("/").at(-1)?.toLowerCase() === "plugin.json";
|
|
1266
|
-
},
|
|
1267
|
-
buildRemoteResult({ entry, files, sourceUrl }) {
|
|
1268
|
-
return {
|
|
1269
|
-
name: entry.name,
|
|
1270
|
-
description: entry.description || "",
|
|
1271
|
-
installName: entry.name,
|
|
1272
|
-
sourceUrl,
|
|
1273
|
-
sourceType: "catalog",
|
|
1274
|
-
files
|
|
1275
|
-
};
|
|
1276
|
-
}
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
1141
|
async fetchAllResources(url, options, config) {
|
|
1280
1142
|
const parsed = new URL(url);
|
|
1281
1143
|
if (parsed.protocol !== "https:") {
|
|
@@ -1450,33 +1312,6 @@ async function resolveCatalogSkills(sourceUrl, options) {
|
|
|
1450
1312
|
maxDownloadBytes: options.maxDownloadBytes
|
|
1451
1313
|
});
|
|
1452
1314
|
}
|
|
1453
|
-
async function resolveWellKnownPlugins(sourceUrl, options) {
|
|
1454
|
-
initializeProviders();
|
|
1455
|
-
const provider = getProviderById("well-known");
|
|
1456
|
-
if (!provider) {
|
|
1457
|
-
throw new Error("Well-known provider is not registered");
|
|
1458
|
-
}
|
|
1459
|
-
const wellKnown = provider;
|
|
1460
|
-
return wellKnown.fetchAllPlugins(sourceUrl, {
|
|
1461
|
-
allowHosts: options.allowHost,
|
|
1462
|
-
denyHosts: options.denyHost,
|
|
1463
|
-
maxDownloadBytes: options.maxDownloadBytes
|
|
1464
|
-
});
|
|
1465
|
-
}
|
|
1466
|
-
async function resolveCatalogPlugins(sourceUrl, options) {
|
|
1467
|
-
assertExperimentalFeatureEnabled("catalog", Boolean(options.experimental));
|
|
1468
|
-
initializeProviders();
|
|
1469
|
-
const provider = getProviderById("catalog");
|
|
1470
|
-
if (!provider) {
|
|
1471
|
-
throw new Error("Catalog provider is not registered");
|
|
1472
|
-
}
|
|
1473
|
-
const catalog = provider;
|
|
1474
|
-
return catalog.fetchAllPlugins(sourceUrl, {
|
|
1475
|
-
allowHosts: options.allowHost,
|
|
1476
|
-
denyHosts: options.denyHost,
|
|
1477
|
-
maxDownloadBytes: options.maxDownloadBytes
|
|
1478
|
-
});
|
|
1479
|
-
}
|
|
1480
1315
|
|
|
1481
1316
|
// ../../packages/core/src/runtime/hash.ts
|
|
1482
1317
|
import fs4 from "node:fs";
|
|
@@ -1637,10 +1472,10 @@ function writePerSkillLockfile(canonicalDir, entry, format) {
|
|
|
1637
1472
|
function isSkillDirEntry(entry) {
|
|
1638
1473
|
return entry.isDirectory() || entry.isSymbolicLink();
|
|
1639
1474
|
}
|
|
1640
|
-
function listInstalledResourceDirs(
|
|
1475
|
+
function listInstalledResourceDirs(_kind, globalInstall, cwd) {
|
|
1641
1476
|
const out = /* @__PURE__ */ new Set();
|
|
1642
1477
|
for (const agent of Object.keys(AGENTS)) {
|
|
1643
|
-
const resourceRoot =
|
|
1478
|
+
const resourceRoot = getAgentSkillsDir(agent, globalInstall, cwd);
|
|
1644
1479
|
if (!fs5.existsSync(resourceRoot) || !fs5.statSync(resourceRoot).isDirectory()) {
|
|
1645
1480
|
continue;
|
|
1646
1481
|
}
|
|
@@ -2028,693 +1863,203 @@ async function assessLockEntries(options, cwd, behavior = { keepResolved: false
|
|
|
2028
1863
|
}
|
|
2029
1864
|
}
|
|
2030
1865
|
|
|
2031
|
-
// ../../packages/core/src/runtime/
|
|
1866
|
+
// ../../packages/core/src/runtime/validate-analysis.ts
|
|
1867
|
+
import fs9 from "node:fs";
|
|
1868
|
+
import path10 from "node:path";
|
|
1869
|
+
import os5 from "node:os";
|
|
1870
|
+
import matter2 from "gray-matter";
|
|
1871
|
+
|
|
1872
|
+
// ../../packages/core/src/runtime/skill-installer.ts
|
|
1873
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2032
1874
|
import fs8 from "node:fs";
|
|
1875
|
+
import os4 from "node:os";
|
|
2033
1876
|
import path9 from "node:path";
|
|
1877
|
+
import YAML2 from "yaml";
|
|
1878
|
+
import { z } from "zod";
|
|
2034
1879
|
|
|
2035
|
-
// ../../packages/core/src/
|
|
1880
|
+
// ../../packages/core/src/runtime/installer-security.ts
|
|
2036
1881
|
import fs7 from "node:fs";
|
|
2037
1882
|
import path8 from "node:path";
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
1883
|
+
function isInsideRoot(rootDir, candidatePath) {
|
|
1884
|
+
const relative = path8.relative(rootDir, candidatePath);
|
|
1885
|
+
return Boolean(relative) && !relative.startsWith("..") && !path8.isAbsolute(relative);
|
|
1886
|
+
}
|
|
1887
|
+
function toEscapeViolation(source) {
|
|
1888
|
+
return {
|
|
1889
|
+
rule: "installer-local-dependency-path-escape",
|
|
1890
|
+
message: `local dependency escapes source root: ${source}`,
|
|
1891
|
+
severity: "error",
|
|
1892
|
+
blocking: true
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
function evaluateInstallerLocalDependency(input, _options = {}) {
|
|
1896
|
+
if (path8.isAbsolute(input.source)) {
|
|
1897
|
+
return {
|
|
1898
|
+
ok: false,
|
|
1899
|
+
violation: {
|
|
1900
|
+
rule: "installer-local-dependency-absolute-path",
|
|
1901
|
+
message: `absolute local dependency paths are not allowed: ${input.source}`,
|
|
1902
|
+
severity: "error",
|
|
1903
|
+
blocking: true
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
2048
1906
|
}
|
|
2049
|
-
const
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
1907
|
+
const resolvedRoot = path8.resolve(input.sourceRoot);
|
|
1908
|
+
const resolvedSourcePath = path8.resolve(resolvedRoot, input.source);
|
|
1909
|
+
if (!isInsideRoot(resolvedRoot, resolvedSourcePath)) {
|
|
1910
|
+
return {
|
|
1911
|
+
ok: false,
|
|
1912
|
+
violation: toEscapeViolation(input.source)
|
|
1913
|
+
};
|
|
2056
1914
|
}
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
const fullPath = path8.join(dir, entry.name);
|
|
2066
|
-
if (entry.isDirectory()) {
|
|
2067
|
-
await collectPluginJsonFilesRecursiveAsync(fullPath, pluginRoot, out);
|
|
2068
|
-
continue;
|
|
2069
|
-
}
|
|
2070
|
-
if (entry.isFile() && path8.basename(fullPath).toLowerCase() === "plugin.json") {
|
|
2071
|
-
out.push(path8.relative(pluginRoot, fullPath));
|
|
1915
|
+
if (fs7.existsSync(resolvedSourcePath)) {
|
|
1916
|
+
const realRoot = fs7.realpathSync.native ? fs7.realpathSync.native(resolvedRoot) : fs7.realpathSync(resolvedRoot);
|
|
1917
|
+
const realSource = fs7.realpathSync.native ? fs7.realpathSync.native(resolvedSourcePath) : fs7.realpathSync(resolvedSourcePath);
|
|
1918
|
+
if (!isInsideRoot(realRoot, realSource)) {
|
|
1919
|
+
return {
|
|
1920
|
+
ok: false,
|
|
1921
|
+
violation: toEscapeViolation(input.source)
|
|
1922
|
+
};
|
|
2072
1923
|
}
|
|
2073
1924
|
}
|
|
1925
|
+
return {
|
|
1926
|
+
ok: true,
|
|
1927
|
+
resolvedPath: resolvedSourcePath
|
|
1928
|
+
};
|
|
2074
1929
|
}
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
throw new Error(`Plugin '${pluginName}' has invalid plugin.json`);
|
|
2081
|
-
}
|
|
2082
|
-
if (!parsed || typeof parsed !== "object") {
|
|
2083
|
-
throw new Error(`Plugin '${pluginName}' has invalid plugin.json`);
|
|
2084
|
-
}
|
|
2085
|
-
const data = parsed;
|
|
2086
|
-
if (typeof data.name !== "string" || data.name.trim().length === 0) {
|
|
2087
|
-
throw new Error(`Plugin '${pluginName}' plugin.json is missing name`);
|
|
1930
|
+
|
|
1931
|
+
// ../../packages/core/src/runtime/policy.ts
|
|
1932
|
+
function applyMode(result, mode) {
|
|
1933
|
+
if (mode === "enforce" || result.ok) {
|
|
1934
|
+
return result;
|
|
2088
1935
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
1936
|
+
const violation = "violation" in result ? result.violation : void 0;
|
|
1937
|
+
if (!violation) {
|
|
1938
|
+
return result;
|
|
2091
1939
|
}
|
|
2092
1940
|
return {
|
|
2093
|
-
|
|
2094
|
-
|
|
1941
|
+
ok: false,
|
|
1942
|
+
violation: {
|
|
1943
|
+
...violation,
|
|
1944
|
+
severity: "warning",
|
|
1945
|
+
blocking: false
|
|
1946
|
+
}
|
|
2095
1947
|
};
|
|
2096
1948
|
}
|
|
2097
|
-
function
|
|
2098
|
-
|
|
2099
|
-
const depthB = b.split(path8.sep).length;
|
|
2100
|
-
if (depthA !== depthB) {
|
|
2101
|
-
return depthA - depthB;
|
|
2102
|
-
}
|
|
2103
|
-
return a.localeCompare(b);
|
|
1949
|
+
function evaluateInstallerLocalDependencyPolicy(input, mode) {
|
|
1950
|
+
return applyMode(evaluateInstallerLocalDependency(input, { policyMode: "fixed" }), mode);
|
|
2104
1951
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
await collectPluginJsonFilesRecursiveAsync(pluginDir, pluginDir, pluginJsonRelativePaths);
|
|
2109
|
-
pluginJsonRelativePaths.sort(sortManifestCandidates);
|
|
2110
|
-
if (pluginJsonRelativePaths.length === 0) {
|
|
2111
|
-
return {
|
|
2112
|
-
pluginName,
|
|
2113
|
-
pluginDir,
|
|
2114
|
-
error: new Error(`Plugin '${pluginName}' is missing plugin.json`)
|
|
2115
|
-
};
|
|
1952
|
+
function evaluateHookTrustPolicy(input) {
|
|
1953
|
+
if (input.sourceType !== "well-known") {
|
|
1954
|
+
return { allowed: true };
|
|
2116
1955
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
path8.join(pluginDir, relativePath),
|
|
2122
|
-
pluginName
|
|
2123
|
-
);
|
|
2124
|
-
manifests.push({
|
|
2125
|
-
description: manifest.description || "",
|
|
2126
|
-
relativePath
|
|
2127
|
-
});
|
|
2128
|
-
}
|
|
2129
|
-
} catch (error) {
|
|
1956
|
+
if (input.trustWellKnown) {
|
|
1957
|
+
return { allowed: true };
|
|
1958
|
+
}
|
|
1959
|
+
if (input.mode === "warn") {
|
|
2130
1960
|
return {
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
1961
|
+
allowed: true,
|
|
1962
|
+
violation: {
|
|
1963
|
+
rule: "hook-trust-required",
|
|
1964
|
+
message: "Well-known hook commands are untrusted. Proceeding due to warning policy mode.",
|
|
1965
|
+
severity: "warning",
|
|
1966
|
+
blocking: false
|
|
1967
|
+
}
|
|
2134
1968
|
};
|
|
2135
1969
|
}
|
|
2136
|
-
const selectedManifest = manifests[0];
|
|
2137
1970
|
return {
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
1971
|
+
allowed: false,
|
|
1972
|
+
violation: {
|
|
1973
|
+
rule: "hook-trust-required",
|
|
1974
|
+
message: "Blocked skill-installer hook commands for well-known source. Trust this source explicitly or use warning policy mode.",
|
|
1975
|
+
severity: "error",
|
|
1976
|
+
blocking: true
|
|
2144
1977
|
}
|
|
2145
1978
|
};
|
|
2146
1979
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
inspections.map((inspection) => [inspection.pluginName, inspection])
|
|
2156
|
-
);
|
|
2157
|
-
for (const requestedPlugin of requestedPlugins) {
|
|
2158
|
-
const inspection = inspectionByName.get(requestedPlugin);
|
|
2159
|
-
if (inspection?.error) {
|
|
2160
|
-
throw inspection.error;
|
|
2161
|
-
}
|
|
1980
|
+
|
|
1981
|
+
// ../../packages/core/src/runtime/skill-installer.ts
|
|
1982
|
+
var InstallerSecurityError = class extends Error {
|
|
1983
|
+
violation;
|
|
1984
|
+
constructor(violation) {
|
|
1985
|
+
super(violation.message);
|
|
1986
|
+
this.name = "InstallerSecurityError";
|
|
1987
|
+
this.violation = violation;
|
|
2162
1988
|
}
|
|
1989
|
+
};
|
|
1990
|
+
function isInstallerSecurityError(error) {
|
|
1991
|
+
return error instanceof InstallerSecurityError;
|
|
2163
1992
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
entries.filter((entry) => entry.isDirectory()).map((entry) => inspectPluginFolderAsync(path8.join(pluginsRoot, entry.name)))
|
|
2171
|
-
);
|
|
2172
|
-
filterRequestedPluginErrors(requestedPlugins, inspections);
|
|
2173
|
-
return filterPluginsByName(
|
|
2174
|
-
inspections.map((inspection) => inspection.plugin).filter((plugin) => Boolean(plugin)),
|
|
2175
|
-
requestedPlugins
|
|
2176
|
-
);
|
|
2177
|
-
}
|
|
2178
|
-
function filterPluginsByName(plugins, requested) {
|
|
2179
|
-
if (!requested || requested.length === 0) {
|
|
2180
|
-
return plugins;
|
|
2181
|
-
}
|
|
2182
|
-
if (requested.includes("*")) {
|
|
2183
|
-
return plugins;
|
|
1993
|
+
var InstallerPolicyError = class extends Error {
|
|
1994
|
+
violation;
|
|
1995
|
+
constructor(violation) {
|
|
1996
|
+
super(violation.message);
|
|
1997
|
+
this.name = "InstallerPolicyError";
|
|
1998
|
+
this.violation = violation;
|
|
2184
1999
|
}
|
|
2185
|
-
|
|
2186
|
-
|
|
2000
|
+
};
|
|
2001
|
+
function isInstallerPolicyError(error) {
|
|
2002
|
+
return error instanceof InstallerPolicyError;
|
|
2187
2003
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2004
|
+
var dependencyObjectSchema = z.object({
|
|
2005
|
+
source: z.string().min(1),
|
|
2006
|
+
path: z.string().min(1)
|
|
2007
|
+
}).strict();
|
|
2008
|
+
var installerConfigSchema = z.object({
|
|
2009
|
+
schemaVersion: z.literal(1),
|
|
2010
|
+
"pre-install": z.array(z.string().min(1)).optional().default([]),
|
|
2011
|
+
dependencies: z.array(z.union([z.string().min(1), dependencyObjectSchema])).optional().default([]),
|
|
2012
|
+
"post-install": z.array(z.string().min(1)).optional().default([])
|
|
2013
|
+
}).strict();
|
|
2014
|
+
function ensureInsideRoot(rootDir, relativeTarget) {
|
|
2015
|
+
const resolved = path9.resolve(rootDir, relativeTarget);
|
|
2016
|
+
const relative = path9.relative(rootDir, resolved);
|
|
2017
|
+
if (!relative || relative.startsWith("..") || path9.isAbsolute(relative)) {
|
|
2018
|
+
throw new Error(`Unsafe destination path: ${relativeTarget}`);
|
|
2192
2019
|
}
|
|
2193
|
-
return
|
|
2194
|
-
prefix: "skillspp-remote-plugin-"
|
|
2195
|
-
});
|
|
2020
|
+
return resolved;
|
|
2196
2021
|
}
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2022
|
+
function sourceLooksLikeUrl(source) {
|
|
2023
|
+
try {
|
|
2024
|
+
const parsed = new URL(source);
|
|
2025
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
2026
|
+
} catch {
|
|
2027
|
+
return false;
|
|
2202
2028
|
}
|
|
2203
|
-
return selected.includes(entry.skillName);
|
|
2204
2029
|
}
|
|
2205
|
-
function
|
|
2206
|
-
|
|
2030
|
+
function sourceLooksLikeRepoShorthand(source) {
|
|
2031
|
+
const trimmed = source.trim().replace(/^https?:\/\//, "");
|
|
2032
|
+
return /^(github\.com|gitlab\.com)\/[^/]+\/[^/]+(?:\.git)?\/?$/.test(trimmed);
|
|
2207
2033
|
}
|
|
2208
|
-
function
|
|
2209
|
-
|
|
2210
|
-
|
|
2034
|
+
function parseRepoSource(source) {
|
|
2035
|
+
const withoutProtocol = source.trim().replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
2036
|
+
const match = withoutProtocol.match(/^(github\.com|gitlab\.com)\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
2037
|
+
if (!match) {
|
|
2038
|
+
throw new Error(`Unsupported repository dependency source: ${source}`);
|
|
2211
2039
|
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2040
|
+
const host = match[1];
|
|
2041
|
+
const owner = match[2];
|
|
2042
|
+
const repo = match[3];
|
|
2043
|
+
return {
|
|
2044
|
+
repoUrl: `https://${host}/${owner}/${repo}.git`,
|
|
2045
|
+
repoName: repo
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
function deriveDestinationNameFromSource(source) {
|
|
2049
|
+
if (sourceLooksLikeUrl(source)) {
|
|
2050
|
+
const parsed = new URL(source);
|
|
2051
|
+
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
2052
|
+
const leaf2 = parts[parts.length - 1];
|
|
2053
|
+
if (!leaf2) {
|
|
2054
|
+
throw new Error(`Cannot derive dependency name from URL source: ${source}`);
|
|
2218
2055
|
}
|
|
2219
|
-
return
|
|
2220
|
-
}
|
|
2221
|
-
if (!entry.source.pinnedRef) {
|
|
2222
|
-
return `remote pin metadata missing; run ${migrateHint2(entry.skillName)}`;
|
|
2223
|
-
}
|
|
2224
|
-
return null;
|
|
2225
|
-
}
|
|
2226
|
-
function createRetainedCleanup2(cleanup) {
|
|
2227
|
-
let cleaned = false;
|
|
2228
|
-
let refCount = 0;
|
|
2229
|
-
const runCleanup = () => {
|
|
2230
|
-
if (cleaned) {
|
|
2231
|
-
return;
|
|
2232
|
-
}
|
|
2233
|
-
cleaned = true;
|
|
2234
|
-
cleanup?.();
|
|
2235
|
-
};
|
|
2236
|
-
const cleanupNow = () => {
|
|
2237
|
-
if (refCount === 0) {
|
|
2238
|
-
runCleanup();
|
|
2239
|
-
}
|
|
2240
|
-
};
|
|
2241
|
-
const retainCleanup = () => {
|
|
2242
|
-
refCount += 1;
|
|
2243
|
-
let released = false;
|
|
2244
|
-
return () => {
|
|
2245
|
-
if (released) {
|
|
2246
|
-
return;
|
|
2247
|
-
}
|
|
2248
|
-
released = true;
|
|
2249
|
-
refCount -= 1;
|
|
2250
|
-
if (refCount === 0) {
|
|
2251
|
-
runCleanup();
|
|
2252
|
-
}
|
|
2253
|
-
};
|
|
2254
|
-
};
|
|
2255
|
-
return {
|
|
2256
|
-
cleanupNow,
|
|
2257
|
-
retainCleanup
|
|
2258
|
-
};
|
|
2259
|
-
}
|
|
2260
|
-
function toAsyncResult2(promise) {
|
|
2261
|
-
return promise.then(
|
|
2262
|
-
(value) => ({ ok: true, value }),
|
|
2263
|
-
(error) => ({ ok: false, error })
|
|
2264
|
-
);
|
|
2265
|
-
}
|
|
2266
|
-
function unwrapAsyncResult2(result) {
|
|
2267
|
-
if (result.ok) {
|
|
2268
|
-
return result.value;
|
|
2269
|
-
}
|
|
2270
|
-
throw result.error;
|
|
2271
|
-
}
|
|
2272
|
-
async function loadCachedSource2(entry, options) {
|
|
2273
|
-
const sourceInput = resolveSourceLoadInput(entry.source);
|
|
2274
|
-
const parsed = parseSource(sourceInput);
|
|
2275
|
-
if (parsed.type === "well-known" || parsed.type === "catalog") {
|
|
2276
|
-
const remotePlugins = parsed.type === "well-known" ? await resolveWellKnownPlugins(parsed.url, options) : await resolveCatalogPlugins(parsed.url, options);
|
|
2277
|
-
return {
|
|
2278
|
-
kind: "remote",
|
|
2279
|
-
remotePlugins
|
|
2280
|
-
};
|
|
2281
|
-
}
|
|
2282
|
-
const prepared = await prepareSourceDirAsync(
|
|
2283
|
-
parsed
|
|
2284
|
-
);
|
|
2285
|
-
const retainedCleanup = createRetainedCleanup2(prepared.cleanup);
|
|
2286
|
-
try {
|
|
2287
|
-
const plugins = await discoverPluginsAsync(prepared.basePath);
|
|
2288
|
-
return {
|
|
2289
|
-
kind: "prepared",
|
|
2290
|
-
basePath: prepared.basePath,
|
|
2291
|
-
plugins,
|
|
2292
|
-
cleanupNow: retainedCleanup.cleanupNow,
|
|
2293
|
-
retainCleanup: retainedCleanup.retainCleanup
|
|
2294
|
-
};
|
|
2295
|
-
} catch (error) {
|
|
2296
|
-
retainedCleanup.cleanupNow();
|
|
2297
|
-
throw error;
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
function resolveSafeRealPath2(inputPath) {
|
|
2301
|
-
try {
|
|
2302
|
-
return fs8.realpathSync(inputPath);
|
|
2303
|
-
} catch {
|
|
2304
|
-
return path9.resolve(inputPath);
|
|
2305
|
-
}
|
|
2306
|
-
}
|
|
2307
|
-
function isLocalSymlinkSource2(localPath) {
|
|
2308
|
-
try {
|
|
2309
|
-
if (!fs8.existsSync(localPath)) {
|
|
2310
|
-
return false;
|
|
2311
|
-
}
|
|
2312
|
-
return fs8.lstatSync(localPath).isSymbolicLink();
|
|
2313
|
-
} catch {
|
|
2314
|
-
return false;
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
|
-
async function buildRefreshedSourceMetadata2(entry, resolved, cachedSource, sourceHash) {
|
|
2318
|
-
if (entry.source.type === "local") {
|
|
2319
|
-
const canonical2 = entry.source.canonical || entry.source.input;
|
|
2320
|
-
return {
|
|
2321
|
-
canonical: canonical2,
|
|
2322
|
-
resolvedPath: resolveSafeRealPath2(resolved.plugin.path),
|
|
2323
|
-
isSymlinkSource: isLocalSymlinkSource2(canonical2),
|
|
2324
|
-
sourcePluginPath: resolved.sourcePluginPath
|
|
2325
|
-
};
|
|
2326
|
-
}
|
|
2327
|
-
if (entry.source.type === "git" || entry.source.type === "github") {
|
|
2328
|
-
const nextPinnedRef = cachedSource.kind === "prepared" ? await resolveGitHeadRefAsync(cachedSource.basePath) : entry.source.pinnedRef;
|
|
2329
|
-
return {
|
|
2330
|
-
canonical: entry.source.canonical,
|
|
2331
|
-
pinnedRef: nextPinnedRef,
|
|
2332
|
-
sourcePluginPath: resolved.sourcePluginPath
|
|
2333
|
-
};
|
|
2334
|
-
}
|
|
2335
|
-
const canonical = resolved.wellKnownSourceUrl || entry.source.canonical;
|
|
2336
|
-
return {
|
|
2337
|
-
canonical,
|
|
2338
|
-
pinnedRef: sourceHash,
|
|
2339
|
-
wellKnownSourceUrl: resolved.wellKnownSourceUrl
|
|
2340
|
-
};
|
|
2341
|
-
}
|
|
2342
|
-
function resolveCandidateFromCachedSource2(entry, cachedSource, keepResolved) {
|
|
2343
|
-
if (cachedSource.kind === "remote") {
|
|
2344
|
-
const matched2 = cachedSource.remotePlugins.find(
|
|
2345
|
-
(item) => item.installName === entry.source.selector.skillName
|
|
2346
|
-
);
|
|
2347
|
-
if (!matched2) {
|
|
2348
|
-
throw new Error(`Plugin '${entry.source.selector.skillName}' not found in well-known source`);
|
|
2349
|
-
}
|
|
2350
|
-
const staged = stageRemotePluginFilesToTempDir(matched2.installName, matched2.files);
|
|
2351
|
-
return {
|
|
2352
|
-
plugin: {
|
|
2353
|
-
name: matched2.installName,
|
|
2354
|
-
description: matched2.description,
|
|
2355
|
-
path: path9.join(staged.path, "plugins", matched2.installName)
|
|
2356
|
-
},
|
|
2357
|
-
wellKnownSourceUrl: matched2.sourceUrl,
|
|
2358
|
-
cleanup: staged.cleanup
|
|
2359
|
-
};
|
|
2360
|
-
}
|
|
2361
|
-
const matched = entry.source.selector.relativePath ? cachedSource.plugins.find(
|
|
2362
|
-
(item) => path9.resolve(item.path) === path9.resolve(path9.join(cachedSource.basePath, entry.source.selector.relativePath))
|
|
2363
|
-
) : cachedSource.plugins.find((item) => item.name === entry.source.selector.skillName);
|
|
2364
|
-
if (!matched) {
|
|
2365
|
-
throw new Error(`Plugin '${entry.source.selector.skillName}' not found in source`);
|
|
2366
|
-
}
|
|
2367
|
-
return {
|
|
2368
|
-
plugin: matched,
|
|
2369
|
-
sourcePluginPath: path9.relative(cachedSource.basePath, matched.path) || ".",
|
|
2370
|
-
cleanup: keepResolved ? cachedSource.retainCleanup() : void 0
|
|
2371
|
-
};
|
|
2372
|
-
}
|
|
2373
|
-
async function assessPluginLockEntries(options, cwd, behavior = { keepResolved: false }) {
|
|
2374
|
-
const lock = readResourceLockfile("plugin", Boolean(options.global), cwd);
|
|
2375
|
-
const entries = lock.entries.filter((entry) => includeByPlugin(entry, options.plugin));
|
|
2376
|
-
const drift = [];
|
|
2377
|
-
const assessments = [];
|
|
2378
|
-
const sourceOptions = {
|
|
2379
|
-
global: options.global,
|
|
2380
|
-
allowHost: options.allowHost,
|
|
2381
|
-
denyHost: options.denyHost,
|
|
2382
|
-
maxDownloadBytes: options.maxDownloadBytes,
|
|
2383
|
-
policyMode: options.policyMode,
|
|
2384
|
-
experimental: options.experimental
|
|
2385
|
-
};
|
|
2386
|
-
const sourceCache = /* @__PURE__ */ new Map();
|
|
2387
|
-
const getCachedSource = (entry) => {
|
|
2388
|
-
const key = buildSourceLoadCacheKey(entry.source);
|
|
2389
|
-
const existing = sourceCache.get(key);
|
|
2390
|
-
if (existing) {
|
|
2391
|
-
return existing;
|
|
2392
|
-
}
|
|
2393
|
-
const created = loadCachedSource2(entry, sourceOptions);
|
|
2394
|
-
sourceCache.set(key, created);
|
|
2395
|
-
return created;
|
|
2396
|
-
};
|
|
2397
|
-
try {
|
|
2398
|
-
for (const entry of entries) {
|
|
2399
|
-
const assessment = {
|
|
2400
|
-
entry,
|
|
2401
|
-
drift: []
|
|
2402
|
-
};
|
|
2403
|
-
if (!fs8.existsSync(entry.canonicalDir) || !fs8.statSync(entry.canonicalDir).isDirectory()) {
|
|
2404
|
-
const row = {
|
|
2405
|
-
skillName: entry.skillName,
|
|
2406
|
-
kind: "local-modified",
|
|
2407
|
-
detail: "canonical directory is missing"
|
|
2408
|
-
};
|
|
2409
|
-
drift.push(row);
|
|
2410
|
-
assessment.drift.push(row);
|
|
2411
|
-
assessments.push(assessment);
|
|
2412
|
-
continue;
|
|
2413
|
-
}
|
|
2414
|
-
const installedHash = unwrapAsyncResult2(
|
|
2415
|
-
await toAsyncResult2(hashDirectoryAsync(entry.canonicalDir))
|
|
2416
|
-
);
|
|
2417
|
-
if (installedHash !== entry.installedHash) {
|
|
2418
|
-
const row = {
|
|
2419
|
-
skillName: entry.skillName,
|
|
2420
|
-
kind: "local-modified",
|
|
2421
|
-
detail: "installed content differs from lockfile hash"
|
|
2422
|
-
};
|
|
2423
|
-
drift.push(row);
|
|
2424
|
-
assessment.drift.push(row);
|
|
2425
|
-
}
|
|
2426
|
-
const metadataIssue = resolveSourceMetadataIssue2(entry);
|
|
2427
|
-
if (metadataIssue) {
|
|
2428
|
-
const row = {
|
|
2429
|
-
skillName: entry.skillName,
|
|
2430
|
-
kind: "migrate-required",
|
|
2431
|
-
detail: metadataIssue
|
|
2432
|
-
};
|
|
2433
|
-
drift.push(row);
|
|
2434
|
-
assessment.drift.push(row);
|
|
2435
|
-
assessments.push(assessment);
|
|
2436
|
-
continue;
|
|
2437
|
-
}
|
|
2438
|
-
let resolved;
|
|
2439
|
-
try {
|
|
2440
|
-
const cachedSource = unwrapAsyncResult2(await toAsyncResult2(getCachedSource(entry)));
|
|
2441
|
-
resolved = resolveCandidateFromCachedSource2(entry, cachedSource, behavior.keepResolved);
|
|
2442
|
-
if (entry.source.type === "local") {
|
|
2443
|
-
const currentResolvedPath = fs8.realpathSync(resolved.plugin.path);
|
|
2444
|
-
if (currentResolvedPath !== path9.resolve(entry.source.resolvedPath)) {
|
|
2445
|
-
const row = {
|
|
2446
|
-
skillName: entry.skillName,
|
|
2447
|
-
kind: "migrate-required",
|
|
2448
|
-
detail: `local source identity changed; run ${migrateHint2(entry.skillName)}`
|
|
2449
|
-
};
|
|
2450
|
-
drift.push(row);
|
|
2451
|
-
assessment.drift.push(row);
|
|
2452
|
-
if (resolved.cleanup && !behavior.keepResolved) {
|
|
2453
|
-
resolved.cleanup();
|
|
2454
|
-
resolved = void 0;
|
|
2455
|
-
}
|
|
2456
|
-
assessments.push(assessment);
|
|
2457
|
-
continue;
|
|
2458
|
-
}
|
|
2459
|
-
}
|
|
2460
|
-
const sourceHash = await hashDirectoryAsync(resolved.plugin.path);
|
|
2461
|
-
assessment.sourceHash = sourceHash;
|
|
2462
|
-
assessment.refreshedSource = await buildRefreshedSourceMetadata2(
|
|
2463
|
-
entry,
|
|
2464
|
-
resolved,
|
|
2465
|
-
cachedSource,
|
|
2466
|
-
sourceHash
|
|
2467
|
-
);
|
|
2468
|
-
if (sourceHash !== entry.sourceHash) {
|
|
2469
|
-
const row = {
|
|
2470
|
-
skillName: entry.skillName,
|
|
2471
|
-
kind: "changed-source",
|
|
2472
|
-
detail: "source hash changed"
|
|
2473
|
-
};
|
|
2474
|
-
drift.push(row);
|
|
2475
|
-
assessment.drift.push(row);
|
|
2476
|
-
}
|
|
2477
|
-
if (behavior.keepResolved) {
|
|
2478
|
-
assessment.resolved = resolved;
|
|
2479
|
-
}
|
|
2480
|
-
} catch (error) {
|
|
2481
|
-
const asText = error instanceof Error ? error.message : String(error);
|
|
2482
|
-
const migrateRequired = entry.source.type === "local" && (asText.includes("Local source not found") || asText.includes("not found in source"));
|
|
2483
|
-
const row = {
|
|
2484
|
-
skillName: entry.skillName,
|
|
2485
|
-
kind: migrateRequired ? "migrate-required" : "missing-source",
|
|
2486
|
-
detail: migrateRequired ? `local source identity changed; run ${migrateHint2(entry.skillName)}` : asText
|
|
2487
|
-
};
|
|
2488
|
-
drift.push(row);
|
|
2489
|
-
assessment.drift.push(row);
|
|
2490
|
-
} finally {
|
|
2491
|
-
if (resolved?.cleanup && !behavior.keepResolved) {
|
|
2492
|
-
resolved.cleanup();
|
|
2493
|
-
}
|
|
2494
|
-
}
|
|
2495
|
-
assessments.push(assessment);
|
|
2496
|
-
}
|
|
2497
|
-
const canonical = listCanonicalResourceDirs("plugin", Boolean(options.global), cwd);
|
|
2498
|
-
const lockNames = new Set(lock.entries.map((item) => item.skillName));
|
|
2499
|
-
for (const pluginName of canonical) {
|
|
2500
|
-
if (!lockNames.has(pluginName) && includeByPlugin({ skillName: pluginName }, options.plugin)) {
|
|
2501
|
-
drift.push({
|
|
2502
|
-
skillName: pluginName,
|
|
2503
|
-
kind: "lock-missing",
|
|
2504
|
-
detail: "installed plugin is not tracked in lockfile"
|
|
2505
|
-
});
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
return { drift, checked: entries.length, assessments };
|
|
2509
|
-
} finally {
|
|
2510
|
-
if (!behavior.keepResolved) {
|
|
2511
|
-
for (const cachedSourcePromise of sourceCache.values()) {
|
|
2512
|
-
const cachedSource = await cachedSourcePromise.catch(() => null);
|
|
2513
|
-
if (cachedSource?.kind === "prepared") {
|
|
2514
|
-
cachedSource.cleanupNow();
|
|
2515
|
-
}
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
|
|
2521
|
-
// ../../packages/core/src/runtime/validate-analysis.ts
|
|
2522
|
-
import fs11 from "node:fs";
|
|
2523
|
-
import path12 from "node:path";
|
|
2524
|
-
import os5 from "node:os";
|
|
2525
|
-
import matter2 from "gray-matter";
|
|
2526
|
-
|
|
2527
|
-
// ../../packages/core/src/runtime/skill-installer.ts
|
|
2528
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2529
|
-
import fs10 from "node:fs";
|
|
2530
|
-
import os4 from "node:os";
|
|
2531
|
-
import path11 from "node:path";
|
|
2532
|
-
import YAML2 from "yaml";
|
|
2533
|
-
import { z } from "zod";
|
|
2534
|
-
|
|
2535
|
-
// ../../packages/core/src/runtime/installer-security.ts
|
|
2536
|
-
import fs9 from "node:fs";
|
|
2537
|
-
import path10 from "node:path";
|
|
2538
|
-
function isInsideRoot(rootDir, candidatePath) {
|
|
2539
|
-
const relative = path10.relative(rootDir, candidatePath);
|
|
2540
|
-
return Boolean(relative) && !relative.startsWith("..") && !path10.isAbsolute(relative);
|
|
2541
|
-
}
|
|
2542
|
-
function toEscapeViolation(source) {
|
|
2543
|
-
return {
|
|
2544
|
-
rule: "installer-local-dependency-path-escape",
|
|
2545
|
-
message: `local dependency escapes source root: ${source}`,
|
|
2546
|
-
severity: "error",
|
|
2547
|
-
blocking: true
|
|
2548
|
-
};
|
|
2549
|
-
}
|
|
2550
|
-
function evaluateInstallerLocalDependency(input, _options = {}) {
|
|
2551
|
-
if (path10.isAbsolute(input.source)) {
|
|
2552
|
-
return {
|
|
2553
|
-
ok: false,
|
|
2554
|
-
violation: {
|
|
2555
|
-
rule: "installer-local-dependency-absolute-path",
|
|
2556
|
-
message: `absolute local dependency paths are not allowed: ${input.source}`,
|
|
2557
|
-
severity: "error",
|
|
2558
|
-
blocking: true
|
|
2559
|
-
}
|
|
2560
|
-
};
|
|
2561
|
-
}
|
|
2562
|
-
const resolvedRoot = path10.resolve(input.sourceRoot);
|
|
2563
|
-
const resolvedSourcePath = path10.resolve(resolvedRoot, input.source);
|
|
2564
|
-
if (!isInsideRoot(resolvedRoot, resolvedSourcePath)) {
|
|
2565
|
-
return {
|
|
2566
|
-
ok: false,
|
|
2567
|
-
violation: toEscapeViolation(input.source)
|
|
2568
|
-
};
|
|
2569
|
-
}
|
|
2570
|
-
if (fs9.existsSync(resolvedSourcePath)) {
|
|
2571
|
-
const realRoot = fs9.realpathSync.native ? fs9.realpathSync.native(resolvedRoot) : fs9.realpathSync(resolvedRoot);
|
|
2572
|
-
const realSource = fs9.realpathSync.native ? fs9.realpathSync.native(resolvedSourcePath) : fs9.realpathSync(resolvedSourcePath);
|
|
2573
|
-
if (!isInsideRoot(realRoot, realSource)) {
|
|
2574
|
-
return {
|
|
2575
|
-
ok: false,
|
|
2576
|
-
violation: toEscapeViolation(input.source)
|
|
2577
|
-
};
|
|
2578
|
-
}
|
|
2579
|
-
}
|
|
2580
|
-
return {
|
|
2581
|
-
ok: true,
|
|
2582
|
-
resolvedPath: resolvedSourcePath
|
|
2583
|
-
};
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
|
-
// ../../packages/core/src/runtime/policy.ts
|
|
2587
|
-
function applyMode(result, mode) {
|
|
2588
|
-
if (mode === "enforce" || result.ok) {
|
|
2589
|
-
return result;
|
|
2590
|
-
}
|
|
2591
|
-
const violation = "violation" in result ? result.violation : void 0;
|
|
2592
|
-
if (!violation) {
|
|
2593
|
-
return result;
|
|
2594
|
-
}
|
|
2595
|
-
return {
|
|
2596
|
-
ok: false,
|
|
2597
|
-
violation: {
|
|
2598
|
-
...violation,
|
|
2599
|
-
severity: "warning",
|
|
2600
|
-
blocking: false
|
|
2601
|
-
}
|
|
2602
|
-
};
|
|
2603
|
-
}
|
|
2604
|
-
function evaluateInstallerLocalDependencyPolicy(input, mode) {
|
|
2605
|
-
return applyMode(evaluateInstallerLocalDependency(input, { policyMode: "fixed" }), mode);
|
|
2606
|
-
}
|
|
2607
|
-
function evaluateHookTrustPolicy(input) {
|
|
2608
|
-
if (input.sourceType !== "well-known") {
|
|
2609
|
-
return { allowed: true };
|
|
2610
|
-
}
|
|
2611
|
-
if (input.trustWellKnown) {
|
|
2612
|
-
return { allowed: true };
|
|
2613
|
-
}
|
|
2614
|
-
if (input.mode === "warn") {
|
|
2615
|
-
return {
|
|
2616
|
-
allowed: true,
|
|
2617
|
-
violation: {
|
|
2618
|
-
rule: "hook-trust-required",
|
|
2619
|
-
message: "Well-known hook commands are untrusted. Proceeding due to warning policy mode.",
|
|
2620
|
-
severity: "warning",
|
|
2621
|
-
blocking: false
|
|
2622
|
-
}
|
|
2623
|
-
};
|
|
2624
|
-
}
|
|
2625
|
-
return {
|
|
2626
|
-
allowed: false,
|
|
2627
|
-
violation: {
|
|
2628
|
-
rule: "hook-trust-required",
|
|
2629
|
-
message: "Blocked skill-installer hook commands for well-known source. Trust this source explicitly or use warning policy mode.",
|
|
2630
|
-
severity: "error",
|
|
2631
|
-
blocking: true
|
|
2632
|
-
}
|
|
2633
|
-
};
|
|
2634
|
-
}
|
|
2635
|
-
|
|
2636
|
-
// ../../packages/core/src/runtime/skill-installer.ts
|
|
2637
|
-
var InstallerSecurityError = class extends Error {
|
|
2638
|
-
violation;
|
|
2639
|
-
constructor(violation) {
|
|
2640
|
-
super(violation.message);
|
|
2641
|
-
this.name = "InstallerSecurityError";
|
|
2642
|
-
this.violation = violation;
|
|
2643
|
-
}
|
|
2644
|
-
};
|
|
2645
|
-
function isInstallerSecurityError(error) {
|
|
2646
|
-
return error instanceof InstallerSecurityError;
|
|
2647
|
-
}
|
|
2648
|
-
var InstallerPolicyError = class extends Error {
|
|
2649
|
-
violation;
|
|
2650
|
-
constructor(violation) {
|
|
2651
|
-
super(violation.message);
|
|
2652
|
-
this.name = "InstallerPolicyError";
|
|
2653
|
-
this.violation = violation;
|
|
2654
|
-
}
|
|
2655
|
-
};
|
|
2656
|
-
function isInstallerPolicyError(error) {
|
|
2657
|
-
return error instanceof InstallerPolicyError;
|
|
2658
|
-
}
|
|
2659
|
-
var dependencyObjectSchema = z.object({
|
|
2660
|
-
source: z.string().min(1),
|
|
2661
|
-
path: z.string().min(1)
|
|
2662
|
-
}).strict();
|
|
2663
|
-
var installerConfigSchema = z.object({
|
|
2664
|
-
schemaVersion: z.literal(1),
|
|
2665
|
-
"pre-install": z.array(z.string().min(1)).optional().default([]),
|
|
2666
|
-
dependencies: z.array(z.union([z.string().min(1), dependencyObjectSchema])).optional().default([]),
|
|
2667
|
-
"post-install": z.array(z.string().min(1)).optional().default([])
|
|
2668
|
-
}).strict();
|
|
2669
|
-
function ensureInsideRoot(rootDir, relativeTarget) {
|
|
2670
|
-
const resolved = path11.resolve(rootDir, relativeTarget);
|
|
2671
|
-
const relative = path11.relative(rootDir, resolved);
|
|
2672
|
-
if (!relative || relative.startsWith("..") || path11.isAbsolute(relative)) {
|
|
2673
|
-
throw new Error(`Unsafe destination path: ${relativeTarget}`);
|
|
2674
|
-
}
|
|
2675
|
-
return resolved;
|
|
2676
|
-
}
|
|
2677
|
-
function sourceLooksLikeUrl(source) {
|
|
2678
|
-
try {
|
|
2679
|
-
const parsed = new URL(source);
|
|
2680
|
-
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
2681
|
-
} catch {
|
|
2682
|
-
return false;
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
function sourceLooksLikeRepoShorthand(source) {
|
|
2686
|
-
const trimmed = source.trim().replace(/^https?:\/\//, "");
|
|
2687
|
-
return /^(github\.com|gitlab\.com)\/[^/]+\/[^/]+(?:\.git)?\/?$/.test(trimmed);
|
|
2688
|
-
}
|
|
2689
|
-
function parseRepoSource(source) {
|
|
2690
|
-
const withoutProtocol = source.trim().replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
2691
|
-
const match = withoutProtocol.match(/^(github\.com|gitlab\.com)\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
2692
|
-
if (!match) {
|
|
2693
|
-
throw new Error(`Unsupported repository dependency source: ${source}`);
|
|
2694
|
-
}
|
|
2695
|
-
const host = match[1];
|
|
2696
|
-
const owner = match[2];
|
|
2697
|
-
const repo = match[3];
|
|
2698
|
-
return {
|
|
2699
|
-
repoUrl: `https://${host}/${owner}/${repo}.git`,
|
|
2700
|
-
repoName: repo
|
|
2701
|
-
};
|
|
2702
|
-
}
|
|
2703
|
-
function deriveDestinationNameFromSource(source) {
|
|
2704
|
-
if (sourceLooksLikeUrl(source)) {
|
|
2705
|
-
const parsed = new URL(source);
|
|
2706
|
-
const parts = parsed.pathname.split("/").filter(Boolean);
|
|
2707
|
-
const leaf2 = parts[parts.length - 1];
|
|
2708
|
-
if (!leaf2) {
|
|
2709
|
-
throw new Error(`Cannot derive dependency name from URL source: ${source}`);
|
|
2710
|
-
}
|
|
2711
|
-
return leaf2;
|
|
2056
|
+
return leaf2;
|
|
2712
2057
|
}
|
|
2713
2058
|
if (sourceLooksLikeRepoShorthand(source)) {
|
|
2714
2059
|
return parseRepoSource(source).repoName;
|
|
2715
2060
|
}
|
|
2716
|
-
const leaf =
|
|
2717
|
-
if (!leaf || leaf === "." || leaf ===
|
|
2061
|
+
const leaf = path9.basename(source);
|
|
2062
|
+
if (!leaf || leaf === "." || leaf === path9.sep) {
|
|
2718
2063
|
throw new Error(`Cannot derive dependency name from source: ${source}`);
|
|
2719
2064
|
}
|
|
2720
2065
|
return leaf;
|
|
@@ -2770,11 +2115,11 @@ function parseConfigObject(raw) {
|
|
|
2770
2115
|
};
|
|
2771
2116
|
}
|
|
2772
2117
|
function assertNoLegacyInstallerBlock(skillDir) {
|
|
2773
|
-
const openAiYamlPath =
|
|
2774
|
-
if (!
|
|
2118
|
+
const openAiYamlPath = path9.join(skillDir, "agents", "openai.yaml");
|
|
2119
|
+
if (!fs8.existsSync(openAiYamlPath) || !fs8.statSync(openAiYamlPath).isFile()) {
|
|
2775
2120
|
return;
|
|
2776
2121
|
}
|
|
2777
|
-
const parsed = YAML2.parse(
|
|
2122
|
+
const parsed = YAML2.parse(fs8.readFileSync(openAiYamlPath, "utf8"));
|
|
2778
2123
|
if (parsed && typeof parsed === "object" && typeof parsed["skill-installer"] !== "undefined") {
|
|
2779
2124
|
throw new Error(
|
|
2780
2125
|
"Legacy skill-installer config detected in agents/openai.yaml. Move it to skill-installer.yaml or skill-installer.json."
|
|
@@ -2783,10 +2128,10 @@ function assertNoLegacyInstallerBlock(skillDir) {
|
|
|
2783
2128
|
}
|
|
2784
2129
|
function loadInstallerConfig(skillDir) {
|
|
2785
2130
|
assertNoLegacyInstallerBlock(skillDir);
|
|
2786
|
-
const yamlPath =
|
|
2787
|
-
const jsonPath =
|
|
2788
|
-
const hasYaml =
|
|
2789
|
-
const hasJson =
|
|
2131
|
+
const yamlPath = path9.join(skillDir, "skill-installer.yaml");
|
|
2132
|
+
const jsonPath = path9.join(skillDir, "skill-installer.json");
|
|
2133
|
+
const hasYaml = fs8.existsSync(yamlPath) && fs8.statSync(yamlPath).isFile();
|
|
2134
|
+
const hasJson = fs8.existsSync(jsonPath) && fs8.statSync(jsonPath).isFile();
|
|
2790
2135
|
if (hasYaml && hasJson) {
|
|
2791
2136
|
throw new Error(
|
|
2792
2137
|
"Both skill-installer.yaml and skill-installer.json exist. Keep only one installer config file."
|
|
@@ -2801,10 +2146,10 @@ function loadInstallerConfig(skillDir) {
|
|
|
2801
2146
|
};
|
|
2802
2147
|
}
|
|
2803
2148
|
if (hasYaml) {
|
|
2804
|
-
const parsed = YAML2.parse(
|
|
2149
|
+
const parsed = YAML2.parse(fs8.readFileSync(yamlPath, "utf8"));
|
|
2805
2150
|
return parseConfigObject(parsed);
|
|
2806
2151
|
}
|
|
2807
|
-
const raw = JSON.parse(
|
|
2152
|
+
const raw = JSON.parse(fs8.readFileSync(jsonPath, "utf8"));
|
|
2808
2153
|
return parseConfigObject(raw);
|
|
2809
2154
|
}
|
|
2810
2155
|
function runHookPhase(phase, commands, cwd, events) {
|
|
@@ -2869,11 +2214,11 @@ async function prepareDependency(source, targetPath, index, sourceCwd, stagingDi
|
|
|
2869
2214
|
message: `[skills] ${violation.message}`
|
|
2870
2215
|
});
|
|
2871
2216
|
}
|
|
2872
|
-
const sourcePath = evaluation.ok ? evaluation.resolvedPath :
|
|
2873
|
-
if (!
|
|
2217
|
+
const sourcePath = evaluation.ok ? evaluation.resolvedPath : path9.resolve(sourceCwd, source);
|
|
2218
|
+
if (!fs8.existsSync(sourcePath)) {
|
|
2874
2219
|
throw new Error(`Dependency[${index}] (local) source not found: ${source}`);
|
|
2875
2220
|
}
|
|
2876
|
-
|
|
2221
|
+
fs8.accessSync(sourcePath, fs8.constants.R_OK);
|
|
2877
2222
|
events.push({
|
|
2878
2223
|
level: "info",
|
|
2879
2224
|
message: `[skills] dependency[${index}] preflight-validated: ${source}`
|
|
@@ -2889,7 +2234,7 @@ async function prepareDependency(source, targetPath, index, sourceCwd, stagingDi
|
|
|
2889
2234
|
if (sourceKind === "repo") {
|
|
2890
2235
|
const stagePath = ensureInsideRoot(
|
|
2891
2236
|
stagingDir,
|
|
2892
|
-
`repo-${index}-${
|
|
2237
|
+
`repo-${index}-${path9.basename(targetPath).replace(/[^a-zA-Z0-9._-]/g, "_")}`
|
|
2893
2238
|
);
|
|
2894
2239
|
const { repoUrl } = parseRepoSource(source);
|
|
2895
2240
|
runGitClone(repoUrl, stagePath);
|
|
@@ -2917,10 +2262,10 @@ async function prepareDependency(source, targetPath, index, sourceCwd, stagingDi
|
|
|
2917
2262
|
}
|
|
2918
2263
|
const stagedFilePath = ensureInsideRoot(
|
|
2919
2264
|
stagingDir,
|
|
2920
|
-
`remote-${index}-${
|
|
2265
|
+
`remote-${index}-${path9.basename(targetPath)}`
|
|
2921
2266
|
);
|
|
2922
|
-
|
|
2923
|
-
|
|
2267
|
+
fs8.mkdirSync(path9.dirname(stagedFilePath), { recursive: true });
|
|
2268
|
+
fs8.writeFileSync(stagedFilePath, Buffer.from(await response.arrayBuffer()));
|
|
2924
2269
|
events.push({
|
|
2925
2270
|
level: "info",
|
|
2926
2271
|
message: `[skills] dependency[${index}] staged: ${source}`
|
|
@@ -2969,7 +2314,7 @@ async function prepareInstallerArtifacts(skillDir, sourceCwd, options = {}) {
|
|
|
2969
2314
|
events
|
|
2970
2315
|
};
|
|
2971
2316
|
}
|
|
2972
|
-
const stagingDir =
|
|
2317
|
+
const stagingDir = fs8.mkdtempSync(path9.join(os4.tmpdir(), "skillspp-installer-stage-"));
|
|
2973
2318
|
const preparedDependencies = [];
|
|
2974
2319
|
const seenTargetPaths = /* @__PURE__ */ new Set();
|
|
2975
2320
|
try {
|
|
@@ -2982,9 +2327,9 @@ async function prepareInstallerArtifacts(skillDir, sourceCwd, options = {}) {
|
|
|
2982
2327
|
}
|
|
2983
2328
|
seenTargetPaths.add(normalizedTarget);
|
|
2984
2329
|
const destinationInSkill = ensureInsideRoot(skillDir, targetPath);
|
|
2985
|
-
if (
|
|
2330
|
+
if (fs8.existsSync(destinationInSkill)) {
|
|
2986
2331
|
throw new Error(
|
|
2987
|
-
`Dependency[${i}] destination already exists: ${
|
|
2332
|
+
`Dependency[${i}] destination already exists: ${path9.relative(
|
|
2988
2333
|
skillDir,
|
|
2989
2334
|
destinationInSkill
|
|
2990
2335
|
)}`
|
|
@@ -3009,13 +2354,13 @@ async function prepareInstallerArtifacts(skillDir, sourceCwd, options = {}) {
|
|
|
3009
2354
|
events
|
|
3010
2355
|
};
|
|
3011
2356
|
} catch (error) {
|
|
3012
|
-
|
|
2357
|
+
fs8.rmSync(stagingDir, { recursive: true, force: true });
|
|
3013
2358
|
throw error;
|
|
3014
2359
|
}
|
|
3015
2360
|
}
|
|
3016
2361
|
function cleanupPreparedInstallerArtifacts(prepared) {
|
|
3017
2362
|
if (prepared.stagingDir) {
|
|
3018
|
-
|
|
2363
|
+
fs8.rmSync(prepared.stagingDir, { recursive: true, force: true });
|
|
3019
2364
|
}
|
|
3020
2365
|
}
|
|
3021
2366
|
async function applyInstallerArtifacts(installedSkillDir, prepared) {
|
|
@@ -3025,37 +2370,37 @@ async function applyInstallerArtifacts(installedSkillDir, prepared) {
|
|
|
3025
2370
|
runHookPhase("pre-install", prepared.preInstall, installedSkillDir, prepared.events);
|
|
3026
2371
|
for (const dep of prepared.preparedDependencies) {
|
|
3027
2372
|
const destinationPath = ensureInsideRoot(installedSkillDir, dep.targetPath);
|
|
3028
|
-
if (
|
|
2373
|
+
if (fs8.existsSync(destinationPath)) {
|
|
3029
2374
|
throw new Error(
|
|
3030
|
-
`Dependency[${dep.index}] destination already exists: ${
|
|
2375
|
+
`Dependency[${dep.index}] destination already exists: ${path9.relative(
|
|
3031
2376
|
installedSkillDir,
|
|
3032
2377
|
destinationPath
|
|
3033
2378
|
)}`
|
|
3034
2379
|
);
|
|
3035
2380
|
}
|
|
3036
|
-
|
|
2381
|
+
fs8.mkdirSync(path9.dirname(destinationPath), { recursive: true });
|
|
3037
2382
|
if (dep.kind === "local") {
|
|
3038
|
-
const stat =
|
|
2383
|
+
const stat = fs8.statSync(dep.sourcePath);
|
|
3039
2384
|
if (stat.isDirectory()) {
|
|
3040
|
-
|
|
2385
|
+
fs8.cpSync(dep.sourcePath, destinationPath, {
|
|
3041
2386
|
recursive: true,
|
|
3042
2387
|
force: false,
|
|
3043
2388
|
errorOnExist: true
|
|
3044
2389
|
});
|
|
3045
2390
|
} else {
|
|
3046
|
-
|
|
2391
|
+
fs8.copyFileSync(dep.sourcePath, destinationPath);
|
|
3047
2392
|
}
|
|
3048
2393
|
} else if (dep.kind === "remote-bytes") {
|
|
3049
|
-
|
|
2394
|
+
fs8.copyFileSync(dep.remoteBufferPath, destinationPath);
|
|
3050
2395
|
} else {
|
|
3051
2396
|
try {
|
|
3052
|
-
|
|
2397
|
+
fs8.renameSync(dep.repoStagePath, destinationPath);
|
|
3053
2398
|
} catch (error) {
|
|
3054
2399
|
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
3055
2400
|
if (code !== "EXDEV") {
|
|
3056
2401
|
throw error;
|
|
3057
2402
|
}
|
|
3058
|
-
|
|
2403
|
+
fs8.cpSync(dep.repoStagePath, destinationPath, {
|
|
3059
2404
|
recursive: true,
|
|
3060
2405
|
force: false,
|
|
3061
2406
|
errorOnExist: true
|
|
@@ -3114,8 +2459,8 @@ var typeRules = [
|
|
|
3114
2459
|
id: "framework-references-dir",
|
|
3115
2460
|
when: (frontmatter) => frontmatter.type === "framework",
|
|
3116
2461
|
validate: ({ skillDir, skillName, diagnostics }) => {
|
|
3117
|
-
const referencesDir =
|
|
3118
|
-
if (!
|
|
2462
|
+
const referencesDir = path10.join(skillDir, "references");
|
|
2463
|
+
if (!fs9.existsSync(referencesDir) || !fs9.statSync(referencesDir).isDirectory()) {
|
|
3119
2464
|
addDiagnostic(diagnostics, {
|
|
3120
2465
|
severity: "error",
|
|
3121
2466
|
skill: skillName,
|
|
@@ -3128,11 +2473,11 @@ var typeRules = [
|
|
|
3128
2473
|
}
|
|
3129
2474
|
];
|
|
3130
2475
|
async function validateInstallerDependencies(skillDir, sourceRoot, diagnostics, skillName) {
|
|
3131
|
-
const installerConfigPath =
|
|
2476
|
+
const installerConfigPath = fs9.existsSync(path10.join(skillDir, "skill-installer.yaml")) ? path10.join(skillDir, "skill-installer.yaml") : path10.join(skillDir, "skill-installer.json");
|
|
3132
2477
|
try {
|
|
3133
2478
|
const installer = loadInstallerConfig(skillDir);
|
|
3134
2479
|
const fallbackRoots = Array.from(
|
|
3135
|
-
/* @__PURE__ */ new Set([
|
|
2480
|
+
/* @__PURE__ */ new Set([path10.resolve(sourceRoot), path10.resolve(process.cwd())])
|
|
3136
2481
|
);
|
|
3137
2482
|
let hasSecurityViolation = false;
|
|
3138
2483
|
for (const dep of installer.dependencies) {
|
|
@@ -3172,18 +2517,18 @@ async function validateInstallerDependencies(skillDir, sourceRoot, diagnostics,
|
|
|
3172
2517
|
if (hasSecurityViolation) {
|
|
3173
2518
|
return;
|
|
3174
2519
|
}
|
|
3175
|
-
const tempSkillDir =
|
|
2520
|
+
const tempSkillDir = fs9.mkdtempSync(path10.join(os5.tmpdir(), "skillspp-validate-installer-"));
|
|
3176
2521
|
try {
|
|
3177
2522
|
const filesToCopy = ["SKILL.md", "skill-installer.yaml", "skill-installer.json"];
|
|
3178
2523
|
for (const fileName of filesToCopy) {
|
|
3179
|
-
const src =
|
|
3180
|
-
if (
|
|
3181
|
-
|
|
2524
|
+
const src = path10.join(skillDir, fileName);
|
|
2525
|
+
if (fs9.existsSync(src) && fs9.statSync(src).isFile()) {
|
|
2526
|
+
fs9.copyFileSync(src, path10.join(tempSkillDir, fileName));
|
|
3182
2527
|
}
|
|
3183
2528
|
}
|
|
3184
|
-
const agentsDir =
|
|
3185
|
-
if (
|
|
3186
|
-
|
|
2529
|
+
const agentsDir = path10.join(skillDir, "agents");
|
|
2530
|
+
if (fs9.existsSync(agentsDir) && fs9.statSync(agentsDir).isDirectory()) {
|
|
2531
|
+
fs9.cpSync(agentsDir, path10.join(tempSkillDir, "agents"), {
|
|
3187
2532
|
recursive: true,
|
|
3188
2533
|
force: true
|
|
3189
2534
|
});
|
|
@@ -3225,7 +2570,7 @@ async function validateInstallerDependencies(skillDir, sourceRoot, diagnostics,
|
|
|
3225
2570
|
throw lastMissingSourceError;
|
|
3226
2571
|
}
|
|
3227
2572
|
} finally {
|
|
3228
|
-
|
|
2573
|
+
fs9.rmSync(tempSkillDir, { recursive: true, force: true });
|
|
3229
2574
|
}
|
|
3230
2575
|
} catch (error) {
|
|
3231
2576
|
if (isInstallerSecurityError(error)) {
|
|
@@ -3258,9 +2603,9 @@ async function validateInstallerDependencies(skillDir, sourceRoot, diagnostics,
|
|
|
3258
2603
|
}
|
|
3259
2604
|
}
|
|
3260
2605
|
async function validateSkillDir(skillDir, sourceRoot, diagnostics, strict, thresholds) {
|
|
3261
|
-
const skillMd =
|
|
3262
|
-
const skillName =
|
|
3263
|
-
if (!
|
|
2606
|
+
const skillMd = path10.join(skillDir, "SKILL.md");
|
|
2607
|
+
const skillName = path10.basename(skillDir);
|
|
2608
|
+
if (!fs9.existsSync(skillMd)) {
|
|
3264
2609
|
addDiagnostic(diagnostics, {
|
|
3265
2610
|
severity: "error",
|
|
3266
2611
|
skill: skillName,
|
|
@@ -3270,7 +2615,7 @@ async function validateSkillDir(skillDir, sourceRoot, diagnostics, strict, thres
|
|
|
3270
2615
|
});
|
|
3271
2616
|
return;
|
|
3272
2617
|
}
|
|
3273
|
-
const content =
|
|
2618
|
+
const content = fs9.readFileSync(skillMd, "utf8");
|
|
3274
2619
|
const lines = content.split(/\r?\n/);
|
|
3275
2620
|
if (lines.length > thresholds.maxLines) {
|
|
3276
2621
|
addDiagnostic(diagnostics, {
|
|
@@ -3336,12 +2681,12 @@ async function validateSkillDir(skillDir, sourceRoot, diagnostics, strict, thres
|
|
|
3336
2681
|
}
|
|
3337
2682
|
}
|
|
3338
2683
|
for (const ref of discoverMarkdownReferences(content)) {
|
|
3339
|
-
const resolved =
|
|
3340
|
-
const rel =
|
|
3341
|
-
if (!rel || rel.startsWith("..") ||
|
|
2684
|
+
const resolved = path10.resolve(skillDir, ref);
|
|
2685
|
+
const rel = path10.relative(skillDir, resolved);
|
|
2686
|
+
if (!rel || rel.startsWith("..") || path10.isAbsolute(rel)) {
|
|
3342
2687
|
continue;
|
|
3343
2688
|
}
|
|
3344
|
-
if (!
|
|
2689
|
+
if (!fs9.existsSync(resolved)) {
|
|
3345
2690
|
addDiagnostic(diagnostics, {
|
|
3346
2691
|
severity: "error",
|
|
3347
2692
|
skill: skillName,
|
|
@@ -3359,11 +2704,11 @@ async function validateSkillDir(skillDir, sourceRoot, diagnostics, strict, thres
|
|
|
3359
2704
|
await validateInstallerDependencies(skillDir, sourceRoot, diagnostics, skillName);
|
|
3360
2705
|
}
|
|
3361
2706
|
async function stageAndValidateLocalRoot(rootPath, dependencyRoot, seenSkillPaths, diagnostics, strict, thresholds, emitProgress) {
|
|
3362
|
-
const resolvedRoot =
|
|
3363
|
-
if (!
|
|
2707
|
+
const resolvedRoot = path10.resolve(rootPath);
|
|
2708
|
+
if (!fs9.existsSync(resolvedRoot) || !fs9.statSync(resolvedRoot).isDirectory()) {
|
|
3364
2709
|
addDiagnostic(diagnostics, {
|
|
3365
2710
|
severity: "error",
|
|
3366
|
-
skill:
|
|
2711
|
+
skill: path10.basename(resolvedRoot),
|
|
3367
2712
|
file: resolvedRoot,
|
|
3368
2713
|
rule: "missing-root",
|
|
3369
2714
|
message: "validation root does not exist"
|
|
@@ -3375,7 +2720,7 @@ async function stageAndValidateLocalRoot(rootPath, dependencyRoot, seenSkillPath
|
|
|
3375
2720
|
if (skills.length === 0) {
|
|
3376
2721
|
addDiagnostic(diagnostics, {
|
|
3377
2722
|
severity: "error",
|
|
3378
|
-
skill:
|
|
2723
|
+
skill: path10.basename(resolvedRoot),
|
|
3379
2724
|
file: resolvedRoot,
|
|
3380
2725
|
rule: "no-skills-discovered",
|
|
3381
2726
|
message: "no SKILL.md files discovered"
|
|
@@ -3383,7 +2728,7 @@ async function stageAndValidateLocalRoot(rootPath, dependencyRoot, seenSkillPath
|
|
|
3383
2728
|
return;
|
|
3384
2729
|
}
|
|
3385
2730
|
for (const skill of skills) {
|
|
3386
|
-
const resolvedSkillPath =
|
|
2731
|
+
const resolvedSkillPath = path10.resolve(skill.path);
|
|
3387
2732
|
if (seenSkillPaths.has(resolvedSkillPath)) {
|
|
3388
2733
|
continue;
|
|
3389
2734
|
}
|
|
@@ -3495,45 +2840,45 @@ async function runValidateAnalysis(options, emitProgress) {
|
|
|
3495
2840
|
}
|
|
3496
2841
|
|
|
3497
2842
|
// ../../packages/core/src/runtime/installer.ts
|
|
3498
|
-
import
|
|
3499
|
-
import
|
|
2843
|
+
import fs10 from "node:fs";
|
|
2844
|
+
import path11 from "node:path";
|
|
3500
2845
|
function sanitizeSkillName(name) {
|
|
3501
2846
|
const sanitized = name.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[.-]+|[.-]+$/g, "");
|
|
3502
2847
|
return sanitized || "unnamed-skill";
|
|
3503
2848
|
}
|
|
3504
2849
|
function ensureSafeInside(baseDir, target) {
|
|
3505
|
-
const resolvedBase =
|
|
3506
|
-
const resolvedTarget =
|
|
3507
|
-
if (!(resolvedTarget === resolvedBase || resolvedTarget.startsWith(`${resolvedBase}${
|
|
2850
|
+
const resolvedBase = path11.resolve(baseDir);
|
|
2851
|
+
const resolvedTarget = path11.resolve(target);
|
|
2852
|
+
if (!(resolvedTarget === resolvedBase || resolvedTarget.startsWith(`${resolvedBase}${path11.sep}`))) {
|
|
3508
2853
|
throw new Error(`Unsafe path detected: ${target}`);
|
|
3509
2854
|
}
|
|
3510
2855
|
}
|
|
3511
2856
|
function symlinkRelative(target, linkPath) {
|
|
3512
|
-
const parent =
|
|
3513
|
-
const relative =
|
|
2857
|
+
const parent = path11.dirname(linkPath);
|
|
2858
|
+
const relative = path11.relative(parent, target);
|
|
3514
2859
|
const symlinkType = process.platform === "win32" ? "junction" : void 0;
|
|
3515
|
-
|
|
2860
|
+
fs10.symlinkSync(relative, linkPath, symlinkType);
|
|
3516
2861
|
}
|
|
3517
2862
|
function installToAgent(itemName, canonicalDir, agent, mode, globalInstall, cwd, resolveAgentBaseDir) {
|
|
3518
2863
|
const agentBase = resolveAgentBaseDir(agent, globalInstall, cwd);
|
|
3519
|
-
const agentDir =
|
|
3520
|
-
|
|
2864
|
+
const agentDir = path11.join(agentBase, itemName);
|
|
2865
|
+
fs10.mkdirSync(agentBase, { recursive: true });
|
|
3521
2866
|
ensureSafeInside(agentBase, agentDir);
|
|
3522
|
-
if (
|
|
2867
|
+
if (path11.resolve(agentDir) === path11.resolve(canonicalDir)) {
|
|
3523
2868
|
return { agent, path: canonicalDir, mode };
|
|
3524
2869
|
}
|
|
3525
2870
|
if (mode === "copy") {
|
|
3526
|
-
|
|
3527
|
-
|
|
2871
|
+
fs10.rmSync(agentDir, { recursive: true, force: true });
|
|
2872
|
+
fs10.cpSync(canonicalDir, agentDir, { recursive: true, force: true });
|
|
3528
2873
|
return { agent, path: agentDir, mode };
|
|
3529
2874
|
}
|
|
3530
2875
|
try {
|
|
3531
|
-
|
|
2876
|
+
fs10.rmSync(agentDir, { recursive: true, force: true });
|
|
3532
2877
|
symlinkRelative(canonicalDir, agentDir);
|
|
3533
2878
|
return { agent, path: agentDir, mode: "symlink" };
|
|
3534
2879
|
} catch {
|
|
3535
|
-
|
|
3536
|
-
|
|
2880
|
+
fs10.rmSync(agentDir, { recursive: true, force: true });
|
|
2881
|
+
fs10.cpSync(canonicalDir, agentDir, { recursive: true, force: true });
|
|
3537
2882
|
return { agent, path: agentDir, mode: "copy" };
|
|
3538
2883
|
}
|
|
3539
2884
|
}
|
|
@@ -3548,23 +2893,12 @@ function installSkillToAgent(skillName, canonicalDir, agent, mode, globalInstall
|
|
|
3548
2893
|
getAgentSkillsDir
|
|
3549
2894
|
);
|
|
3550
2895
|
}
|
|
3551
|
-
function installPluginToAgent(pluginName, canonicalDir, agent, mode, globalInstall, cwd) {
|
|
3552
|
-
return installToAgent(
|
|
3553
|
-
pluginName,
|
|
3554
|
-
canonicalDir,
|
|
3555
|
-
agent,
|
|
3556
|
-
mode,
|
|
3557
|
-
globalInstall,
|
|
3558
|
-
cwd,
|
|
3559
|
-
getAgentPluginsDir
|
|
3560
|
-
);
|
|
3561
|
-
}
|
|
3562
2896
|
function installToCanonicalDir(sourcePath, itemName, canonicalBase) {
|
|
3563
|
-
const canonicalDir =
|
|
3564
|
-
|
|
2897
|
+
const canonicalDir = path11.join(canonicalBase, itemName);
|
|
2898
|
+
fs10.mkdirSync(canonicalBase, { recursive: true });
|
|
3565
2899
|
ensureSafeInside(canonicalBase, canonicalDir);
|
|
3566
|
-
|
|
3567
|
-
|
|
2900
|
+
fs10.rmSync(canonicalDir, { recursive: true, force: true });
|
|
2901
|
+
fs10.cpSync(sourcePath, canonicalDir, { recursive: true, force: true });
|
|
3568
2902
|
return canonicalDir;
|
|
3569
2903
|
}
|
|
3570
2904
|
function installSkill(skill, agents, options) {
|
|
@@ -3595,48 +2929,20 @@ function installSkill(skill, agents, options) {
|
|
|
3595
2929
|
installedTo
|
|
3596
2930
|
};
|
|
3597
2931
|
}
|
|
3598
|
-
function installPlugin(plugin, agents, options) {
|
|
3599
|
-
if (agents.length === 0) {
|
|
3600
|
-
throw new Error("At least one target agent is required for installation.");
|
|
3601
|
-
}
|
|
3602
|
-
const uniqueAgents = Array.from(new Set(agents));
|
|
3603
|
-
const pluginName = sanitizeSkillName(plugin.name);
|
|
3604
|
-
const canonicalAgent = uniqueAgents[0];
|
|
3605
|
-
const canonicalBase = getAgentPluginsDir(canonicalAgent, options.globalInstall, options.cwd);
|
|
3606
|
-
const canonicalDir = installToCanonicalDir(plugin.path, pluginName, canonicalBase);
|
|
3607
|
-
const installedTo = [
|
|
3608
|
-
{ agent: canonicalAgent, path: canonicalDir, mode: options.mode },
|
|
3609
|
-
...uniqueAgents.slice(1).map(
|
|
3610
|
-
(agent) => installPluginToAgent(
|
|
3611
|
-
pluginName,
|
|
3612
|
-
canonicalDir,
|
|
3613
|
-
agent,
|
|
3614
|
-
options.mode,
|
|
3615
|
-
options.globalInstall,
|
|
3616
|
-
options.cwd
|
|
3617
|
-
)
|
|
3618
|
-
)
|
|
3619
|
-
];
|
|
3620
|
-
return {
|
|
3621
|
-
skillName: pluginName,
|
|
3622
|
-
canonicalDir,
|
|
3623
|
-
installedTo
|
|
3624
|
-
};
|
|
3625
|
-
}
|
|
3626
2932
|
|
|
3627
2933
|
// ../../packages/core/src/sources/scanner.ts
|
|
3628
|
-
import
|
|
2934
|
+
import fs11 from "node:fs";
|
|
3629
2935
|
import os6 from "node:os";
|
|
3630
|
-
import
|
|
2936
|
+
import path12 from "node:path";
|
|
3631
2937
|
function listDirs(dir) {
|
|
3632
|
-
if (!
|
|
2938
|
+
if (!fs11.existsSync(dir) || !fs11.statSync(dir).isDirectory()) {
|
|
3633
2939
|
return [];
|
|
3634
2940
|
}
|
|
3635
|
-
return
|
|
2941
|
+
return fs11.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
3636
2942
|
}
|
|
3637
2943
|
function detectLocalGlobalConflicts(cwd) {
|
|
3638
|
-
const localDir =
|
|
3639
|
-
const globalDir =
|
|
2944
|
+
const localDir = path12.join(cwd, ".agents", "skills");
|
|
2945
|
+
const globalDir = path12.join(os6.homedir(), ".config", "agents", "skills");
|
|
3640
2946
|
const local = new Set(listDirs(localDir));
|
|
3641
2947
|
const global = new Set(listDirs(globalDir));
|
|
3642
2948
|
const overlap = [...local].filter((name) => global.has(name));
|
|
@@ -3646,30 +2952,30 @@ function detectLocalGlobalConflicts(cwd) {
|
|
|
3646
2952
|
}));
|
|
3647
2953
|
}
|
|
3648
2954
|
function readPackageMeta(packageDir) {
|
|
3649
|
-
const packageJson =
|
|
3650
|
-
if (!
|
|
2955
|
+
const packageJson = path12.join(packageDir, "package.json");
|
|
2956
|
+
if (!fs11.existsSync(packageJson) || !fs11.statSync(packageJson).isFile()) {
|
|
3651
2957
|
return {
|
|
3652
|
-
name:
|
|
2958
|
+
name: path12.basename(packageDir),
|
|
3653
2959
|
version: "0.0.0"
|
|
3654
2960
|
};
|
|
3655
2961
|
}
|
|
3656
|
-
const parsed = JSON.parse(
|
|
2962
|
+
const parsed = JSON.parse(fs11.readFileSync(packageJson, "utf8"));
|
|
3657
2963
|
return {
|
|
3658
|
-
name: parsed.name ||
|
|
2964
|
+
name: parsed.name || path12.basename(packageDir),
|
|
3659
2965
|
version: parsed.version || "0.0.0"
|
|
3660
2966
|
};
|
|
3661
2967
|
}
|
|
3662
2968
|
function collectSkillsFromPackage(packageDir, depth, out) {
|
|
3663
2969
|
const meta = readPackageMeta(packageDir);
|
|
3664
|
-
const skillsDir =
|
|
3665
|
-
if (
|
|
3666
|
-
for (const entry of
|
|
2970
|
+
const skillsDir = path12.join(packageDir, "skills");
|
|
2971
|
+
if (fs11.existsSync(skillsDir) && fs11.statSync(skillsDir).isDirectory()) {
|
|
2972
|
+
for (const entry of fs11.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
3667
2973
|
if (!entry.isDirectory()) {
|
|
3668
2974
|
continue;
|
|
3669
2975
|
}
|
|
3670
|
-
const skillDir =
|
|
3671
|
-
const skillMd =
|
|
3672
|
-
if (!
|
|
2976
|
+
const skillDir = path12.join(skillsDir, entry.name);
|
|
2977
|
+
const skillMd = path12.join(skillDir, "SKILL.md");
|
|
2978
|
+
if (!fs11.existsSync(skillMd) || !fs11.statSync(skillMd).isFile()) {
|
|
3673
2979
|
continue;
|
|
3674
2980
|
}
|
|
3675
2981
|
out.push({
|
|
@@ -3683,42 +2989,42 @@ function collectSkillsFromPackage(packageDir, depth, out) {
|
|
|
3683
2989
|
}
|
|
3684
2990
|
}
|
|
3685
2991
|
function walkNodeModules(nodeModulesDir, depth, maxDepth, seen, out) {
|
|
3686
|
-
const resolvedNodeModules =
|
|
2992
|
+
const resolvedNodeModules = path12.resolve(nodeModulesDir);
|
|
3687
2993
|
if (seen.has(resolvedNodeModules) || depth > maxDepth) {
|
|
3688
2994
|
return;
|
|
3689
2995
|
}
|
|
3690
2996
|
seen.add(resolvedNodeModules);
|
|
3691
|
-
if (!
|
|
2997
|
+
if (!fs11.existsSync(resolvedNodeModules) || !fs11.statSync(resolvedNodeModules).isDirectory()) {
|
|
3692
2998
|
return;
|
|
3693
2999
|
}
|
|
3694
|
-
for (const entry of
|
|
3000
|
+
for (const entry of fs11.readdirSync(resolvedNodeModules, {
|
|
3695
3001
|
withFileTypes: true
|
|
3696
3002
|
})) {
|
|
3697
3003
|
if (!entry.isDirectory()) {
|
|
3698
3004
|
continue;
|
|
3699
3005
|
}
|
|
3700
3006
|
if (entry.name.startsWith("@")) {
|
|
3701
|
-
const scopeDir =
|
|
3702
|
-
for (const scoped of
|
|
3007
|
+
const scopeDir = path12.join(resolvedNodeModules, entry.name);
|
|
3008
|
+
for (const scoped of fs11.readdirSync(scopeDir, { withFileTypes: true })) {
|
|
3703
3009
|
if (!scoped.isDirectory()) {
|
|
3704
3010
|
continue;
|
|
3705
3011
|
}
|
|
3706
|
-
const packageDir2 =
|
|
3012
|
+
const packageDir2 = path12.join(scopeDir, scoped.name);
|
|
3707
3013
|
collectSkillsFromPackage(packageDir2, depth, out);
|
|
3708
|
-
walkNodeModules(
|
|
3014
|
+
walkNodeModules(path12.join(packageDir2, "node_modules"), depth + 1, maxDepth, seen, out);
|
|
3709
3015
|
}
|
|
3710
3016
|
continue;
|
|
3711
3017
|
}
|
|
3712
|
-
const packageDir =
|
|
3018
|
+
const packageDir = path12.join(resolvedNodeModules, entry.name);
|
|
3713
3019
|
collectSkillsFromPackage(packageDir, depth, out);
|
|
3714
|
-
walkNodeModules(
|
|
3020
|
+
walkNodeModules(path12.join(packageDir, "node_modules"), depth + 1, maxDepth, seen, out);
|
|
3715
3021
|
}
|
|
3716
3022
|
}
|
|
3717
3023
|
function discoverTransitiveSkillCandidates(cwd, options = {}) {
|
|
3718
3024
|
const maxDepth = options.maxDepth ?? 8;
|
|
3719
3025
|
const out = [];
|
|
3720
3026
|
const seen = /* @__PURE__ */ new Set();
|
|
3721
|
-
walkNodeModules(
|
|
3027
|
+
walkNodeModules(path12.join(cwd, "node_modules"), 0, maxDepth, seen, out);
|
|
3722
3028
|
return out.sort((a, b) => {
|
|
3723
3029
|
if (a.skillName !== b.skillName) {
|
|
3724
3030
|
return a.skillName.localeCompare(b.skillName);
|
|
@@ -3769,8 +3075,8 @@ function detectTransitiveSkillConflicts(candidates) {
|
|
|
3769
3075
|
}
|
|
3770
3076
|
|
|
3771
3077
|
// ../../packages/core/src/runtime/installer-scaffold.ts
|
|
3772
|
-
import
|
|
3773
|
-
import
|
|
3078
|
+
import fs12 from "node:fs";
|
|
3079
|
+
import path13 from "node:path";
|
|
3774
3080
|
import YAML3 from "yaml";
|
|
3775
3081
|
function installerConfigSkeleton() {
|
|
3776
3082
|
return {
|
|
@@ -3781,11 +3087,11 @@ function installerConfigSkeleton() {
|
|
|
3781
3087
|
};
|
|
3782
3088
|
}
|
|
3783
3089
|
function isFile(filePath) {
|
|
3784
|
-
return
|
|
3090
|
+
return fs12.existsSync(filePath) && fs12.statSync(filePath).isFile();
|
|
3785
3091
|
}
|
|
3786
3092
|
function getInstallerConfigState(skillDir) {
|
|
3787
|
-
const yamlPath =
|
|
3788
|
-
const jsonPath =
|
|
3093
|
+
const yamlPath = path13.join(skillDir, "skill-installer.yaml");
|
|
3094
|
+
const jsonPath = path13.join(skillDir, "skill-installer.json");
|
|
3789
3095
|
const hasYaml = isFile(yamlPath);
|
|
3790
3096
|
const hasJson = isFile(jsonPath);
|
|
3791
3097
|
if (hasYaml && hasJson) {
|
|
@@ -3811,7 +3117,7 @@ function scaffoldInstallerConfigFile(skillDir, format) {
|
|
|
3811
3117
|
}
|
|
3812
3118
|
const content = format === "yaml" ? YAML3.stringify(installerConfigSkeleton()) : JSON.stringify(installerConfigSkeleton(), null, 2);
|
|
3813
3119
|
const destinationPath = format === "yaml" ? state.yamlPath : state.jsonPath;
|
|
3814
|
-
|
|
3120
|
+
fs12.writeFileSync(destinationPath, `${content}
|
|
3815
3121
|
`, "utf8");
|
|
3816
3122
|
return { created: true, filePath: destinationPath };
|
|
3817
3123
|
}
|
|
@@ -3873,19 +3179,19 @@ function canonicalSourceIdentity(options) {
|
|
|
3873
3179
|
}
|
|
3874
3180
|
return options.parsedSource.repoUrl;
|
|
3875
3181
|
}
|
|
3876
|
-
function
|
|
3182
|
+
function resolveSafeRealPath2(inputPath) {
|
|
3877
3183
|
try {
|
|
3878
|
-
return
|
|
3184
|
+
return fs13.realpathSync(inputPath);
|
|
3879
3185
|
} catch {
|
|
3880
|
-
return
|
|
3186
|
+
return path14.resolve(inputPath);
|
|
3881
3187
|
}
|
|
3882
3188
|
}
|
|
3883
|
-
function
|
|
3189
|
+
function isLocalSymlinkSource2(localPath) {
|
|
3884
3190
|
try {
|
|
3885
|
-
if (!
|
|
3191
|
+
if (!fs13.existsSync(localPath)) {
|
|
3886
3192
|
return false;
|
|
3887
3193
|
}
|
|
3888
|
-
return
|
|
3194
|
+
return fs13.lstatSync(localPath).isSymbolicLink();
|
|
3889
3195
|
} catch {
|
|
3890
3196
|
return false;
|
|
3891
3197
|
}
|
|
@@ -3899,18 +3205,18 @@ function staleLockfileNameForFormat(format) {
|
|
|
3899
3205
|
function propagateLockfileVisibility(options) {
|
|
3900
3206
|
const lockName = lockfileNameForFormat(options.lockFormat);
|
|
3901
3207
|
const staleLockName = staleLockfileNameForFormat(options.lockFormat);
|
|
3902
|
-
const canonicalLockPath =
|
|
3903
|
-
const canonicalRealPath =
|
|
3208
|
+
const canonicalLockPath = path14.join(options.canonicalDir, lockName);
|
|
3209
|
+
const canonicalRealPath = fs13.existsSync(options.canonicalDir) ? fs13.realpathSync(options.canonicalDir) : path14.resolve(options.canonicalDir);
|
|
3904
3210
|
for (const targetDir of options.targetDirs) {
|
|
3905
|
-
const targetRealPath =
|
|
3211
|
+
const targetRealPath = fs13.existsSync(targetDir) ? fs13.realpathSync(targetDir) : path14.resolve(targetDir);
|
|
3906
3212
|
if (targetRealPath === canonicalRealPath) {
|
|
3907
3213
|
continue;
|
|
3908
3214
|
}
|
|
3909
|
-
const targetLockPath =
|
|
3910
|
-
const staleTargetPath =
|
|
3911
|
-
|
|
3912
|
-
if (
|
|
3913
|
-
|
|
3215
|
+
const targetLockPath = path14.join(targetDir, lockName);
|
|
3216
|
+
const staleTargetPath = path14.join(targetDir, staleLockName);
|
|
3217
|
+
fs13.copyFileSync(canonicalLockPath, targetLockPath);
|
|
3218
|
+
if (fs13.existsSync(staleTargetPath)) {
|
|
3219
|
+
fs13.rmSync(staleTargetPath, { force: true });
|
|
3914
3220
|
}
|
|
3915
3221
|
}
|
|
3916
3222
|
}
|
|
@@ -3955,12 +3261,12 @@ function writeLockEntryAfterInstall(options) {
|
|
|
3955
3261
|
targetDirs: options.outcome.installedTo.map((destination) => destination.path),
|
|
3956
3262
|
lockFormat: selectedFormat
|
|
3957
3263
|
});
|
|
3958
|
-
const staleLockPath =
|
|
3264
|
+
const staleLockPath = path14.join(
|
|
3959
3265
|
options.outcome.canonicalDir,
|
|
3960
3266
|
staleLockfileNameForFormat(selectedFormat)
|
|
3961
3267
|
);
|
|
3962
|
-
if (
|
|
3963
|
-
|
|
3268
|
+
if (fs13.existsSync(staleLockPath)) {
|
|
3269
|
+
fs13.rmSync(staleLockPath, { force: true });
|
|
3964
3270
|
}
|
|
3965
3271
|
}
|
|
3966
3272
|
function buildRemoteSkill(remote) {
|
|
@@ -3974,23 +3280,6 @@ function buildRemoteSkill(remote) {
|
|
|
3974
3280
|
cleanup: staged.cleanup
|
|
3975
3281
|
};
|
|
3976
3282
|
}
|
|
3977
|
-
async function buildRemotePlugin(remote) {
|
|
3978
|
-
const staged = stageRemotePluginFilesToTempDir(remote.installName, remote.files);
|
|
3979
|
-
try {
|
|
3980
|
-
const plugins = await discoverPluginsAsync(staged.path, [remote.installName]);
|
|
3981
|
-
const plugin = plugins[0];
|
|
3982
|
-
if (!plugin) {
|
|
3983
|
-
throw new Error(`Plugin '${remote.installName}' is missing plugin.json`);
|
|
3984
|
-
}
|
|
3985
|
-
return {
|
|
3986
|
-
plugin,
|
|
3987
|
-
cleanup: staged.cleanup
|
|
3988
|
-
};
|
|
3989
|
-
} catch (error) {
|
|
3990
|
-
staged.cleanup();
|
|
3991
|
-
throw error;
|
|
3992
|
-
}
|
|
3993
|
-
}
|
|
3994
3283
|
async function runCheckScanTask(cwd, options, emitProgress) {
|
|
3995
3284
|
await emitProgress("checking drift");
|
|
3996
3285
|
const assessed = await assessLockEntries(options, cwd, {
|
|
@@ -4017,20 +3306,11 @@ async function runUpdateAssessTask(cwd, options, emitProgress) {
|
|
|
4017
3306
|
assessments: serializeAssessments(assessed.assessments)
|
|
4018
3307
|
};
|
|
4019
3308
|
}
|
|
4020
|
-
async function runPluginUpdateAssessTask(cwd, options, emitProgress) {
|
|
4021
|
-
await emitProgress("assessing drift");
|
|
4022
|
-
const assessed = await assessPluginLockEntries(options, cwd, {
|
|
4023
|
-
keepResolved: false
|
|
4024
|
-
});
|
|
4025
|
-
return {
|
|
4026
|
-
assessments: serializeAssessments(assessed.assessments)
|
|
4027
|
-
};
|
|
4028
|
-
}
|
|
4029
3309
|
function createBackupDir(skillName, sourceDir) {
|
|
4030
|
-
const backupRoot =
|
|
4031
|
-
const backupDir =
|
|
4032
|
-
|
|
4033
|
-
|
|
3310
|
+
const backupRoot = fs13.mkdtempSync(path14.join(os7.tmpdir(), "skillspp-update-backup-"));
|
|
3311
|
+
const backupDir = path14.join(backupRoot, skillName);
|
|
3312
|
+
fs13.mkdirSync(backupDir, { recursive: true });
|
|
3313
|
+
fs13.cpSync(sourceDir, backupDir, { recursive: true, force: true });
|
|
4034
3314
|
return backupDir;
|
|
4035
3315
|
}
|
|
4036
3316
|
async function applyEntryUpdate(assessment, options, cwd) {
|
|
@@ -4090,70 +3370,7 @@ async function applyEntryUpdate(assessment, options, cwd) {
|
|
|
4090
3370
|
});
|
|
4091
3371
|
throw error;
|
|
4092
3372
|
} finally {
|
|
4093
|
-
|
|
4094
|
-
if (resolved.cleanup) {
|
|
4095
|
-
resolved.cleanup();
|
|
4096
|
-
}
|
|
4097
|
-
}
|
|
4098
|
-
}
|
|
4099
|
-
async function applyPluginEntryUpdate(assessment, options, cwd) {
|
|
4100
|
-
const { entry } = assessment;
|
|
4101
|
-
if (!assessment.resolved || !assessment.sourceHash) {
|
|
4102
|
-
throw new Error(`No resolved source available for ${entry.skillName}`);
|
|
4103
|
-
}
|
|
4104
|
-
const resolved = assessment.resolved;
|
|
4105
|
-
const sourceHash = assessment.sourceHash;
|
|
4106
|
-
const backupDir = createBackupDir(entry.skillName, entry.canonicalDir);
|
|
4107
|
-
try {
|
|
4108
|
-
const preparedInstaller = await prepareInstallerArtifacts(resolved.plugin.path, cwd, {
|
|
4109
|
-
sourceType: entry.source.type,
|
|
4110
|
-
policyMode: options.policyMode || "enforce",
|
|
4111
|
-
trustWellKnown: Boolean(options.trustWellKnown)
|
|
4112
|
-
});
|
|
4113
|
-
const outcome = installPlugin(resolved.plugin, entry.agents, {
|
|
4114
|
-
mode: entry.installMode,
|
|
4115
|
-
globalInstall: entry.global,
|
|
4116
|
-
cwd
|
|
4117
|
-
});
|
|
4118
|
-
try {
|
|
4119
|
-
await applyInstallerArtifacts(outcome.canonicalDir, preparedInstaller);
|
|
4120
|
-
} finally {
|
|
4121
|
-
cleanupPreparedInstallerArtifacts(preparedInstaller);
|
|
4122
|
-
}
|
|
4123
|
-
const installedHash = await hashDirectoryAsync(outcome.canonicalDir);
|
|
4124
|
-
return {
|
|
4125
|
-
...entry,
|
|
4126
|
-
source: {
|
|
4127
|
-
...entry.source,
|
|
4128
|
-
canonical: assessment.refreshedSource?.canonical ?? entry.source.canonical,
|
|
4129
|
-
pinnedRef: assessment.refreshedSource?.pinnedRef ?? entry.source.pinnedRef,
|
|
4130
|
-
resolvedPath: assessment.refreshedSource?.resolvedPath ?? entry.source.resolvedPath,
|
|
4131
|
-
isSymlinkSource: assessment.refreshedSource?.isSymlinkSource ?? entry.source.isSymlinkSource,
|
|
4132
|
-
selector: {
|
|
4133
|
-
...entry.source.selector,
|
|
4134
|
-
relativePath: assessment.refreshedSource?.sourcePluginPath ?? entry.source.selector.relativePath,
|
|
4135
|
-
wellKnownSourceUrl: assessment.refreshedSource?.wellKnownSourceUrl ?? entry.source.selector.wellKnownSourceUrl
|
|
4136
|
-
}
|
|
4137
|
-
},
|
|
4138
|
-
sourceHash,
|
|
4139
|
-
installedHash,
|
|
4140
|
-
canonicalDir: outcome.canonicalDir,
|
|
4141
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4142
|
-
};
|
|
4143
|
-
} catch (error) {
|
|
4144
|
-
const rollbackPlugin = {
|
|
4145
|
-
name: entry.skillName,
|
|
4146
|
-
description: `Rollback for ${entry.skillName}`,
|
|
4147
|
-
path: backupDir
|
|
4148
|
-
};
|
|
4149
|
-
installPlugin(rollbackPlugin, entry.agents, {
|
|
4150
|
-
mode: entry.installMode,
|
|
4151
|
-
globalInstall: entry.global,
|
|
4152
|
-
cwd
|
|
4153
|
-
});
|
|
4154
|
-
throw error;
|
|
4155
|
-
} finally {
|
|
4156
|
-
fs15.rmSync(path16.dirname(backupDir), { recursive: true, force: true });
|
|
3373
|
+
fs13.rmSync(path14.dirname(backupDir), { recursive: true, force: true });
|
|
4157
3374
|
if (resolved.cleanup) {
|
|
4158
3375
|
resolved.cleanup();
|
|
4159
3376
|
}
|
|
@@ -4164,61 +3381,8 @@ async function runUpdateApplyTask(payload, emitProgress) {
|
|
|
4164
3381
|
...payload.options,
|
|
4165
3382
|
skill: payload.selectedSkillNames
|
|
4166
3383
|
};
|
|
4167
|
-
await emitProgress("assessing selected skills");
|
|
4168
|
-
const assessed = await assessLockEntries(selectedOptions, payload.cwd, {
|
|
4169
|
-
keepResolved: true
|
|
4170
|
-
});
|
|
4171
|
-
const candidateAssessments = assessed.assessments.filter(
|
|
4172
|
-
(assessment) => !assessment.drift.some((item) => item.kind === "migrate-required") && assessment.drift.some(
|
|
4173
|
-
(item) => item.kind === "changed-source" || item.kind === "local-modified"
|
|
4174
|
-
)
|
|
4175
|
-
);
|
|
4176
|
-
let nextLock = readLockfile(Boolean(payload.options.global), payload.cwd);
|
|
4177
|
-
const updatedEntries = [];
|
|
4178
|
-
const ordered = [...candidateAssessments].sort(
|
|
4179
|
-
(a, b) => a.entry.skillName.localeCompare(b.entry.skillName)
|
|
4180
|
-
);
|
|
4181
|
-
try {
|
|
4182
|
-
for (const assessment of ordered) {
|
|
4183
|
-
await emitProgress(`updating ${assessment.entry.skillName}`);
|
|
4184
|
-
const updated = await applyEntryUpdate(assessment, payload.options, payload.cwd);
|
|
4185
|
-
updatedEntries.push(updated);
|
|
4186
|
-
nextLock = upsertLockEntry(nextLock, updated);
|
|
4187
|
-
}
|
|
4188
|
-
await emitProgress("writing lockfile");
|
|
4189
|
-
writeLockfile(Boolean(payload.options.global), payload.cwd, nextLock, payload.lockFormat);
|
|
4190
|
-
for (const updated of updatedEntries) {
|
|
4191
|
-
const targetDirs = Array.from(
|
|
4192
|
-
new Set(
|
|
4193
|
-
updated.agents.map(
|
|
4194
|
-
(agent) => path16.join(getAgentSkillsDir(agent, updated.global, payload.cwd), updated.skillName)
|
|
4195
|
-
)
|
|
4196
|
-
)
|
|
4197
|
-
);
|
|
4198
|
-
propagateLockfileVisibility({
|
|
4199
|
-
canonicalDir: updated.canonicalDir,
|
|
4200
|
-
targetDirs,
|
|
4201
|
-
lockFormat: payload.lockFormat
|
|
4202
|
-
});
|
|
4203
|
-
}
|
|
4204
|
-
return {
|
|
4205
|
-
updatedSkillNames: ordered.map((assessment) => assessment.entry.skillName)
|
|
4206
|
-
};
|
|
4207
|
-
} finally {
|
|
4208
|
-
for (const assessment of assessed.assessments) {
|
|
4209
|
-
if (assessment.resolved?.cleanup) {
|
|
4210
|
-
assessment.resolved.cleanup();
|
|
4211
|
-
}
|
|
4212
|
-
}
|
|
4213
|
-
}
|
|
4214
|
-
}
|
|
4215
|
-
async function runPluginUpdateApplyTask(payload, emitProgress) {
|
|
4216
|
-
const selectedOptions = {
|
|
4217
|
-
...payload.options,
|
|
4218
|
-
skill: payload.selectedPluginNames
|
|
4219
|
-
};
|
|
4220
|
-
await emitProgress("assessing selected plugins");
|
|
4221
|
-
const assessed = await assessPluginLockEntries(selectedOptions, payload.cwd, {
|
|
3384
|
+
await emitProgress("assessing selected skills");
|
|
3385
|
+
const assessed = await assessLockEntries(selectedOptions, payload.cwd, {
|
|
4222
3386
|
keepResolved: true
|
|
4223
3387
|
});
|
|
4224
3388
|
const candidateAssessments = assessed.assessments.filter(
|
|
@@ -4226,7 +3390,7 @@ async function runPluginUpdateApplyTask(payload, emitProgress) {
|
|
|
4226
3390
|
(item) => item.kind === "changed-source" || item.kind === "local-modified"
|
|
4227
3391
|
)
|
|
4228
3392
|
);
|
|
4229
|
-
let nextLock =
|
|
3393
|
+
let nextLock = readLockfile(Boolean(payload.options.global), payload.cwd);
|
|
4230
3394
|
const updatedEntries = [];
|
|
4231
3395
|
const ordered = [...candidateAssessments].sort(
|
|
4232
3396
|
(a, b) => a.entry.skillName.localeCompare(b.entry.skillName)
|
|
@@ -4234,23 +3398,17 @@ async function runPluginUpdateApplyTask(payload, emitProgress) {
|
|
|
4234
3398
|
try {
|
|
4235
3399
|
for (const assessment of ordered) {
|
|
4236
3400
|
await emitProgress(`updating ${assessment.entry.skillName}`);
|
|
4237
|
-
const updated = await
|
|
3401
|
+
const updated = await applyEntryUpdate(assessment, payload.options, payload.cwd);
|
|
4238
3402
|
updatedEntries.push(updated);
|
|
4239
|
-
nextLock =
|
|
3403
|
+
nextLock = upsertLockEntry(nextLock, updated);
|
|
4240
3404
|
}
|
|
4241
3405
|
await emitProgress("writing lockfile");
|
|
4242
|
-
|
|
4243
|
-
"plugin",
|
|
4244
|
-
Boolean(payload.options.global),
|
|
4245
|
-
payload.cwd,
|
|
4246
|
-
nextLock,
|
|
4247
|
-
payload.lockFormat
|
|
4248
|
-
);
|
|
3406
|
+
writeLockfile(Boolean(payload.options.global), payload.cwd, nextLock, payload.lockFormat);
|
|
4249
3407
|
for (const updated of updatedEntries) {
|
|
4250
3408
|
const targetDirs = Array.from(
|
|
4251
3409
|
new Set(
|
|
4252
3410
|
updated.agents.map(
|
|
4253
|
-
(agent) =>
|
|
3411
|
+
(agent) => path14.join(getAgentSkillsDir(agent, updated.global, payload.cwd), updated.skillName)
|
|
4254
3412
|
)
|
|
4255
3413
|
)
|
|
4256
3414
|
);
|
|
@@ -4261,7 +3419,7 @@ async function runPluginUpdateApplyTask(payload, emitProgress) {
|
|
|
4261
3419
|
});
|
|
4262
3420
|
}
|
|
4263
3421
|
return {
|
|
4264
|
-
|
|
3422
|
+
updatedSkillNames: ordered.map((assessment) => assessment.entry.skillName)
|
|
4265
3423
|
};
|
|
4266
3424
|
} finally {
|
|
4267
3425
|
for (const assessment of assessed.assessments) {
|
|
@@ -4311,67 +3469,12 @@ async function resolveMigrationSource(options) {
|
|
|
4311
3469
|
return {
|
|
4312
3470
|
parsedSource,
|
|
4313
3471
|
skill,
|
|
4314
|
-
sourceSkillPath:
|
|
4315
|
-
sourceHash,
|
|
4316
|
-
sourceCanonical: canonicalSourceIdentity({ parsedSource }),
|
|
4317
|
-
sourcePinnedRef,
|
|
4318
|
-
sourceResolvedPath: parsedSource.type === "local" ? resolveSafeRealPath3(skill.path) : void 0,
|
|
4319
|
-
sourceIsSymlink: parsedSource.type === "local" ? isLocalSymlinkSource3(parsedSource.localPath) : void 0,
|
|
4320
|
-
cleanup: prepared.cleanup
|
|
4321
|
-
};
|
|
4322
|
-
} catch (error) {
|
|
4323
|
-
if (prepared.cleanup) {
|
|
4324
|
-
prepared.cleanup();
|
|
4325
|
-
}
|
|
4326
|
-
throw error;
|
|
4327
|
-
}
|
|
4328
|
-
}
|
|
4329
|
-
async function resolvePluginMigrationSource(options) {
|
|
4330
|
-
const parsedSource = parseSource(options.sourceInput);
|
|
4331
|
-
if (parsedSource.type === "well-known" || parsedSource.type === "catalog") {
|
|
4332
|
-
const remotePlugins = parsedSource.type === "well-known" ? await resolveWellKnownPlugins(parsedSource.url, options.addOptions) : await resolveCatalogPlugins(parsedSource.url, options.addOptions);
|
|
4333
|
-
const remote = remotePlugins.find((item) => item.installName === options.pluginName);
|
|
4334
|
-
if (!remote) {
|
|
4335
|
-
throw new Error(`Plugin '${options.pluginName}' not found in migration source`);
|
|
4336
|
-
}
|
|
4337
|
-
const staged = await buildRemotePlugin(remote);
|
|
4338
|
-
const sourceHash = hashDirectory(staged.plugin.path);
|
|
4339
|
-
return {
|
|
4340
|
-
parsedSource,
|
|
4341
|
-
plugin: staged.plugin,
|
|
4342
|
-
sourceHash,
|
|
4343
|
-
sourceCanonical: canonicalSourceIdentity({
|
|
4344
|
-
parsedSource,
|
|
4345
|
-
wellKnownSourceUrl: remote.sourceUrl
|
|
4346
|
-
}),
|
|
4347
|
-
sourcePinnedRef: sourceHash,
|
|
4348
|
-
wellKnownSourceUrl: remote.sourceUrl,
|
|
4349
|
-
cleanup: staged.cleanup
|
|
4350
|
-
};
|
|
4351
|
-
}
|
|
4352
|
-
const prepared = await prepareSourceDirAsync(
|
|
4353
|
-
parsedSource
|
|
4354
|
-
);
|
|
4355
|
-
try {
|
|
4356
|
-
const plugins = await discoverPluginsAsync(prepared.basePath, [options.pluginName]);
|
|
4357
|
-
const plugin = plugins.find((item) => item.name === options.pluginName);
|
|
4358
|
-
if (!plugin) {
|
|
4359
|
-
throw new Error(`Plugin '${options.pluginName}' not found in migration source`);
|
|
4360
|
-
}
|
|
4361
|
-
const sourceHash = sourceHashForInstalledSkill({
|
|
4362
|
-
parsedSource,
|
|
4363
|
-
skillPath: plugin.path
|
|
4364
|
-
});
|
|
4365
|
-
const sourcePinnedRef = parsedSource.type === "github" || parsedSource.type === "git" ? await resolveGitHeadRefAsync(prepared.basePath) : void 0;
|
|
4366
|
-
return {
|
|
4367
|
-
parsedSource,
|
|
4368
|
-
plugin,
|
|
4369
|
-
sourcePluginPath: path16.relative(prepared.basePath, plugin.path) || ".",
|
|
3472
|
+
sourceSkillPath: path14.relative(prepared.basePath, skill.path) || ".",
|
|
4370
3473
|
sourceHash,
|
|
4371
3474
|
sourceCanonical: canonicalSourceIdentity({ parsedSource }),
|
|
4372
3475
|
sourcePinnedRef,
|
|
4373
|
-
sourceResolvedPath: parsedSource.type === "local" ?
|
|
4374
|
-
sourceIsSymlink: parsedSource.type === "local" ?
|
|
3476
|
+
sourceResolvedPath: parsedSource.type === "local" ? resolveSafeRealPath2(skill.path) : void 0,
|
|
3477
|
+
sourceIsSymlink: parsedSource.type === "local" ? isLocalSymlinkSource2(parsedSource.localPath) : void 0,
|
|
4375
3478
|
cleanup: prepared.cleanup
|
|
4376
3479
|
};
|
|
4377
3480
|
} catch (error) {
|
|
@@ -4442,82 +3545,13 @@ async function runUpdateMigrateTask(payload, emitProgress) {
|
|
|
4442
3545
|
});
|
|
4443
3546
|
throw error;
|
|
4444
3547
|
} finally {
|
|
4445
|
-
|
|
3548
|
+
fs13.rmSync(path14.dirname(backupDir), { recursive: true, force: true });
|
|
4446
3549
|
if (source.cleanup) {
|
|
4447
3550
|
source.cleanup();
|
|
4448
3551
|
}
|
|
4449
3552
|
}
|
|
4450
3553
|
return { skillName: entry.skillName };
|
|
4451
3554
|
}
|
|
4452
|
-
async function runPluginUpdateMigrateTask(payload, emitProgress) {
|
|
4453
|
-
await emitProgress("resolving migration source");
|
|
4454
|
-
const lock = readResourceLockfile("plugin", Boolean(payload.options.global), payload.cwd);
|
|
4455
|
-
const entry = lock.entries.find((item) => item.skillName === payload.pluginName);
|
|
4456
|
-
if (!entry) {
|
|
4457
|
-
throw new Error(`Unknown plugin for migration: ${payload.pluginName}`);
|
|
4458
|
-
}
|
|
4459
|
-
const source = await resolvePluginMigrationSource({
|
|
4460
|
-
sourceInput: payload.sourceInput,
|
|
4461
|
-
pluginName: payload.pluginName,
|
|
4462
|
-
addOptions: payload.options
|
|
4463
|
-
});
|
|
4464
|
-
const backupDir = createBackupDir(entry.skillName, entry.canonicalDir);
|
|
4465
|
-
try {
|
|
4466
|
-
await emitProgress(`migrating ${entry.skillName}`);
|
|
4467
|
-
const preparedInstaller = await prepareInstallerArtifacts(source.plugin.path, payload.cwd, {
|
|
4468
|
-
sourceType: source.parsedSource.type,
|
|
4469
|
-
policyMode: payload.options.policyMode || "enforce",
|
|
4470
|
-
trustWellKnown: Boolean(payload.options.trustWellKnown)
|
|
4471
|
-
});
|
|
4472
|
-
const outcome = installPlugin(source.plugin, entry.agents, {
|
|
4473
|
-
mode: entry.installMode,
|
|
4474
|
-
globalInstall: entry.global,
|
|
4475
|
-
cwd: payload.cwd
|
|
4476
|
-
});
|
|
4477
|
-
try {
|
|
4478
|
-
await applyInstallerArtifacts(outcome.canonicalDir, preparedInstaller);
|
|
4479
|
-
await emitProgress("writing lockfile");
|
|
4480
|
-
writeLockEntryAfterInstall({
|
|
4481
|
-
resourceKind: "plugin",
|
|
4482
|
-
globalInstall: entry.global,
|
|
4483
|
-
cwd: payload.cwd,
|
|
4484
|
-
sourceInput: payload.sourceInput,
|
|
4485
|
-
sourceType: source.parsedSource.type,
|
|
4486
|
-
sourceCanonical: source.sourceCanonical,
|
|
4487
|
-
sourcePinnedRef: source.sourcePinnedRef,
|
|
4488
|
-
sourceResolvedPath: source.sourceResolvedPath,
|
|
4489
|
-
sourceIsSymlink: source.sourceIsSymlink,
|
|
4490
|
-
sourceSkillName: source.plugin.name,
|
|
4491
|
-
sourceSkillPath: source.sourcePluginPath,
|
|
4492
|
-
wellKnownSourceUrl: source.wellKnownSourceUrl,
|
|
4493
|
-
sourceHash: source.sourceHash,
|
|
4494
|
-
outcome,
|
|
4495
|
-
mode: entry.installMode,
|
|
4496
|
-
lockFormat: payload.lockFormat
|
|
4497
|
-
});
|
|
4498
|
-
} finally {
|
|
4499
|
-
cleanupPreparedInstallerArtifacts(preparedInstaller);
|
|
4500
|
-
}
|
|
4501
|
-
} catch (error) {
|
|
4502
|
-
const rollbackPlugin = {
|
|
4503
|
-
name: entry.skillName,
|
|
4504
|
-
description: `Rollback for ${entry.skillName}`,
|
|
4505
|
-
path: backupDir
|
|
4506
|
-
};
|
|
4507
|
-
installPlugin(rollbackPlugin, entry.agents, {
|
|
4508
|
-
mode: entry.installMode,
|
|
4509
|
-
globalInstall: entry.global,
|
|
4510
|
-
cwd: payload.cwd
|
|
4511
|
-
});
|
|
4512
|
-
throw error;
|
|
4513
|
-
} finally {
|
|
4514
|
-
fs15.rmSync(path16.dirname(backupDir), { recursive: true, force: true });
|
|
4515
|
-
if (source.cleanup) {
|
|
4516
|
-
source.cleanup();
|
|
4517
|
-
}
|
|
4518
|
-
}
|
|
4519
|
-
return { pluginName: entry.skillName };
|
|
4520
|
-
}
|
|
4521
3555
|
async function runListDetectAgentsTask(cwd, options, emitProgress) {
|
|
4522
3556
|
await emitProgress("detecting installed agents");
|
|
4523
3557
|
const agents = options.agent ? filterInstalledAgents(resolveAgents(options.agent), cwd) : detectInstalledAgents(cwd);
|
|
@@ -4528,17 +3562,17 @@ async function runListScanInventoryTask(payload, emitProgress) {
|
|
|
4528
3562
|
for (const agent of payload.agents) {
|
|
4529
3563
|
await emitProgress(`scanning installed skills (${AGENTS[agent].displayName})`);
|
|
4530
3564
|
const dir = getAgentSkillsDir(agent, payload.globalInstall, payload.cwd);
|
|
4531
|
-
if (!
|
|
3565
|
+
if (!fs13.existsSync(dir) || !fs13.statSync(dir).isDirectory()) {
|
|
4532
3566
|
continue;
|
|
4533
3567
|
}
|
|
4534
|
-
for (const entry of
|
|
3568
|
+
for (const entry of fs13.readdirSync(dir, { withFileTypes: true })) {
|
|
4535
3569
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
4536
3570
|
continue;
|
|
4537
3571
|
}
|
|
4538
|
-
const fullPath =
|
|
3572
|
+
const fullPath = path14.join(dir, entry.name);
|
|
4539
3573
|
let resolvedPath = fullPath;
|
|
4540
3574
|
try {
|
|
4541
|
-
resolvedPath =
|
|
3575
|
+
resolvedPath = fs13.realpathSync(fullPath);
|
|
4542
3576
|
} catch {
|
|
4543
3577
|
resolvedPath = fullPath;
|
|
4544
3578
|
}
|
|
@@ -4595,56 +3629,6 @@ async function resolveAddSourceSkills(sourceInput, options, emitProgress) {
|
|
|
4595
3629
|
}
|
|
4596
3630
|
}
|
|
4597
3631
|
}
|
|
4598
|
-
async function resolveAddSourcePlugins(sourceInput, options, emitProgress) {
|
|
4599
|
-
const parsed = parseSource(sourceInput);
|
|
4600
|
-
const requestedPlugins = options.skill;
|
|
4601
|
-
if (parsed.type === "well-known" || parsed.type === "catalog") {
|
|
4602
|
-
await emitProgress("fetching plugin index");
|
|
4603
|
-
const remotePlugins = parsed.type === "well-known" ? await resolveWellKnownPlugins(parsed.url, options) : await resolveCatalogPlugins(parsed.url, options);
|
|
4604
|
-
if (remotePlugins.length === 0) {
|
|
4605
|
-
throw new Error("No plugins found at remote endpoint");
|
|
4606
|
-
}
|
|
4607
|
-
const selectedRemotePlugins = requestedPlugins && !requestedPlugins.includes("*") ? remotePlugins.filter((remote) => requestedPlugins.includes(remote.installName)) : remotePlugins;
|
|
4608
|
-
const discoveredPlugins = [];
|
|
4609
|
-
for (const remote of selectedRemotePlugins) {
|
|
4610
|
-
const staged = await buildRemotePlugin(remote);
|
|
4611
|
-
try {
|
|
4612
|
-
discoveredPlugins.push(staged.plugin);
|
|
4613
|
-
} finally {
|
|
4614
|
-
staged.cleanup();
|
|
4615
|
-
}
|
|
4616
|
-
}
|
|
4617
|
-
if (discoveredPlugins.length === 0) {
|
|
4618
|
-
throw new Error("No plugins found in source");
|
|
4619
|
-
}
|
|
4620
|
-
return {
|
|
4621
|
-
plugins: discoveredPlugins.map((plugin) => ({
|
|
4622
|
-
name: plugin.name,
|
|
4623
|
-
description: plugin.description
|
|
4624
|
-
}))
|
|
4625
|
-
};
|
|
4626
|
-
}
|
|
4627
|
-
await emitProgress("loading source");
|
|
4628
|
-
const prepared = await prepareSourceDirAsync(
|
|
4629
|
-
parsed
|
|
4630
|
-
);
|
|
4631
|
-
try {
|
|
4632
|
-
const plugins = await discoverPluginsAsync(prepared.basePath, requestedPlugins);
|
|
4633
|
-
if (plugins.length === 0) {
|
|
4634
|
-
throw new Error("No plugins found in source");
|
|
4635
|
-
}
|
|
4636
|
-
return {
|
|
4637
|
-
plugins: plugins.map((plugin) => ({
|
|
4638
|
-
name: plugin.name,
|
|
4639
|
-
description: plugin.description
|
|
4640
|
-
}))
|
|
4641
|
-
};
|
|
4642
|
-
} finally {
|
|
4643
|
-
if (prepared.cleanup) {
|
|
4644
|
-
prepared.cleanup();
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4647
|
-
}
|
|
4648
3632
|
async function installSelectedAddSkills(payload, emitProgress) {
|
|
4649
3633
|
const parsedSource = parseSource(payload.sourceInput);
|
|
4650
3634
|
const globalInstall = resolveAddGlobalInstall(payload.options);
|
|
@@ -4703,7 +3687,6 @@ async function installSelectedAddSkills(payload, emitProgress) {
|
|
|
4703
3687
|
try {
|
|
4704
3688
|
await applyInstallerArtifacts(outcome.canonicalDir, preparedInstaller);
|
|
4705
3689
|
writeLockEntryAfterInstall({
|
|
4706
|
-
resourceKind: "plugin",
|
|
4707
3690
|
globalInstall,
|
|
4708
3691
|
cwd: payload.cwd,
|
|
4709
3692
|
sourceInput: payload.sourceInput,
|
|
@@ -4738,7 +3721,7 @@ async function installSelectedAddSkills(payload, emitProgress) {
|
|
|
4738
3721
|
try {
|
|
4739
3722
|
const sourceCanonical = canonicalSourceIdentity({ parsedSource });
|
|
4740
3723
|
const sourcePinnedRef = parsedSource.type === "github" || parsedSource.type === "git" ? await resolveGitHeadRefAsync(prepared.basePath) : void 0;
|
|
4741
|
-
const sourceIsSymlink = parsedSource.type === "local" ?
|
|
3724
|
+
const sourceIsSymlink = parsedSource.type === "local" ? isLocalSymlinkSource2(parsedSource.localPath) : void 0;
|
|
4742
3725
|
const skills = await discoverSkillsAsync(prepared.basePath);
|
|
4743
3726
|
const selected = skills.filter((skill) => payload.selectedSkillNames.includes(skill.name));
|
|
4744
3727
|
if (selected.length === 0) {
|
|
@@ -4758,9 +3741,9 @@ async function installSelectedAddSkills(payload, emitProgress) {
|
|
|
4758
3741
|
scaffoldInstallerConfigForSkills(missingInstallerSkillDirs, scaffoldFormat);
|
|
4759
3742
|
}
|
|
4760
3743
|
for (const skill of selected) {
|
|
4761
|
-
const sourceResolvedPath = parsedSource.type === "local" ?
|
|
3744
|
+
const sourceResolvedPath = parsedSource.type === "local" ? resolveSafeRealPath2(skill.path) : void 0;
|
|
4762
3745
|
await emitProgress(`installing ${skill.name}`);
|
|
4763
|
-
const sourceSkillPath =
|
|
3746
|
+
const sourceSkillPath = path14.relative(prepared.basePath, skill.path) || ".";
|
|
4764
3747
|
const preparedInstaller = await prepareInstallerArtifacts(skill.path, payload.cwd, {
|
|
4765
3748
|
sourceType: parsedSource.type,
|
|
4766
3749
|
policyMode: payload.options.policyMode || "enforce",
|
|
@@ -4774,7 +3757,6 @@ async function installSelectedAddSkills(payload, emitProgress) {
|
|
|
4774
3757
|
try {
|
|
4775
3758
|
await applyInstallerArtifacts(outcome.canonicalDir, preparedInstaller);
|
|
4776
3759
|
writeLockEntryAfterInstall({
|
|
4777
|
-
resourceKind: "plugin",
|
|
4778
3760
|
globalInstall,
|
|
4779
3761
|
cwd: payload.cwd,
|
|
4780
3762
|
sourceInput: payload.sourceInput,
|
|
@@ -4808,166 +3790,6 @@ async function installSelectedAddSkills(payload, emitProgress) {
|
|
|
4808
3790
|
}
|
|
4809
3791
|
}
|
|
4810
3792
|
}
|
|
4811
|
-
async function installSelectedAddPlugins(payload, emitProgress) {
|
|
4812
|
-
const parsedSource = parseSource(payload.sourceInput);
|
|
4813
|
-
const globalInstall = resolveAddGlobalInstall(payload.options);
|
|
4814
|
-
const mode = resolveAddInstallMode(payload.options);
|
|
4815
|
-
if (parsedSource.type === "well-known" || parsedSource.type === "catalog") {
|
|
4816
|
-
await emitProgress("fetching selected plugins");
|
|
4817
|
-
const remotePlugins = parsedSource.type === "well-known" ? await resolveWellKnownPlugins(parsedSource.url, payload.options) : await resolveCatalogPlugins(parsedSource.url, payload.options);
|
|
4818
|
-
const remoteByName = new Map(remotePlugins.map((remote) => [remote.installName, remote]));
|
|
4819
|
-
const tempCleanups = [];
|
|
4820
|
-
const stagedSelected = [];
|
|
4821
|
-
const sourceHashesBefore = /* @__PURE__ */ new Map();
|
|
4822
|
-
try {
|
|
4823
|
-
for (const pluginName of payload.selectedPluginNames) {
|
|
4824
|
-
const remote = remoteByName.get(pluginName);
|
|
4825
|
-
if (!remote) {
|
|
4826
|
-
throw new Error("No matching plugins found in source");
|
|
4827
|
-
}
|
|
4828
|
-
const staged = await buildRemotePlugin(remote);
|
|
4829
|
-
tempCleanups.push(staged.cleanup);
|
|
4830
|
-
stagedSelected.push(staged.plugin);
|
|
4831
|
-
sourceHashesBefore.set(staged.plugin.path, hashDirectory(staged.plugin.path));
|
|
4832
|
-
}
|
|
4833
|
-
const missingInstallerPluginDirs = listSkillsMissingInstallerConfig(
|
|
4834
|
-
stagedSelected.map((item) => item.path)
|
|
4835
|
-
);
|
|
4836
|
-
const scaffoldFormat = resolveAddInstallerScaffoldFormat(
|
|
4837
|
-
payload.options,
|
|
4838
|
-
missingInstallerPluginDirs.length
|
|
4839
|
-
);
|
|
4840
|
-
if (scaffoldFormat) {
|
|
4841
|
-
scaffoldInstallerConfigForSkills(missingInstallerPluginDirs, scaffoldFormat);
|
|
4842
|
-
}
|
|
4843
|
-
for (const localPlugin of stagedSelected) {
|
|
4844
|
-
const remote = remoteByName.get(localPlugin.name);
|
|
4845
|
-
if (!remote) {
|
|
4846
|
-
throw new Error(
|
|
4847
|
-
`Could not resolve remote metadata for selected plugin '${localPlugin.name}'`
|
|
4848
|
-
);
|
|
4849
|
-
}
|
|
4850
|
-
const sourceHash = sourceHashesBefore.get(localPlugin.path) || hashDirectory(localPlugin.path);
|
|
4851
|
-
const sourceCanonical = canonicalSourceIdentity({
|
|
4852
|
-
parsedSource,
|
|
4853
|
-
wellKnownSourceUrl: remote.sourceUrl
|
|
4854
|
-
});
|
|
4855
|
-
await emitProgress(`installing ${localPlugin.name}`);
|
|
4856
|
-
const preparedInstaller = await prepareInstallerArtifacts(localPlugin.path, payload.cwd, {
|
|
4857
|
-
sourceType: parsedSource.type,
|
|
4858
|
-
policyMode: payload.options.policyMode || "enforce",
|
|
4859
|
-
trustWellKnown: Boolean(payload.options.trustWellKnown)
|
|
4860
|
-
});
|
|
4861
|
-
const outcome = installPlugin(localPlugin, payload.agents, {
|
|
4862
|
-
mode,
|
|
4863
|
-
globalInstall,
|
|
4864
|
-
cwd: payload.cwd
|
|
4865
|
-
});
|
|
4866
|
-
try {
|
|
4867
|
-
await applyInstallerArtifacts(outcome.canonicalDir, preparedInstaller);
|
|
4868
|
-
writeLockEntryAfterInstall({
|
|
4869
|
-
globalInstall,
|
|
4870
|
-
cwd: payload.cwd,
|
|
4871
|
-
sourceInput: payload.sourceInput,
|
|
4872
|
-
sourceType: parsedSource.type,
|
|
4873
|
-
sourceCanonical,
|
|
4874
|
-
sourcePinnedRef: sourceHash,
|
|
4875
|
-
sourceSkillName: remote.installName,
|
|
4876
|
-
sourceHash,
|
|
4877
|
-
wellKnownSourceUrl: remote.sourceUrl,
|
|
4878
|
-
outcome,
|
|
4879
|
-
mode,
|
|
4880
|
-
lockFormat: payload.options.lockFormat
|
|
4881
|
-
});
|
|
4882
|
-
} finally {
|
|
4883
|
-
cleanupPreparedInstallerArtifacts(preparedInstaller);
|
|
4884
|
-
}
|
|
4885
|
-
}
|
|
4886
|
-
} finally {
|
|
4887
|
-
for (const cleanup of tempCleanups) {
|
|
4888
|
-
cleanup();
|
|
4889
|
-
}
|
|
4890
|
-
}
|
|
4891
|
-
return {
|
|
4892
|
-
installedPluginNames: [...payload.selectedPluginNames],
|
|
4893
|
-
agentCount: payload.agents.length
|
|
4894
|
-
};
|
|
4895
|
-
}
|
|
4896
|
-
await emitProgress("loading source");
|
|
4897
|
-
const prepared = await prepareSourceDirAsync(
|
|
4898
|
-
parsedSource
|
|
4899
|
-
);
|
|
4900
|
-
try {
|
|
4901
|
-
const sourceCanonical = canonicalSourceIdentity({ parsedSource });
|
|
4902
|
-
const sourcePinnedRef = parsedSource.type === "github" || parsedSource.type === "git" ? await resolveGitHeadRefAsync(prepared.basePath) : void 0;
|
|
4903
|
-
const sourceIsSymlink = parsedSource.type === "local" ? isLocalSymlinkSource3(parsedSource.localPath) : void 0;
|
|
4904
|
-
const selected = await discoverPluginsAsync(prepared.basePath, payload.selectedPluginNames);
|
|
4905
|
-
if (selected.length === 0) {
|
|
4906
|
-
throw new Error("No matching plugins found in source");
|
|
4907
|
-
}
|
|
4908
|
-
const sourceHashesBefore = new Map(
|
|
4909
|
-
selected.map((plugin) => [plugin.path, hashDirectory(plugin.path)])
|
|
4910
|
-
);
|
|
4911
|
-
const missingInstallerPluginDirs = listSkillsMissingInstallerConfig(
|
|
4912
|
-
selected.map((plugin) => plugin.path)
|
|
4913
|
-
);
|
|
4914
|
-
const scaffoldFormat = resolveAddInstallerScaffoldFormat(
|
|
4915
|
-
payload.options,
|
|
4916
|
-
missingInstallerPluginDirs.length
|
|
4917
|
-
);
|
|
4918
|
-
if (scaffoldFormat) {
|
|
4919
|
-
scaffoldInstallerConfigForSkills(missingInstallerPluginDirs, scaffoldFormat);
|
|
4920
|
-
}
|
|
4921
|
-
for (const plugin of selected) {
|
|
4922
|
-
const sourceResolvedPath = parsedSource.type === "local" ? resolveSafeRealPath3(plugin.path) : void 0;
|
|
4923
|
-
await emitProgress(`installing ${plugin.name}`);
|
|
4924
|
-
const sourceSkillPath = path16.relative(prepared.basePath, plugin.path) || ".";
|
|
4925
|
-
const preparedInstaller = await prepareInstallerArtifacts(plugin.path, payload.cwd, {
|
|
4926
|
-
sourceType: parsedSource.type,
|
|
4927
|
-
policyMode: payload.options.policyMode || "enforce",
|
|
4928
|
-
trustWellKnown: Boolean(payload.options.trustWellKnown)
|
|
4929
|
-
});
|
|
4930
|
-
const outcome = installPlugin(plugin, payload.agents, {
|
|
4931
|
-
mode,
|
|
4932
|
-
globalInstall,
|
|
4933
|
-
cwd: payload.cwd
|
|
4934
|
-
});
|
|
4935
|
-
try {
|
|
4936
|
-
await applyInstallerArtifacts(outcome.canonicalDir, preparedInstaller);
|
|
4937
|
-
writeLockEntryAfterInstall({
|
|
4938
|
-
globalInstall,
|
|
4939
|
-
cwd: payload.cwd,
|
|
4940
|
-
sourceInput: payload.sourceInput,
|
|
4941
|
-
sourceType: parsedSource.type,
|
|
4942
|
-
sourceCanonical,
|
|
4943
|
-
sourcePinnedRef,
|
|
4944
|
-
sourceResolvedPath,
|
|
4945
|
-
sourceIsSymlink,
|
|
4946
|
-
sourceSkillName: plugin.name,
|
|
4947
|
-
sourceSkillPath,
|
|
4948
|
-
sourceHash: sourceHashForInstalledSkill({
|
|
4949
|
-
parsedSource,
|
|
4950
|
-
skillPath: plugin.path,
|
|
4951
|
-
beforeHash: sourceHashesBefore.get(plugin.path)
|
|
4952
|
-
}),
|
|
4953
|
-
outcome,
|
|
4954
|
-
mode,
|
|
4955
|
-
lockFormat: payload.options.lockFormat
|
|
4956
|
-
});
|
|
4957
|
-
} finally {
|
|
4958
|
-
cleanupPreparedInstallerArtifacts(preparedInstaller);
|
|
4959
|
-
}
|
|
4960
|
-
}
|
|
4961
|
-
return {
|
|
4962
|
-
installedPluginNames: selected.map((plugin) => plugin.name),
|
|
4963
|
-
agentCount: payload.agents.length
|
|
4964
|
-
};
|
|
4965
|
-
} finally {
|
|
4966
|
-
if (prepared.cleanup) {
|
|
4967
|
-
prepared.cleanup();
|
|
4968
|
-
}
|
|
4969
|
-
}
|
|
4970
|
-
}
|
|
4971
3793
|
async function runFindFetchInventoryTask(sourceInput, options, emitProgress) {
|
|
4972
3794
|
await emitProgress("parsing source");
|
|
4973
3795
|
const parsedSource = parseSource(sourceInput);
|
|
@@ -5030,20 +3852,10 @@ async function executeBackgroundTask(request, emitProgress) {
|
|
|
5030
3852
|
return await runCheckScanTask(request.payload.cwd, request.payload.options, emitProgress);
|
|
5031
3853
|
case "update.assess":
|
|
5032
3854
|
return await runUpdateAssessTask(request.payload.cwd, request.payload.options, emitProgress);
|
|
5033
|
-
case "plugin.update.assess":
|
|
5034
|
-
return await runPluginUpdateAssessTask(
|
|
5035
|
-
request.payload.cwd,
|
|
5036
|
-
request.payload.options,
|
|
5037
|
-
emitProgress
|
|
5038
|
-
);
|
|
5039
3855
|
case "update.apply":
|
|
5040
3856
|
return await runUpdateApplyTask(request.payload, emitProgress);
|
|
5041
|
-
case "plugin.update.apply":
|
|
5042
|
-
return await runPluginUpdateApplyTask(request.payload, emitProgress);
|
|
5043
3857
|
case "update.migrate":
|
|
5044
3858
|
return await runUpdateMigrateTask(request.payload, emitProgress);
|
|
5045
|
-
case "plugin.update.migrate":
|
|
5046
|
-
return await runPluginUpdateMigrateTask(request.payload, emitProgress);
|
|
5047
3859
|
case "list.detectAgents":
|
|
5048
3860
|
return await runListDetectAgentsTask(
|
|
5049
3861
|
request.payload.cwd,
|
|
@@ -5060,14 +3872,6 @@ async function executeBackgroundTask(request, emitProgress) {
|
|
|
5060
3872
|
);
|
|
5061
3873
|
case "add.install":
|
|
5062
3874
|
return await installSelectedAddSkills(request.payload, emitProgress);
|
|
5063
|
-
case "plugin.add.fetchOrDiscover":
|
|
5064
|
-
return await resolveAddSourcePlugins(
|
|
5065
|
-
request.payload.sourceInput,
|
|
5066
|
-
request.payload.options,
|
|
5067
|
-
emitProgress
|
|
5068
|
-
);
|
|
5069
|
-
case "plugin.add.install":
|
|
5070
|
-
return await installSelectedAddPlugins(request.payload, emitProgress);
|
|
5071
3875
|
case "find.fetchInventory":
|
|
5072
3876
|
return await runFindFetchInventoryTask(
|
|
5073
3877
|
request.payload.sourceInput,
|