@standardagents/builder 0.11.12 → 0.12.1
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/built-in-routes.js +3498 -498
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/assets/index.css +1 -1
- package/dist/client/index.js +56 -25
- package/dist/client/vendor.js +78 -5
- package/dist/client/vue.js +1 -1
- package/dist/discovery-CpMs68Yx.d.ts +97 -0
- package/dist/index-DkbUJ4MM.d.ts +1043 -0
- package/dist/index.d.ts +205 -999
- package/dist/index.js +4563 -956
- package/dist/index.js.map +1 -1
- package/dist/packing.d.ts +266 -0
- package/dist/packing.js +2202 -0
- package/dist/packing.js.map +1 -0
- package/dist/plugin.js +3477 -608
- package/dist/plugin.js.map +1 -1
- package/dist/test.d.ts +256 -0
- package/dist/test.js +391 -0
- package/dist/test.js.map +1 -0
- package/dist/types-pLkJx8vg.d.ts +306 -0
- package/package.json +25 -4
package/dist/packing.js
ADDED
|
@@ -0,0 +1,2202 @@
|
|
|
1
|
+
import * as fs2 from 'fs';
|
|
2
|
+
import * as path2 from 'path';
|
|
3
|
+
import * as ts from 'typescript';
|
|
4
|
+
import MagicString from 'magic-string';
|
|
5
|
+
|
|
6
|
+
// src/packing/packing-service.ts
|
|
7
|
+
var MetadataService = class {
|
|
8
|
+
metadataDir;
|
|
9
|
+
/**
|
|
10
|
+
* Create a new MetadataService.
|
|
11
|
+
*
|
|
12
|
+
* @param agentsDir - Path to the agents/ directory
|
|
13
|
+
*/
|
|
14
|
+
constructor(agentsDir) {
|
|
15
|
+
this.metadataDir = path2.join(agentsDir, ".standardagent");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Read metadata for an agent.
|
|
19
|
+
*
|
|
20
|
+
* @param agentName - Name of the agent
|
|
21
|
+
* @returns Metadata if found, null otherwise
|
|
22
|
+
*/
|
|
23
|
+
async read(agentName) {
|
|
24
|
+
const filePath = this.getMetadataPath(agentName);
|
|
25
|
+
if (!fs2.existsSync(filePath)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
30
|
+
return JSON.parse(content);
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Write metadata for an agent.
|
|
37
|
+
*
|
|
38
|
+
* @param agentName - Name of the agent
|
|
39
|
+
* @param metadata - Metadata to write
|
|
40
|
+
*/
|
|
41
|
+
async write(agentName, metadata) {
|
|
42
|
+
if (!fs2.existsSync(this.metadataDir)) {
|
|
43
|
+
fs2.mkdirSync(this.metadataDir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
const filePath = this.getMetadataPath(agentName);
|
|
46
|
+
fs2.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Delete metadata for an agent.
|
|
50
|
+
*
|
|
51
|
+
* @param agentName - Name of the agent
|
|
52
|
+
*/
|
|
53
|
+
async delete(agentName) {
|
|
54
|
+
const filePath = this.getMetadataPath(agentName);
|
|
55
|
+
if (fs2.existsSync(filePath)) {
|
|
56
|
+
fs2.unlinkSync(filePath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the next version by incrementing the patch number.
|
|
61
|
+
*
|
|
62
|
+
* @param currentVersion - Current semver version (e.g., "1.0.0")
|
|
63
|
+
* @returns Incremented version (e.g., "1.0.1")
|
|
64
|
+
*/
|
|
65
|
+
getNextVersion(currentVersion) {
|
|
66
|
+
const parts = currentVersion.split(".");
|
|
67
|
+
if (parts.length < 3) {
|
|
68
|
+
return `${currentVersion}.1`;
|
|
69
|
+
}
|
|
70
|
+
const patchPart = parts[2];
|
|
71
|
+
const prereleaseIndex = patchPart.indexOf("-");
|
|
72
|
+
if (prereleaseIndex > -1) {
|
|
73
|
+
const patch2 = parseInt(patchPart.substring(0, prereleaseIndex), 10);
|
|
74
|
+
const prerelease = patchPart.substring(prereleaseIndex);
|
|
75
|
+
return `${parts[0]}.${parts[1]}.${patch2 + 1}${prerelease}`;
|
|
76
|
+
}
|
|
77
|
+
const patch = parseInt(patchPart, 10);
|
|
78
|
+
return `${parts[0]}.${parts[1]}.${patch + 1}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validate a semver version string.
|
|
82
|
+
*
|
|
83
|
+
* @param version - Version string to validate
|
|
84
|
+
* @returns true if valid semver format
|
|
85
|
+
*/
|
|
86
|
+
isValidVersion(version) {
|
|
87
|
+
const semverPattern = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/;
|
|
88
|
+
return semverPattern.test(version);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Validate an npm package name.
|
|
92
|
+
*
|
|
93
|
+
* @param name - Package name to validate
|
|
94
|
+
* @returns Object with valid flag and optional error message
|
|
95
|
+
*/
|
|
96
|
+
validatePackageName(name) {
|
|
97
|
+
if (!name) {
|
|
98
|
+
return { valid: false, error: "Package name is required" };
|
|
99
|
+
}
|
|
100
|
+
if (name.length > 214) {
|
|
101
|
+
return { valid: false, error: "Package name must be 214 characters or less" };
|
|
102
|
+
}
|
|
103
|
+
if (name.startsWith(".") || name.startsWith("_")) {
|
|
104
|
+
return { valid: false, error: "Package name cannot start with . or _" };
|
|
105
|
+
}
|
|
106
|
+
if (name !== name.toLowerCase()) {
|
|
107
|
+
return { valid: false, error: "Package name must be lowercase" };
|
|
108
|
+
}
|
|
109
|
+
const validPattern = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
110
|
+
if (!validPattern.test(name)) {
|
|
111
|
+
return {
|
|
112
|
+
valid: false,
|
|
113
|
+
error: "Package name can only contain lowercase letters, numbers, hyphens, underscores, and dots"
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return { valid: true };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Generate a suggested package name from project ID and agent name.
|
|
120
|
+
*
|
|
121
|
+
* @param projectId - Project identifier (optional)
|
|
122
|
+
* @param agentName - Agent name
|
|
123
|
+
* @returns Suggested npm package name
|
|
124
|
+
*/
|
|
125
|
+
suggestPackageName(projectId, agentName) {
|
|
126
|
+
const normalizedAgent = agentName.toLowerCase().replace(/_/g, "-");
|
|
127
|
+
if (projectId) {
|
|
128
|
+
const normalizedProject = projectId.toLowerCase().replace(/_/g, "-");
|
|
129
|
+
return `standardagent-${normalizedProject}-${normalizedAgent}`;
|
|
130
|
+
}
|
|
131
|
+
return `standardagent-${normalizedAgent}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get the file path for an agent's metadata.
|
|
135
|
+
*/
|
|
136
|
+
getMetadataPath(agentName) {
|
|
137
|
+
return path2.join(this.metadataDir, `${agentName}.json`);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
function extractToolUses(sourceCode) {
|
|
141
|
+
const sourceFile = ts.createSourceFile(
|
|
142
|
+
"tool.ts",
|
|
143
|
+
sourceCode,
|
|
144
|
+
ts.ScriptTarget.ESNext,
|
|
145
|
+
true
|
|
146
|
+
);
|
|
147
|
+
const result = {
|
|
148
|
+
uses: [],
|
|
149
|
+
found: false
|
|
150
|
+
};
|
|
151
|
+
function visit(node) {
|
|
152
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineTool" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
153
|
+
const configObj = node.arguments[0];
|
|
154
|
+
for (const prop of configObj.properties) {
|
|
155
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "uses" && ts.isArrayLiteralExpression(prop.initializer)) {
|
|
156
|
+
result.found = true;
|
|
157
|
+
result.line = sourceFile.getLineAndCharacterOfPosition(prop.getStart()).line + 1;
|
|
158
|
+
for (const element of prop.initializer.elements) {
|
|
159
|
+
if (ts.isStringLiteral(element)) {
|
|
160
|
+
result.uses.push(element.text);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
ts.forEachChild(node, visit);
|
|
167
|
+
}
|
|
168
|
+
visit(sourceFile);
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
function extractPromptTools(sourceCode) {
|
|
172
|
+
const sourceFile = ts.createSourceFile(
|
|
173
|
+
"prompt.ts",
|
|
174
|
+
sourceCode,
|
|
175
|
+
ts.ScriptTarget.ESNext,
|
|
176
|
+
true
|
|
177
|
+
);
|
|
178
|
+
const result = {
|
|
179
|
+
tools: [],
|
|
180
|
+
hasSubpromptConfigs: false
|
|
181
|
+
};
|
|
182
|
+
function visit(node) {
|
|
183
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "definePrompt" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
184
|
+
const configObj = node.arguments[0];
|
|
185
|
+
for (const prop of configObj.properties) {
|
|
186
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "tools" && ts.isArrayLiteralExpression(prop.initializer)) {
|
|
187
|
+
for (const element of prop.initializer.elements) {
|
|
188
|
+
if (ts.isStringLiteral(element)) {
|
|
189
|
+
result.tools.push(element.text);
|
|
190
|
+
} else if (ts.isObjectLiteralExpression(element)) {
|
|
191
|
+
result.hasSubpromptConfigs = true;
|
|
192
|
+
for (const objProp of element.properties) {
|
|
193
|
+
if (ts.isPropertyAssignment(objProp) && ts.isIdentifier(objProp.name) && objProp.name.text === "name" && ts.isStringLiteral(objProp.initializer)) {
|
|
194
|
+
result.tools.push(objProp.initializer.text);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
ts.forEachChild(node, visit);
|
|
203
|
+
}
|
|
204
|
+
visit(sourceFile);
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
function extractPromptModel(sourceCode) {
|
|
208
|
+
const sourceFile = ts.createSourceFile(
|
|
209
|
+
"prompt.ts",
|
|
210
|
+
sourceCode,
|
|
211
|
+
ts.ScriptTarget.ESNext,
|
|
212
|
+
true
|
|
213
|
+
);
|
|
214
|
+
let model = null;
|
|
215
|
+
function visit(node) {
|
|
216
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "definePrompt" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
217
|
+
const configObj = node.arguments[0];
|
|
218
|
+
for (const prop of configObj.properties) {
|
|
219
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "model" && ts.isStringLiteral(prop.initializer)) {
|
|
220
|
+
model = prop.initializer.text;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
ts.forEachChild(node, visit);
|
|
225
|
+
}
|
|
226
|
+
visit(sourceFile);
|
|
227
|
+
return model;
|
|
228
|
+
}
|
|
229
|
+
function extractPromptIncludes(sourceCode) {
|
|
230
|
+
const sourceFile = ts.createSourceFile(
|
|
231
|
+
"prompt.ts",
|
|
232
|
+
sourceCode,
|
|
233
|
+
ts.ScriptTarget.ESNext,
|
|
234
|
+
true
|
|
235
|
+
);
|
|
236
|
+
const includes = [];
|
|
237
|
+
function extractFromStructuredPrompt(arr) {
|
|
238
|
+
for (const element of arr.elements) {
|
|
239
|
+
if (ts.isObjectLiteralExpression(element)) {
|
|
240
|
+
let hasIncludeType = false;
|
|
241
|
+
let includeName = null;
|
|
242
|
+
for (const prop of element.properties) {
|
|
243
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
244
|
+
if (prop.name.text === "type" && ts.isStringLiteral(prop.initializer) && prop.initializer.text === "include") {
|
|
245
|
+
hasIncludeType = true;
|
|
246
|
+
}
|
|
247
|
+
if (prop.name.text === "name" && ts.isStringLiteral(prop.initializer)) {
|
|
248
|
+
includeName = prop.initializer.text;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (hasIncludeType && includeName && !includes.includes(includeName)) {
|
|
253
|
+
includes.push(includeName);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
function visit(node) {
|
|
259
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "definePrompt" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
260
|
+
const configObj = node.arguments[0];
|
|
261
|
+
for (const prop of configObj.properties) {
|
|
262
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
263
|
+
if (prop.name.text === "prompt" && ts.isArrayLiteralExpression(prop.initializer)) {
|
|
264
|
+
extractFromStructuredPrompt(prop.initializer);
|
|
265
|
+
}
|
|
266
|
+
if (prop.name.text === "includes" && ts.isArrayLiteralExpression(prop.initializer)) {
|
|
267
|
+
for (const element of prop.initializer.elements) {
|
|
268
|
+
if (ts.isStringLiteral(element) && !includes.includes(element.text)) {
|
|
269
|
+
includes.push(element.text);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
ts.forEachChild(node, visit);
|
|
277
|
+
}
|
|
278
|
+
visit(sourceFile);
|
|
279
|
+
return includes;
|
|
280
|
+
}
|
|
281
|
+
function extractAgentPrompts(sourceCode) {
|
|
282
|
+
const sourceFile = ts.createSourceFile(
|
|
283
|
+
"agent.ts",
|
|
284
|
+
sourceCode,
|
|
285
|
+
ts.ScriptTarget.ESNext,
|
|
286
|
+
true
|
|
287
|
+
);
|
|
288
|
+
const result = {};
|
|
289
|
+
function extractPromptFromSide(obj) {
|
|
290
|
+
for (const prop of obj.properties) {
|
|
291
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "prompt" && ts.isStringLiteral(prop.initializer)) {
|
|
292
|
+
return prop.initializer.text;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return void 0;
|
|
296
|
+
}
|
|
297
|
+
function visit(node) {
|
|
298
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineAgent" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
299
|
+
const configObj = node.arguments[0];
|
|
300
|
+
for (const prop of configObj.properties) {
|
|
301
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
302
|
+
if (prop.name.text === "sideA" && ts.isObjectLiteralExpression(prop.initializer)) {
|
|
303
|
+
result.sideA = extractPromptFromSide(prop.initializer);
|
|
304
|
+
}
|
|
305
|
+
if (prop.name.text === "sideB" && ts.isObjectLiteralExpression(prop.initializer)) {
|
|
306
|
+
result.sideB = extractPromptFromSide(prop.initializer);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
ts.forEachChild(node, visit);
|
|
312
|
+
}
|
|
313
|
+
visit(sourceFile);
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
function extractAgentDescription(sourceCode) {
|
|
317
|
+
const sourceFile = ts.createSourceFile(
|
|
318
|
+
"agent.ts",
|
|
319
|
+
sourceCode,
|
|
320
|
+
ts.ScriptTarget.ESNext,
|
|
321
|
+
true
|
|
322
|
+
);
|
|
323
|
+
let description = null;
|
|
324
|
+
function visit(node) {
|
|
325
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineAgent" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
326
|
+
const configObj = node.arguments[0];
|
|
327
|
+
for (const prop of configObj.properties) {
|
|
328
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "description" && ts.isStringLiteral(prop.initializer)) {
|
|
329
|
+
description = prop.initializer.text;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
ts.forEachChild(node, visit);
|
|
334
|
+
}
|
|
335
|
+
visit(sourceFile);
|
|
336
|
+
return description;
|
|
337
|
+
}
|
|
338
|
+
function extractDefinitionName(sourceCode) {
|
|
339
|
+
const sourceFile = ts.createSourceFile(
|
|
340
|
+
"def.ts",
|
|
341
|
+
sourceCode,
|
|
342
|
+
ts.ScriptTarget.ESNext,
|
|
343
|
+
true
|
|
344
|
+
);
|
|
345
|
+
let name = null;
|
|
346
|
+
function visit(node) {
|
|
347
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && (node.expression.text === "defineTool" || node.expression.text === "definePrompt" || node.expression.text === "defineAgent" || node.expression.text === "defineModel" || node.expression.text === "defineHook") && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
348
|
+
const configObj = node.arguments[0];
|
|
349
|
+
for (const prop of configObj.properties) {
|
|
350
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "name" && ts.isStringLiteral(prop.initializer)) {
|
|
351
|
+
name = prop.initializer.text;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
ts.forEachChild(node, visit);
|
|
356
|
+
}
|
|
357
|
+
visit(sourceFile);
|
|
358
|
+
return name;
|
|
359
|
+
}
|
|
360
|
+
function extractModelFallbacks(sourceCode) {
|
|
361
|
+
const sourceFile = ts.createSourceFile(
|
|
362
|
+
"model.ts",
|
|
363
|
+
sourceCode,
|
|
364
|
+
ts.ScriptTarget.ESNext,
|
|
365
|
+
true
|
|
366
|
+
);
|
|
367
|
+
const fallbacks = [];
|
|
368
|
+
function visit(node) {
|
|
369
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineModel" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
370
|
+
const configObj = node.arguments[0];
|
|
371
|
+
for (const prop of configObj.properties) {
|
|
372
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "fallbacks" && ts.isArrayLiteralExpression(prop.initializer)) {
|
|
373
|
+
for (const element of prop.initializer.elements) {
|
|
374
|
+
if (ts.isStringLiteral(element)) {
|
|
375
|
+
fallbacks.push(element.text);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
ts.forEachChild(node, visit);
|
|
382
|
+
}
|
|
383
|
+
visit(sourceFile);
|
|
384
|
+
return fallbacks;
|
|
385
|
+
}
|
|
386
|
+
function transformBundledJs(code) {
|
|
387
|
+
const s = new MagicString(code);
|
|
388
|
+
const sourceFile = ts.createSourceFile(
|
|
389
|
+
"file.js",
|
|
390
|
+
code,
|
|
391
|
+
ts.ScriptTarget.ESNext,
|
|
392
|
+
true
|
|
393
|
+
);
|
|
394
|
+
let firstImportStart = -1;
|
|
395
|
+
let varStatementInfo = null;
|
|
396
|
+
function visit(node) {
|
|
397
|
+
if (ts.isImportDeclaration(node) && firstImportStart === -1) {
|
|
398
|
+
firstImportStart = node.getStart();
|
|
399
|
+
}
|
|
400
|
+
if (ts.isVariableStatement(node)) {
|
|
401
|
+
const decl = node.declarationList.declarations[0];
|
|
402
|
+
if (decl && decl.initializer && ts.isCallExpression(decl.initializer)) {
|
|
403
|
+
const callExpr = decl.initializer.expression;
|
|
404
|
+
if (ts.isIdentifier(callExpr) && (callExpr.text === "defineAgent" || callExpr.text === "definePrompt" || callExpr.text === "defineTool" || callExpr.text === "defineModel" || callExpr.text === "defineHook")) {
|
|
405
|
+
varStatementInfo = {
|
|
406
|
+
fullStart: node.getFullStart(),
|
|
407
|
+
start: node.getStart(),
|
|
408
|
+
varNameEnd: decl.initializer.getStart()
|
|
409
|
+
};
|
|
410
|
+
s.overwrite(varStatementInfo.start, varStatementInfo.varNameEnd, "export default ");
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (ts.isExportDeclaration(node)) {
|
|
415
|
+
const exportClause = node.exportClause;
|
|
416
|
+
if (exportClause && ts.isNamedExports(exportClause)) {
|
|
417
|
+
for (const element of exportClause.elements) {
|
|
418
|
+
if (element.propertyName && ts.isIdentifier(element.name) && element.name.text === "default") {
|
|
419
|
+
s.remove(node.getFullStart(), node.getEnd());
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
ts.forEachChild(node, visit);
|
|
425
|
+
}
|
|
426
|
+
visit(sourceFile);
|
|
427
|
+
if (firstImportStart > 0) {
|
|
428
|
+
s.remove(0, firstImportStart);
|
|
429
|
+
}
|
|
430
|
+
return s.toString().trim() + "\n";
|
|
431
|
+
}
|
|
432
|
+
function injectAgentMetadata(tsCode, metadata) {
|
|
433
|
+
if (!metadata.packageName && !metadata.version && !metadata.author && !metadata.license) {
|
|
434
|
+
return tsCode;
|
|
435
|
+
}
|
|
436
|
+
const s = new MagicString(tsCode);
|
|
437
|
+
const sourceFile = ts.createSourceFile(
|
|
438
|
+
"agent.ts",
|
|
439
|
+
tsCode,
|
|
440
|
+
ts.ScriptTarget.ESNext,
|
|
441
|
+
true
|
|
442
|
+
);
|
|
443
|
+
function visit(node) {
|
|
444
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineAgent" && node.arguments.length > 0 && ts.isObjectLiteralExpression(node.arguments[0])) {
|
|
445
|
+
const configObj = node.arguments[0];
|
|
446
|
+
for (const prop of configObj.properties) {
|
|
447
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "name") {
|
|
448
|
+
const metadataProps = [];
|
|
449
|
+
if (metadata.packageName) {
|
|
450
|
+
metadataProps.push(`packageName: ${JSON.stringify(metadata.packageName)}`);
|
|
451
|
+
}
|
|
452
|
+
if (metadata.version) {
|
|
453
|
+
metadataProps.push(`version: ${JSON.stringify(metadata.version)}`);
|
|
454
|
+
}
|
|
455
|
+
if (metadata.author) {
|
|
456
|
+
metadataProps.push(`author: ${JSON.stringify(metadata.author)}`);
|
|
457
|
+
}
|
|
458
|
+
if (metadata.license) {
|
|
459
|
+
metadataProps.push(`license: ${JSON.stringify(metadata.license)}`);
|
|
460
|
+
}
|
|
461
|
+
if (metadataProps.length > 0) {
|
|
462
|
+
const propEnd = prop.getEnd();
|
|
463
|
+
const afterProp = tsCode.substring(propEnd, propEnd + 1);
|
|
464
|
+
if (afterProp === ",") {
|
|
465
|
+
const insertText = `
|
|
466
|
+
${metadataProps.join(",\n ")},`;
|
|
467
|
+
s.appendRight(propEnd + 1, insertText);
|
|
468
|
+
} else {
|
|
469
|
+
const insertText = `,
|
|
470
|
+
${metadataProps.join(",\n ")}`;
|
|
471
|
+
s.appendRight(propEnd, insertText);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
ts.forEachChild(node, visit);
|
|
479
|
+
}
|
|
480
|
+
visit(sourceFile);
|
|
481
|
+
return s.toString();
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// src/packing/packing-service.ts
|
|
485
|
+
var PackingService = class {
|
|
486
|
+
/**
|
|
487
|
+
* Resolve the version of an npm package from node_modules.
|
|
488
|
+
*
|
|
489
|
+
* @param pkgName - Package name (e.g., '@standardagents/spec')
|
|
490
|
+
* @param rootDir - Root directory of the project
|
|
491
|
+
* @returns Version specifier (e.g., '^1.2.3') or '*' if not found
|
|
492
|
+
*/
|
|
493
|
+
resolvePackageVersion(pkgName, rootDir) {
|
|
494
|
+
const pkgJsonPath = path2.join(rootDir, "node_modules", pkgName, "package.json");
|
|
495
|
+
try {
|
|
496
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
497
|
+
return `^${pkgJson.version}`;
|
|
498
|
+
} catch {
|
|
499
|
+
return "*";
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Analyze an agent to discover all its constituents.
|
|
504
|
+
*
|
|
505
|
+
* This performs static analysis on the agent definition and all
|
|
506
|
+
* referenced prompts, tools, models, and hooks.
|
|
507
|
+
*
|
|
508
|
+
* @param agentName - Name of the agent to analyze
|
|
509
|
+
* @param rootDir - Root directory of the agents workspace
|
|
510
|
+
* @returns Analysis result with all discovered constituents
|
|
511
|
+
*/
|
|
512
|
+
async analyzeAgent(agentName, rootDir) {
|
|
513
|
+
const agentsDir = path2.join(rootDir, "agents");
|
|
514
|
+
const analysis = {
|
|
515
|
+
agent: agentName,
|
|
516
|
+
primaryPrompt: "",
|
|
517
|
+
constituents: {
|
|
518
|
+
prompts: [],
|
|
519
|
+
tools: [],
|
|
520
|
+
models: [],
|
|
521
|
+
hooks: [],
|
|
522
|
+
agents: []
|
|
523
|
+
},
|
|
524
|
+
shared: {
|
|
525
|
+
prompts: [],
|
|
526
|
+
tools: [],
|
|
527
|
+
models: [],
|
|
528
|
+
hooks: []
|
|
529
|
+
},
|
|
530
|
+
warnings: [],
|
|
531
|
+
errors: []
|
|
532
|
+
};
|
|
533
|
+
const agentFilePath = this.findFile(path2.join(agentsDir, "agents"), agentName);
|
|
534
|
+
if (!agentFilePath) {
|
|
535
|
+
analysis.errors.push(`Agent file not found: ${agentName}`);
|
|
536
|
+
return analysis;
|
|
537
|
+
}
|
|
538
|
+
analysis.constituents.agents.push({
|
|
539
|
+
name: agentName,
|
|
540
|
+
filePath: agentFilePath,
|
|
541
|
+
discoveredVia: "static",
|
|
542
|
+
sharedWith: []
|
|
543
|
+
});
|
|
544
|
+
const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
|
|
545
|
+
const agentPrompts = extractAgentPrompts(agentSource);
|
|
546
|
+
if (agentPrompts.sideA) {
|
|
547
|
+
analysis.primaryPrompt = agentPrompts.sideA;
|
|
548
|
+
await this.analyzePrompt(agentPrompts.sideA, agentsDir, analysis, /* @__PURE__ */ new Set(), `agent:${agentName}`);
|
|
549
|
+
}
|
|
550
|
+
if (agentPrompts.sideB) {
|
|
551
|
+
await this.analyzePrompt(agentPrompts.sideB, agentsDir, analysis, /* @__PURE__ */ new Set(), `agent:${agentName}`);
|
|
552
|
+
}
|
|
553
|
+
await this.checkSharedItems(agentsDir, analysis);
|
|
554
|
+
return analysis;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Generate a README for an analyzed agent.
|
|
558
|
+
*
|
|
559
|
+
* This is used during analysis to provide a pre-populated README
|
|
560
|
+
* that can be edited in the PackModal before packing.
|
|
561
|
+
*
|
|
562
|
+
* @param analysis - The packing analysis result
|
|
563
|
+
* @param rootDir - Root directory of the project
|
|
564
|
+
* @returns Object with generatedReadme and agentDescription
|
|
565
|
+
*/
|
|
566
|
+
generateReadmeForAnalysis(analysis, rootDir) {
|
|
567
|
+
const agentsDir = path2.join(rootDir, "agents");
|
|
568
|
+
const metadataService = new MetadataService(agentsDir);
|
|
569
|
+
let agentDescription;
|
|
570
|
+
const agentItem = analysis.constituents.agents.find((a) => a.name === analysis.agent);
|
|
571
|
+
if (agentItem?.filePath) {
|
|
572
|
+
try {
|
|
573
|
+
const agentSource = fs2.readFileSync(agentItem.filePath, "utf-8");
|
|
574
|
+
agentDescription = extractAgentDescription(agentSource) || void 0;
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const suggestedPackageName = metadataService.suggestPackageName(void 0, analysis.agent);
|
|
579
|
+
const generatedReadme = this.generateReadme(
|
|
580
|
+
suggestedPackageName,
|
|
581
|
+
analysis.agent,
|
|
582
|
+
"1.0.0",
|
|
583
|
+
// Default version, will be replaced in modal
|
|
584
|
+
"MIT",
|
|
585
|
+
// Default license
|
|
586
|
+
agentDescription
|
|
587
|
+
);
|
|
588
|
+
return { generatedReadme, agentDescription };
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Recursively analyze a prompt and its dependencies.
|
|
592
|
+
*/
|
|
593
|
+
async analyzePrompt(promptName, agentsDir, analysis, visited, parentKey) {
|
|
594
|
+
const promptFilePath = this.findFile(path2.join(agentsDir, "prompts"), promptName);
|
|
595
|
+
if (!promptFilePath) {
|
|
596
|
+
analysis.warnings.push(`Prompt file not found: ${promptName}`);
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const thisKey = `prompt:${promptName}`;
|
|
600
|
+
if (!analysis.constituents.prompts.some((p) => p.name === promptName && p.parentKey === parentKey)) {
|
|
601
|
+
analysis.constituents.prompts.push({
|
|
602
|
+
name: promptName,
|
|
603
|
+
filePath: promptFilePath,
|
|
604
|
+
discoveredVia: "agent-prompt",
|
|
605
|
+
sharedWith: [],
|
|
606
|
+
parentKey
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
if (visited.has(`prompt:${promptName}`)) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
visited.add(`prompt:${promptName}`);
|
|
613
|
+
const promptSource = fs2.readFileSync(promptFilePath, "utf-8");
|
|
614
|
+
const modelName = extractPromptModel(promptSource);
|
|
615
|
+
if (modelName) {
|
|
616
|
+
await this.analyzeModel(modelName, agentsDir, analysis, visited, thisKey);
|
|
617
|
+
}
|
|
618
|
+
const { tools: toolNames } = extractPromptTools(promptSource);
|
|
619
|
+
for (const toolName of toolNames) {
|
|
620
|
+
await this.analyzeTool(toolName, agentsDir, analysis, visited, "prompt-tools", thisKey);
|
|
621
|
+
}
|
|
622
|
+
const includedPrompts = extractPromptIncludes(promptSource);
|
|
623
|
+
for (const includedPrompt of includedPrompts) {
|
|
624
|
+
const item = analysis.constituents.prompts.find((p) => p.name === includedPrompt);
|
|
625
|
+
if (item) {
|
|
626
|
+
if (item.discoveredVia === "agent-prompt") {
|
|
627
|
+
item.discoveredVia = "prompt-includes";
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
await this.analyzePrompt(includedPrompt, agentsDir, analysis, visited, thisKey);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Analyze a tool and its dependencies.
|
|
635
|
+
* This also handles prompts-as-tools and agents-as-tools (handoffs).
|
|
636
|
+
*/
|
|
637
|
+
async analyzeTool(toolName, agentsDir, analysis, visited, discoveredVia, parentKey) {
|
|
638
|
+
const thisKey = `tool:${toolName}`;
|
|
639
|
+
const promptFilePath = this.findFile(path2.join(agentsDir, "prompts"), toolName);
|
|
640
|
+
if (promptFilePath) {
|
|
641
|
+
await this.analyzePrompt(toolName, agentsDir, analysis, visited, parentKey);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const agentFilePath = this.findFile(path2.join(agentsDir, "agents"), toolName);
|
|
645
|
+
if (agentFilePath) {
|
|
646
|
+
await this.analyzeNestedAgent(toolName, agentsDir, analysis, visited, parentKey);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const toolFilePath = this.findFile(path2.join(agentsDir, "tools"), toolName);
|
|
650
|
+
if (!toolFilePath) {
|
|
651
|
+
analysis.warnings.push(`Tool file not found: ${toolName}`);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (!analysis.constituents.tools.some((t) => t.name === toolName && t.parentKey === parentKey)) {
|
|
655
|
+
analysis.constituents.tools.push({
|
|
656
|
+
name: toolName,
|
|
657
|
+
filePath: toolFilePath,
|
|
658
|
+
discoveredVia,
|
|
659
|
+
sharedWith: [],
|
|
660
|
+
parentKey
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
if (visited.has(`tool:${toolName}`)) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
visited.add(`tool:${toolName}`);
|
|
667
|
+
const toolSource = fs2.readFileSync(toolFilePath, "utf-8");
|
|
668
|
+
const { uses } = extractToolUses(toolSource);
|
|
669
|
+
for (const usedItem of uses) {
|
|
670
|
+
await this.analyzeTool(usedItem, agentsDir, analysis, visited, "uses", thisKey);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Analyze a nested agent (used as a handoff target).
|
|
675
|
+
*/
|
|
676
|
+
async analyzeNestedAgent(agentName, agentsDir, analysis, visited, parentKey) {
|
|
677
|
+
const agentFilePath = this.findFile(path2.join(agentsDir, "agents"), agentName);
|
|
678
|
+
if (!agentFilePath) {
|
|
679
|
+
analysis.warnings.push(`Agent file not found: ${agentName}`);
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
const thisKey = `agent:${agentName}`;
|
|
683
|
+
if (!analysis.constituents.agents.some((a) => a.name === agentName && a.parentKey === parentKey)) {
|
|
684
|
+
analysis.constituents.agents.push({
|
|
685
|
+
name: agentName,
|
|
686
|
+
filePath: agentFilePath,
|
|
687
|
+
discoveredVia: "uses",
|
|
688
|
+
sharedWith: [],
|
|
689
|
+
parentKey
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
if (visited.has(`agent:${agentName}`)) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
visited.add(`agent:${agentName}`);
|
|
696
|
+
const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
|
|
697
|
+
const agentPrompts = extractAgentPrompts(agentSource);
|
|
698
|
+
if (agentPrompts.sideA) {
|
|
699
|
+
await this.analyzePrompt(agentPrompts.sideA, agentsDir, analysis, visited, thisKey);
|
|
700
|
+
}
|
|
701
|
+
if (agentPrompts.sideB) {
|
|
702
|
+
await this.analyzePrompt(agentPrompts.sideB, agentsDir, analysis, visited, thisKey);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Analyze a model and its fallbacks.
|
|
707
|
+
*/
|
|
708
|
+
async analyzeModel(modelName, agentsDir, analysis, visited, parentKey) {
|
|
709
|
+
const modelFilePath = this.findFile(path2.join(agentsDir, "models"), modelName);
|
|
710
|
+
if (!modelFilePath) {
|
|
711
|
+
analysis.warnings.push(`Model file not found: ${modelName}`);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const thisKey = `model:${modelName}`;
|
|
715
|
+
if (!analysis.constituents.models.some((m) => m.name === modelName && m.parentKey === parentKey)) {
|
|
716
|
+
analysis.constituents.models.push({
|
|
717
|
+
name: modelName,
|
|
718
|
+
filePath: modelFilePath,
|
|
719
|
+
discoveredVia: "static",
|
|
720
|
+
sharedWith: [],
|
|
721
|
+
parentKey
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
if (visited.has(`model:${modelName}`)) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
visited.add(`model:${modelName}`);
|
|
728
|
+
const modelSource = fs2.readFileSync(modelFilePath, "utf-8");
|
|
729
|
+
const fallbacks = extractModelFallbacks(modelSource);
|
|
730
|
+
for (const fallbackName of fallbacks) {
|
|
731
|
+
await this.analyzeModel(fallbackName, agentsDir, analysis, visited, thisKey);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Check which items are shared with other agents.
|
|
736
|
+
*/
|
|
737
|
+
async checkSharedItems(agentsDir, analysis) {
|
|
738
|
+
const agentsPath = path2.join(agentsDir, "agents");
|
|
739
|
+
if (!fs2.existsSync(agentsPath)) return;
|
|
740
|
+
const agentFiles = fs2.readdirSync(agentsPath).filter((f) => f.endsWith(".ts"));
|
|
741
|
+
for (const agentFile of agentFiles) {
|
|
742
|
+
const otherAgentName = agentFile.replace(".ts", "");
|
|
743
|
+
if (otherAgentName === analysis.agent) continue;
|
|
744
|
+
const otherAnalysis = await this.analyzeAgentLight(otherAgentName, path2.dirname(agentsDir));
|
|
745
|
+
for (const prompt of analysis.constituents.prompts) {
|
|
746
|
+
if (otherAnalysis.prompts.includes(prompt.name)) {
|
|
747
|
+
prompt.sharedWith.push(otherAgentName);
|
|
748
|
+
if (!analysis.shared.prompts.includes(prompt.name)) {
|
|
749
|
+
analysis.shared.prompts.push(prompt.name);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
for (const tool of analysis.constituents.tools) {
|
|
754
|
+
if (otherAnalysis.tools.includes(tool.name)) {
|
|
755
|
+
tool.sharedWith.push(otherAgentName);
|
|
756
|
+
if (!analysis.shared.tools.includes(tool.name)) {
|
|
757
|
+
analysis.shared.tools.push(tool.name);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
for (const model of analysis.constituents.models) {
|
|
762
|
+
if (otherAnalysis.models.includes(model.name)) {
|
|
763
|
+
model.sharedWith.push(otherAgentName);
|
|
764
|
+
if (!analysis.shared.models.includes(model.name)) {
|
|
765
|
+
analysis.shared.models.push(model.name);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Light analysis of an agent - just get the names of used items.
|
|
773
|
+
*/
|
|
774
|
+
async analyzeAgentLight(agentName, rootDir) {
|
|
775
|
+
const result = { prompts: [], tools: [], models: [] };
|
|
776
|
+
const agentsDir = path2.join(rootDir, "agents");
|
|
777
|
+
const visited = /* @__PURE__ */ new Set();
|
|
778
|
+
const agentFilePath = this.findFile(path2.join(agentsDir, "agents"), agentName);
|
|
779
|
+
if (!agentFilePath) return result;
|
|
780
|
+
const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
|
|
781
|
+
const agentPrompts = extractAgentPrompts(agentSource);
|
|
782
|
+
const analyzePromptLight = (promptName) => {
|
|
783
|
+
if (visited.has(promptName)) return;
|
|
784
|
+
visited.add(promptName);
|
|
785
|
+
result.prompts.push(promptName);
|
|
786
|
+
const promptFilePath = this.findFile(path2.join(agentsDir, "prompts"), promptName);
|
|
787
|
+
if (!promptFilePath) return;
|
|
788
|
+
const promptSource = fs2.readFileSync(promptFilePath, "utf-8");
|
|
789
|
+
const modelName = extractPromptModel(promptSource);
|
|
790
|
+
if (modelName && !result.models.includes(modelName)) {
|
|
791
|
+
result.models.push(modelName);
|
|
792
|
+
}
|
|
793
|
+
const { tools } = extractPromptTools(promptSource);
|
|
794
|
+
for (const tool of tools) {
|
|
795
|
+
if (!result.tools.includes(tool)) {
|
|
796
|
+
result.tools.push(tool);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
const includes = extractPromptIncludes(promptSource);
|
|
800
|
+
for (const inc of includes) {
|
|
801
|
+
analyzePromptLight(inc);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
if (agentPrompts.sideA) analyzePromptLight(agentPrompts.sideA);
|
|
805
|
+
if (agentPrompts.sideB) analyzePromptLight(agentPrompts.sideB);
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Pack an agent with all its dependencies using Rollup bundling.
|
|
810
|
+
*
|
|
811
|
+
* The packing format creates:
|
|
812
|
+
* - dist/{type}/{name}.js - Individual bundled files per constituent
|
|
813
|
+
* - dist/index.js - Re-exports and lazy loaders
|
|
814
|
+
* - dist/index.d.ts - TypeScript type definitions
|
|
815
|
+
* - package.json - With standardagent field and dependencies
|
|
816
|
+
* - tsconfig.json - For building
|
|
817
|
+
*
|
|
818
|
+
* @param options - Packing options
|
|
819
|
+
* @returns Packing result
|
|
820
|
+
*/
|
|
821
|
+
async pack(options) {
|
|
822
|
+
const {
|
|
823
|
+
agentName,
|
|
824
|
+
rootDir,
|
|
825
|
+
outputDir,
|
|
826
|
+
version = "1.0.0",
|
|
827
|
+
removeOriginals = false,
|
|
828
|
+
packageId = `standardagent-${agentName.replace(/_/g, "-")}`,
|
|
829
|
+
packageName,
|
|
830
|
+
license,
|
|
831
|
+
licenseOwner,
|
|
832
|
+
itemSelections,
|
|
833
|
+
readme
|
|
834
|
+
} = options;
|
|
835
|
+
const finalPackageName = packageName || packageId;
|
|
836
|
+
const packedAt = Date.now();
|
|
837
|
+
const meta = {
|
|
838
|
+
packageId,
|
|
839
|
+
version,
|
|
840
|
+
entryAgents: [agentName],
|
|
841
|
+
packedAt
|
|
842
|
+
};
|
|
843
|
+
const result = {
|
|
844
|
+
success: false,
|
|
845
|
+
packageId,
|
|
846
|
+
outputPath: "",
|
|
847
|
+
meta,
|
|
848
|
+
filesCreated: [],
|
|
849
|
+
warnings: []
|
|
850
|
+
};
|
|
851
|
+
try {
|
|
852
|
+
const analysis = await this.analyzeAgent(agentName, rootDir);
|
|
853
|
+
if (analysis.errors.length > 0) {
|
|
854
|
+
result.error = analysis.errors.join("\n");
|
|
855
|
+
result.warnings = analysis.warnings;
|
|
856
|
+
return result;
|
|
857
|
+
}
|
|
858
|
+
result.warnings = analysis.warnings;
|
|
859
|
+
const pkgOutputDir = path2.join(outputDir, packageId);
|
|
860
|
+
fs2.mkdirSync(path2.join(pkgOutputDir, "dist", "agents"), { recursive: true });
|
|
861
|
+
fs2.mkdirSync(path2.join(pkgOutputDir, "dist", "prompts"), { recursive: true });
|
|
862
|
+
fs2.mkdirSync(path2.join(pkgOutputDir, "dist", "tools"), { recursive: true });
|
|
863
|
+
fs2.mkdirSync(path2.join(pkgOutputDir, "dist", "models"), { recursive: true });
|
|
864
|
+
fs2.mkdirSync(path2.join(pkgOutputDir, "dist", "hooks"), { recursive: true });
|
|
865
|
+
const seenItems = /* @__PURE__ */ new Set();
|
|
866
|
+
const allItems = [];
|
|
867
|
+
for (const a of analysis.constituents.agents) {
|
|
868
|
+
const key = `agent:${a.name}`;
|
|
869
|
+
if (!seenItems.has(key)) {
|
|
870
|
+
seenItems.add(key);
|
|
871
|
+
allItems.push({ ...a, type: "agent" });
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
for (const p of analysis.constituents.prompts) {
|
|
875
|
+
const key = `prompt:${p.name}`;
|
|
876
|
+
if (!seenItems.has(key)) {
|
|
877
|
+
seenItems.add(key);
|
|
878
|
+
allItems.push({ ...p, type: "prompt" });
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
for (const t of analysis.constituents.tools) {
|
|
882
|
+
const key = `tool:${t.name}`;
|
|
883
|
+
if (!seenItems.has(key)) {
|
|
884
|
+
seenItems.add(key);
|
|
885
|
+
allItems.push({ ...t, type: "tool" });
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
for (const m of analysis.constituents.models) {
|
|
889
|
+
const key = `model:${m.name}`;
|
|
890
|
+
if (!seenItems.has(key)) {
|
|
891
|
+
seenItems.add(key);
|
|
892
|
+
allItems.push({ ...m, type: "model" });
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
for (const h of analysis.constituents.hooks) {
|
|
896
|
+
const key = `hook:${h.name}`;
|
|
897
|
+
if (!seenItems.has(key)) {
|
|
898
|
+
seenItems.add(key);
|
|
899
|
+
allItems.push({ ...h, type: "hook" });
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
const externalDeps = /* @__PURE__ */ new Map();
|
|
903
|
+
for (const item of allItems) {
|
|
904
|
+
const outputPath = path2.join(
|
|
905
|
+
pkgOutputDir,
|
|
906
|
+
"dist",
|
|
907
|
+
this.getTypeDir(item.type),
|
|
908
|
+
`${item.name}.js`
|
|
909
|
+
);
|
|
910
|
+
const deps = await this.bundleFile(item.filePath, outputPath, rootDir);
|
|
911
|
+
for (const [depName, depVersion] of deps) {
|
|
912
|
+
if (!externalDeps.has(depName)) {
|
|
913
|
+
externalDeps.set(depName, depVersion);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
result.filesCreated.push(outputPath);
|
|
917
|
+
}
|
|
918
|
+
const indexJs = this.generateReExportIndex(analysis, meta);
|
|
919
|
+
const indexJsPath = path2.join(pkgOutputDir, "dist", "index.js");
|
|
920
|
+
fs2.writeFileSync(indexJsPath, indexJs);
|
|
921
|
+
result.filesCreated.push(indexJsPath);
|
|
922
|
+
const indexDts = this.generateIndexDts(analysis);
|
|
923
|
+
const indexDtsPath = path2.join(pkgOutputDir, "dist", "index.d.ts");
|
|
924
|
+
fs2.writeFileSync(indexDtsPath, indexDts);
|
|
925
|
+
result.filesCreated.push(indexDtsPath);
|
|
926
|
+
const pkgJson = this.generatePackageJson(
|
|
927
|
+
finalPackageName,
|
|
928
|
+
version,
|
|
929
|
+
agentName,
|
|
930
|
+
externalDeps,
|
|
931
|
+
rootDir,
|
|
932
|
+
license,
|
|
933
|
+
licenseOwner
|
|
934
|
+
);
|
|
935
|
+
const pkgJsonPath = path2.join(pkgOutputDir, "package.json");
|
|
936
|
+
fs2.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
937
|
+
result.filesCreated.push(pkgJsonPath);
|
|
938
|
+
if (license) {
|
|
939
|
+
const licenseContent = this.generateLicenseFile(license, licenseOwner);
|
|
940
|
+
const licensePath = path2.join(pkgOutputDir, "LICENSE");
|
|
941
|
+
fs2.writeFileSync(licensePath, licenseContent);
|
|
942
|
+
result.filesCreated.push(licensePath);
|
|
943
|
+
}
|
|
944
|
+
let readmeContent = readme;
|
|
945
|
+
if (!readmeContent) {
|
|
946
|
+
const agentItem = analysis.constituents.agents.find((a) => a.name === agentName);
|
|
947
|
+
let agentDescription;
|
|
948
|
+
if (agentItem?.filePath) {
|
|
949
|
+
const agentSource = fs2.readFileSync(agentItem.filePath, "utf-8");
|
|
950
|
+
agentDescription = extractAgentDescription(agentSource) || void 0;
|
|
951
|
+
}
|
|
952
|
+
readmeContent = this.generateReadme(
|
|
953
|
+
finalPackageName,
|
|
954
|
+
agentName,
|
|
955
|
+
version,
|
|
956
|
+
license,
|
|
957
|
+
agentDescription
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
const readmePath = path2.join(pkgOutputDir, "README.md");
|
|
961
|
+
fs2.writeFileSync(readmePath, readmeContent);
|
|
962
|
+
result.filesCreated.push(readmePath);
|
|
963
|
+
if (removeOriginals || itemSelections) {
|
|
964
|
+
result.filesRemoved = [];
|
|
965
|
+
for (const item of allItems) {
|
|
966
|
+
const selection = itemSelections?.find((s) => s.name === item.name && s.type === item.type);
|
|
967
|
+
const shouldRemove = selection ? selection.mode === "extract" : removeOriginals && item.sharedWith.length === 0;
|
|
968
|
+
if (shouldRemove && fs2.existsSync(item.filePath)) {
|
|
969
|
+
fs2.unlinkSync(item.filePath);
|
|
970
|
+
result.filesRemoved.push(item.filePath);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
const agentsDir = path2.join(rootDir, "agents");
|
|
975
|
+
const metadataService = new MetadataService(agentsDir);
|
|
976
|
+
const metadata = {
|
|
977
|
+
packageName: finalPackageName,
|
|
978
|
+
version,
|
|
979
|
+
license: license || "",
|
|
980
|
+
licenseOwner: licenseOwner || "",
|
|
981
|
+
lastPackedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
982
|
+
};
|
|
983
|
+
await metadataService.write(agentName, metadata);
|
|
984
|
+
result.success = true;
|
|
985
|
+
result.outputPath = pkgOutputDir;
|
|
986
|
+
result.meta = meta;
|
|
987
|
+
return result;
|
|
988
|
+
} catch (error) {
|
|
989
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
990
|
+
return result;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Bundle a single source file with its local dependencies using Rollup.
|
|
995
|
+
*
|
|
996
|
+
* Local files (from the same agents/ directory) are inlined.
|
|
997
|
+
* npm packages are kept as external dependencies.
|
|
998
|
+
* Output is bundled JavaScript with all local deps inlined.
|
|
999
|
+
*
|
|
1000
|
+
* @returns Map of external dependencies (name -> version specifier)
|
|
1001
|
+
*/
|
|
1002
|
+
async bundleFile(inputPath, outputPath, rootDir) {
|
|
1003
|
+
const { rollup } = await import('rollup');
|
|
1004
|
+
const nodeResolve = (await import('@rollup/plugin-node-resolve')).default;
|
|
1005
|
+
const commonjs = (await import('@rollup/plugin-commonjs')).default;
|
|
1006
|
+
const esbuild = (await import('rollup-plugin-esbuild')).default;
|
|
1007
|
+
const externalDeps = /* @__PURE__ */ new Map();
|
|
1008
|
+
const agentsDir = path2.join(rootDir, "agents");
|
|
1009
|
+
const resolveVersion = this.resolvePackageVersion.bind(this);
|
|
1010
|
+
const trackExternalsPlugin = {
|
|
1011
|
+
name: "track-externals",
|
|
1012
|
+
resolveId(source, importer) {
|
|
1013
|
+
if (!importer) {
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
1016
|
+
if (source.startsWith("./") || source.startsWith("../")) {
|
|
1017
|
+
const resolved = path2.resolve(path2.dirname(importer), source);
|
|
1018
|
+
let tsResolved = resolved;
|
|
1019
|
+
if (!resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
|
|
1020
|
+
if (fs2.existsSync(`${resolved}.ts`)) {
|
|
1021
|
+
tsResolved = `${resolved}.ts`;
|
|
1022
|
+
} else if (fs2.existsSync(`${resolved}.js`)) {
|
|
1023
|
+
tsResolved = `${resolved}.js`;
|
|
1024
|
+
} else if (fs2.existsSync(`${resolved}/index.ts`)) {
|
|
1025
|
+
tsResolved = `${resolved}/index.ts`;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
if (tsResolved.includes(agentsDir) || resolved.includes(agentsDir)) {
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
if (source.startsWith("/") && source.includes(agentsDir)) {
|
|
1034
|
+
return null;
|
|
1035
|
+
}
|
|
1036
|
+
const pkgName = source.startsWith("@") ? source.split("/").slice(0, 2).join("/") : source.split("/")[0];
|
|
1037
|
+
if (pkgName.startsWith("@standardagents/")) {
|
|
1038
|
+
externalDeps.set(pkgName, resolveVersion(pkgName, rootDir));
|
|
1039
|
+
} else if (pkgName === "zod") {
|
|
1040
|
+
externalDeps.set(pkgName, "^4.0.0");
|
|
1041
|
+
} else {
|
|
1042
|
+
externalDeps.set(pkgName, "*");
|
|
1043
|
+
}
|
|
1044
|
+
return { id: source, external: true };
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
const rollupOptions = {
|
|
1048
|
+
input: inputPath,
|
|
1049
|
+
plugins: [
|
|
1050
|
+
trackExternalsPlugin,
|
|
1051
|
+
nodeResolve({
|
|
1052
|
+
extensions: [".ts", ".js"]
|
|
1053
|
+
}),
|
|
1054
|
+
commonjs(),
|
|
1055
|
+
esbuild({
|
|
1056
|
+
target: "es2022",
|
|
1057
|
+
sourceMap: false
|
|
1058
|
+
})
|
|
1059
|
+
],
|
|
1060
|
+
onwarn(warning, warn) {
|
|
1061
|
+
if (warning.code === "UNRESOLVED_IMPORT") return;
|
|
1062
|
+
if (warning.code === "CIRCULAR_DEPENDENCY") return;
|
|
1063
|
+
warn(warning);
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
const bundle = await rollup(rollupOptions);
|
|
1067
|
+
try {
|
|
1068
|
+
const { output } = await bundle.generate({
|
|
1069
|
+
format: "esm",
|
|
1070
|
+
exports: "named"
|
|
1071
|
+
});
|
|
1072
|
+
const bundledCode = output[0].code;
|
|
1073
|
+
const header = `// Bundled from: ${path2.relative(rootDir, inputPath)}
|
|
1074
|
+
// Local dependencies have been inlined
|
|
1075
|
+
|
|
1076
|
+
`;
|
|
1077
|
+
fs2.writeFileSync(outputPath, header + bundledCode);
|
|
1078
|
+
await bundle.close();
|
|
1079
|
+
} catch (error) {
|
|
1080
|
+
await bundle.close();
|
|
1081
|
+
throw error;
|
|
1082
|
+
}
|
|
1083
|
+
return externalDeps;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Get the directory name for a constituent type.
|
|
1087
|
+
*/
|
|
1088
|
+
getTypeDir(type) {
|
|
1089
|
+
switch (type) {
|
|
1090
|
+
case "agent":
|
|
1091
|
+
return "agents";
|
|
1092
|
+
case "prompt":
|
|
1093
|
+
return "prompts";
|
|
1094
|
+
case "tool":
|
|
1095
|
+
return "tools";
|
|
1096
|
+
case "model":
|
|
1097
|
+
return "models";
|
|
1098
|
+
case "hook":
|
|
1099
|
+
return "hooks";
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Deduplicate constituents by name (for packing, not for tree display).
|
|
1104
|
+
*/
|
|
1105
|
+
deduplicateConstituents(analysis) {
|
|
1106
|
+
const dedupe = (items) => {
|
|
1107
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1108
|
+
return items.filter((item) => {
|
|
1109
|
+
if (seen.has(item.name)) return false;
|
|
1110
|
+
seen.add(item.name);
|
|
1111
|
+
return true;
|
|
1112
|
+
});
|
|
1113
|
+
};
|
|
1114
|
+
return {
|
|
1115
|
+
agents: dedupe(analysis.constituents.agents),
|
|
1116
|
+
prompts: dedupe(analysis.constituents.prompts),
|
|
1117
|
+
tools: dedupe(analysis.constituents.tools),
|
|
1118
|
+
models: dedupe(analysis.constituents.models),
|
|
1119
|
+
hooks: dedupe(analysis.constituents.hooks)
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Check if a name is a valid JavaScript/TypeScript identifier.
|
|
1124
|
+
*/
|
|
1125
|
+
isValidIdentifier(name) {
|
|
1126
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Quote a property/export name if it contains non-identifier characters.
|
|
1130
|
+
* JavaScript identifiers must start with a letter, underscore, or dollar sign,
|
|
1131
|
+
* and contain only letters, digits, underscores, or dollar signs.
|
|
1132
|
+
*/
|
|
1133
|
+
quoteName(name) {
|
|
1134
|
+
if (this.isValidIdentifier(name)) {
|
|
1135
|
+
return name;
|
|
1136
|
+
}
|
|
1137
|
+
return `'${name}'`;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Generate the dist/index.js file with re-exports and lazy loaders.
|
|
1141
|
+
*/
|
|
1142
|
+
generateReExportIndex(analysis, meta) {
|
|
1143
|
+
const constituents = this.deduplicateConstituents(analysis);
|
|
1144
|
+
const lines = [
|
|
1145
|
+
"// Packed agent: " + analysis.agent,
|
|
1146
|
+
"// Generated by @standardagents/builder",
|
|
1147
|
+
""
|
|
1148
|
+
];
|
|
1149
|
+
for (const agent of constituents.agents) {
|
|
1150
|
+
lines.push(`export { default as ${this.quoteName(agent.name)} } from './agents/${agent.name}.js';`);
|
|
1151
|
+
}
|
|
1152
|
+
for (const prompt of constituents.prompts) {
|
|
1153
|
+
lines.push(`export { default as ${this.quoteName(prompt.name)} } from './prompts/${prompt.name}.js';`);
|
|
1154
|
+
}
|
|
1155
|
+
for (const tool of constituents.tools) {
|
|
1156
|
+
lines.push(`export { default as ${this.quoteName(tool.name)} } from './tools/${tool.name}.js';`);
|
|
1157
|
+
}
|
|
1158
|
+
for (const model of constituents.models) {
|
|
1159
|
+
lines.push(`export { default as ${this.quoteName(model.name)} } from './models/${model.name}.js';`);
|
|
1160
|
+
}
|
|
1161
|
+
for (const hook of constituents.hooks) {
|
|
1162
|
+
lines.push(`export { default as ${this.quoteName(hook.name)} } from './hooks/${hook.name}.js';`);
|
|
1163
|
+
}
|
|
1164
|
+
lines.push("");
|
|
1165
|
+
lines.push("// Registry exports for lazy loading");
|
|
1166
|
+
lines.push("export const agents = {");
|
|
1167
|
+
for (const agent of constituents.agents) {
|
|
1168
|
+
lines.push(` ${this.quoteName(agent.name)}: async () => (await import('./agents/${agent.name}.js')).default,`);
|
|
1169
|
+
}
|
|
1170
|
+
lines.push("};");
|
|
1171
|
+
lines.push("");
|
|
1172
|
+
lines.push("export const prompts = {");
|
|
1173
|
+
for (const prompt of constituents.prompts) {
|
|
1174
|
+
lines.push(` ${this.quoteName(prompt.name)}: async () => (await import('./prompts/${prompt.name}.js')).default,`);
|
|
1175
|
+
}
|
|
1176
|
+
lines.push("};");
|
|
1177
|
+
lines.push("");
|
|
1178
|
+
lines.push("export const tools = {");
|
|
1179
|
+
for (const tool of constituents.tools) {
|
|
1180
|
+
lines.push(` ${this.quoteName(tool.name)}: async () => (await import('./tools/${tool.name}.js')).default,`);
|
|
1181
|
+
}
|
|
1182
|
+
lines.push("};");
|
|
1183
|
+
lines.push("");
|
|
1184
|
+
lines.push("export const models = {");
|
|
1185
|
+
for (const model of constituents.models) {
|
|
1186
|
+
lines.push(` ${this.quoteName(model.name)}: async () => (await import('./models/${model.name}.js')).default,`);
|
|
1187
|
+
}
|
|
1188
|
+
lines.push("};");
|
|
1189
|
+
lines.push("");
|
|
1190
|
+
lines.push("export const hooks = {");
|
|
1191
|
+
for (const hook of constituents.hooks) {
|
|
1192
|
+
lines.push(` ${this.quoteName(hook.name)}: async () => (await import('./hooks/${hook.name}.js')).default,`);
|
|
1193
|
+
}
|
|
1194
|
+
lines.push("};");
|
|
1195
|
+
lines.push("");
|
|
1196
|
+
lines.push("export const __meta = " + JSON.stringify(meta, null, 2) + ";");
|
|
1197
|
+
lines.push("");
|
|
1198
|
+
return lines.join("\n");
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Generate the dist/index.d.ts file with type definitions.
|
|
1202
|
+
*/
|
|
1203
|
+
generateIndexDts(analysis) {
|
|
1204
|
+
const constituents = this.deduplicateConstituents(analysis);
|
|
1205
|
+
const lines = [
|
|
1206
|
+
"import type {",
|
|
1207
|
+
" AgentDefinition,",
|
|
1208
|
+
" PromptDefinition,",
|
|
1209
|
+
" ToolDefinition,",
|
|
1210
|
+
" ModelDefinition,",
|
|
1211
|
+
" PackedMeta,",
|
|
1212
|
+
"} from '@standardagents/spec';",
|
|
1213
|
+
"",
|
|
1214
|
+
"type DefinitionLoader<T> = () => Promise<T>;",
|
|
1215
|
+
""
|
|
1216
|
+
];
|
|
1217
|
+
for (const agent of constituents.agents) {
|
|
1218
|
+
if (this.isValidIdentifier(agent.name)) {
|
|
1219
|
+
lines.push(`export declare const ${agent.name}: AgentDefinition;`);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
for (const prompt of constituents.prompts) {
|
|
1223
|
+
if (this.isValidIdentifier(prompt.name)) {
|
|
1224
|
+
lines.push(`export declare const ${prompt.name}: PromptDefinition;`);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
for (const tool of constituents.tools) {
|
|
1228
|
+
if (this.isValidIdentifier(tool.name)) {
|
|
1229
|
+
lines.push(`export declare const ${tool.name}: ToolDefinition<unknown, any, any>;`);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
for (const model of constituents.models) {
|
|
1233
|
+
if (this.isValidIdentifier(model.name)) {
|
|
1234
|
+
lines.push(`export declare const ${model.name}: ModelDefinition;`);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
for (const hook of constituents.hooks) {
|
|
1238
|
+
if (this.isValidIdentifier(hook.name)) {
|
|
1239
|
+
lines.push(`export declare const ${hook.name}: unknown;`);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
lines.push("");
|
|
1243
|
+
lines.push("export declare const agents: {");
|
|
1244
|
+
for (const agent of constituents.agents) {
|
|
1245
|
+
lines.push(` readonly ${this.quoteName(agent.name)}: DefinitionLoader<AgentDefinition>;`);
|
|
1246
|
+
}
|
|
1247
|
+
lines.push("};");
|
|
1248
|
+
lines.push("");
|
|
1249
|
+
lines.push("export declare const prompts: {");
|
|
1250
|
+
for (const prompt of constituents.prompts) {
|
|
1251
|
+
lines.push(` readonly ${this.quoteName(prompt.name)}: DefinitionLoader<PromptDefinition>;`);
|
|
1252
|
+
}
|
|
1253
|
+
lines.push("};");
|
|
1254
|
+
lines.push("");
|
|
1255
|
+
lines.push("export declare const tools: {");
|
|
1256
|
+
for (const tool of constituents.tools) {
|
|
1257
|
+
lines.push(` readonly ${this.quoteName(tool.name)}: DefinitionLoader<ToolDefinition<unknown, any, any>>;`);
|
|
1258
|
+
}
|
|
1259
|
+
lines.push("};");
|
|
1260
|
+
lines.push("");
|
|
1261
|
+
lines.push("export declare const models: {");
|
|
1262
|
+
for (const model of constituents.models) {
|
|
1263
|
+
lines.push(` readonly ${this.quoteName(model.name)}: DefinitionLoader<ModelDefinition>;`);
|
|
1264
|
+
}
|
|
1265
|
+
lines.push("};");
|
|
1266
|
+
lines.push("");
|
|
1267
|
+
lines.push("export declare const hooks: {");
|
|
1268
|
+
for (const hook of constituents.hooks) {
|
|
1269
|
+
lines.push(` readonly ${this.quoteName(hook.name)}: DefinitionLoader<unknown>;`);
|
|
1270
|
+
}
|
|
1271
|
+
lines.push("};");
|
|
1272
|
+
lines.push("");
|
|
1273
|
+
lines.push("export declare const __meta: PackedMeta;");
|
|
1274
|
+
lines.push("");
|
|
1275
|
+
return lines.join("\n");
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Generate the package.json file with dependencies.
|
|
1279
|
+
*/
|
|
1280
|
+
generatePackageJson(packageName, version, agentName, externalDeps, rootDir, license, licenseOwner) {
|
|
1281
|
+
const dependencies = {
|
|
1282
|
+
"@standardagents/spec": this.resolvePackageVersion("@standardagents/spec", rootDir)
|
|
1283
|
+
};
|
|
1284
|
+
for (const [name, ver] of externalDeps) {
|
|
1285
|
+
dependencies[name] = ver;
|
|
1286
|
+
}
|
|
1287
|
+
const pkgJson = {
|
|
1288
|
+
name: packageName,
|
|
1289
|
+
version,
|
|
1290
|
+
type: "module",
|
|
1291
|
+
main: "./dist/index.js",
|
|
1292
|
+
types: "./dist/index.d.ts",
|
|
1293
|
+
exports: {
|
|
1294
|
+
".": {
|
|
1295
|
+
types: "./dist/index.d.ts",
|
|
1296
|
+
import: "./dist/index.js"
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
keywords: ["standardagent"],
|
|
1300
|
+
standardagent: {
|
|
1301
|
+
entryAgents: [agentName]
|
|
1302
|
+
},
|
|
1303
|
+
files: license ? ["dist", "LICENSE", "README.md"] : ["dist", "README.md"],
|
|
1304
|
+
dependencies
|
|
1305
|
+
};
|
|
1306
|
+
if (license) {
|
|
1307
|
+
pkgJson.license = license;
|
|
1308
|
+
}
|
|
1309
|
+
if (licenseOwner) {
|
|
1310
|
+
pkgJson.author = licenseOwner;
|
|
1311
|
+
}
|
|
1312
|
+
return pkgJson;
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* Generate LICENSE file content for common licenses.
|
|
1316
|
+
*/
|
|
1317
|
+
generateLicenseFile(license, owner) {
|
|
1318
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
1319
|
+
const copyrightHolder = owner || "[COPYRIGHT HOLDER]";
|
|
1320
|
+
switch (license) {
|
|
1321
|
+
case "MIT":
|
|
1322
|
+
return `MIT License
|
|
1323
|
+
|
|
1324
|
+
Copyright (c) ${year} ${copyrightHolder}
|
|
1325
|
+
|
|
1326
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1327
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1328
|
+
in the Software without restriction, including without limitation the rights
|
|
1329
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1330
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1331
|
+
furnished to do so, subject to the following conditions:
|
|
1332
|
+
|
|
1333
|
+
The above copyright notice and this permission notice shall be included in all
|
|
1334
|
+
copies or substantial portions of the Software.
|
|
1335
|
+
|
|
1336
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1337
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1338
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1339
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1340
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1341
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1342
|
+
SOFTWARE.
|
|
1343
|
+
`;
|
|
1344
|
+
case "Apache-2.0":
|
|
1345
|
+
return ` Apache License
|
|
1346
|
+
Version 2.0, January 2004
|
|
1347
|
+
http://www.apache.org/licenses/
|
|
1348
|
+
|
|
1349
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
1350
|
+
|
|
1351
|
+
Copyright ${year} ${copyrightHolder}
|
|
1352
|
+
|
|
1353
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
1354
|
+
you may not use this file except in compliance with the License.
|
|
1355
|
+
You may obtain a copy of the License at
|
|
1356
|
+
|
|
1357
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
1358
|
+
|
|
1359
|
+
Unless required by applicable law or agreed to in writing, software
|
|
1360
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
1361
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
1362
|
+
See the License for the specific language governing permissions and
|
|
1363
|
+
limitations under the License.
|
|
1364
|
+
`;
|
|
1365
|
+
case "ISC":
|
|
1366
|
+
return `ISC License
|
|
1367
|
+
|
|
1368
|
+
Copyright (c) ${year} ${copyrightHolder}
|
|
1369
|
+
|
|
1370
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
1371
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
1372
|
+
copyright notice and this permission notice appear in all copies.
|
|
1373
|
+
|
|
1374
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
1375
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
1376
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
1377
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
1378
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
1379
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
1380
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
1381
|
+
`;
|
|
1382
|
+
case "GPL-3.0":
|
|
1383
|
+
return `GNU GENERAL PUBLIC LICENSE
|
|
1384
|
+
Version 3, 29 June 2007
|
|
1385
|
+
|
|
1386
|
+
Copyright (c) ${year} ${copyrightHolder}
|
|
1387
|
+
|
|
1388
|
+
This program is free software: you can redistribute it and/or modify
|
|
1389
|
+
it under the terms of the GNU General Public License as published by
|
|
1390
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
1391
|
+
(at your option) any later version.
|
|
1392
|
+
|
|
1393
|
+
This program is distributed in the hope that it will be useful,
|
|
1394
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1395
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
1396
|
+
GNU General Public License for more details.
|
|
1397
|
+
|
|
1398
|
+
You should have received a copy of the GNU General Public License
|
|
1399
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
1400
|
+
`;
|
|
1401
|
+
case "BSD-3-Clause":
|
|
1402
|
+
return `BSD 3-Clause License
|
|
1403
|
+
|
|
1404
|
+
Copyright (c) ${year} ${copyrightHolder}
|
|
1405
|
+
|
|
1406
|
+
Redistribution and use in source and binary forms, with or without
|
|
1407
|
+
modification, are permitted provided that the following conditions are met:
|
|
1408
|
+
|
|
1409
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
1410
|
+
list of conditions and the following disclaimer.
|
|
1411
|
+
|
|
1412
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
1413
|
+
this list of conditions and the following disclaimer in the documentation
|
|
1414
|
+
and/or other materials provided with the distribution.
|
|
1415
|
+
|
|
1416
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
1417
|
+
contributors may be used to endorse or promote products derived from
|
|
1418
|
+
this software without specific prior written permission.
|
|
1419
|
+
|
|
1420
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
1421
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
1422
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
1423
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
1424
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
1425
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
1426
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
1427
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
1428
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1429
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1430
|
+
`;
|
|
1431
|
+
case "Unlicensed":
|
|
1432
|
+
case "UNLICENSED":
|
|
1433
|
+
return `Copyright (c) ${year} ${copyrightHolder}
|
|
1434
|
+
|
|
1435
|
+
All Rights Reserved.
|
|
1436
|
+
|
|
1437
|
+
This software and associated documentation files (the "Software") are
|
|
1438
|
+
proprietary and confidential. Unauthorized copying, modification, distribution,
|
|
1439
|
+
or use of the Software, via any medium, is strictly prohibited.
|
|
1440
|
+
`;
|
|
1441
|
+
default:
|
|
1442
|
+
return `${license}
|
|
1443
|
+
|
|
1444
|
+
Copyright (c) ${year} ${copyrightHolder}
|
|
1445
|
+
`;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Get information about a packed package.
|
|
1450
|
+
*
|
|
1451
|
+
* Reads the package.json and README.md from a packed package directory.
|
|
1452
|
+
* Used by the packed-info API endpoint to show package details before publishing.
|
|
1453
|
+
*
|
|
1454
|
+
* @param packageId - The package directory name (e.g., 'standardagent-my-agent')
|
|
1455
|
+
* @param rootDir - Root directory of the project
|
|
1456
|
+
* @returns Package info or null if not found
|
|
1457
|
+
*/
|
|
1458
|
+
getPackedInfo(packageId, rootDir) {
|
|
1459
|
+
const packedDir = path2.join(rootDir, "agents", "packed");
|
|
1460
|
+
let packageDir = path2.join(packedDir, packageId);
|
|
1461
|
+
if (!fs2.existsSync(packageDir)) {
|
|
1462
|
+
if (!fs2.existsSync(packedDir)) {
|
|
1463
|
+
return null;
|
|
1464
|
+
}
|
|
1465
|
+
const dirs = fs2.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
1466
|
+
const matchingDir = dirs.find(
|
|
1467
|
+
(d) => d === packageId || d === `standardagent-${packageId}` || d === `standardagent-${packageId.replace(/_/g, "-")}`
|
|
1468
|
+
);
|
|
1469
|
+
if (!matchingDir) {
|
|
1470
|
+
return null;
|
|
1471
|
+
}
|
|
1472
|
+
packageDir = path2.join(packedDir, matchingDir);
|
|
1473
|
+
}
|
|
1474
|
+
const pkgJsonPath = path2.join(packageDir, "package.json");
|
|
1475
|
+
if (!fs2.existsSync(pkgJsonPath)) {
|
|
1476
|
+
return null;
|
|
1477
|
+
}
|
|
1478
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
1479
|
+
let readme;
|
|
1480
|
+
const readmePath = path2.join(packageDir, "README.md");
|
|
1481
|
+
if (fs2.existsSync(readmePath)) {
|
|
1482
|
+
readme = fs2.readFileSync(readmePath, "utf-8");
|
|
1483
|
+
}
|
|
1484
|
+
return {
|
|
1485
|
+
packageName: pkgJson.name,
|
|
1486
|
+
version: pkgJson.version,
|
|
1487
|
+
license: pkgJson.license,
|
|
1488
|
+
author: pkgJson.author,
|
|
1489
|
+
entryAgents: pkgJson.standardagent?.entryAgents || [],
|
|
1490
|
+
readme
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* List all packed packages in the workspace.
|
|
1495
|
+
*
|
|
1496
|
+
* @param rootDir - Root directory of the project
|
|
1497
|
+
* @returns Array of package directory names
|
|
1498
|
+
*/
|
|
1499
|
+
listPackedPackages(rootDir) {
|
|
1500
|
+
const packedDir = path2.join(rootDir, "agents", "packed");
|
|
1501
|
+
if (!fs2.existsSync(packedDir)) {
|
|
1502
|
+
return [];
|
|
1503
|
+
}
|
|
1504
|
+
return fs2.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* Generate README.md content for a packed agent.
|
|
1508
|
+
*
|
|
1509
|
+
* @param packageName - The npm package name
|
|
1510
|
+
* @param agentName - The agent name
|
|
1511
|
+
* @param version - The package version
|
|
1512
|
+
* @param license - The license type
|
|
1513
|
+
* @param description - Optional description from the agent definition
|
|
1514
|
+
* @returns README markdown content
|
|
1515
|
+
*/
|
|
1516
|
+
generateReadme(packageName, agentName, version, license, description) {
|
|
1517
|
+
const desc = description || "A Standard Agent package.";
|
|
1518
|
+
return `# ${packageName}
|
|
1519
|
+
|
|
1520
|
+
${desc}
|
|
1521
|
+
|
|
1522
|
+
## Installation
|
|
1523
|
+
|
|
1524
|
+
\`\`\`bash
|
|
1525
|
+
npm install ${packageName}
|
|
1526
|
+
\`\`\`
|
|
1527
|
+
|
|
1528
|
+
## Usage
|
|
1529
|
+
|
|
1530
|
+
This is a [Standard Agent](https://standardagentbuilder.com) package. To use it:
|
|
1531
|
+
|
|
1532
|
+
1. Install in your Standard Agents project
|
|
1533
|
+
2. The agent will be automatically discovered and available
|
|
1534
|
+
|
|
1535
|
+
\`\`\`typescript
|
|
1536
|
+
// Create a thread with this agent
|
|
1537
|
+
const thread = await client.createThread({
|
|
1538
|
+
agent_id: '${packageName}/${agentName}'
|
|
1539
|
+
});
|
|
1540
|
+
\`\`\`
|
|
1541
|
+
|
|
1542
|
+
## License
|
|
1543
|
+
|
|
1544
|
+
${license || "See LICENSE file"}
|
|
1545
|
+
`;
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Find a file by name in a directory.
|
|
1549
|
+
*/
|
|
1550
|
+
findFile(dir, name) {
|
|
1551
|
+
if (!fs2.existsSync(dir)) {
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1554
|
+
const exactPath = path2.join(dir, `${name}.ts`);
|
|
1555
|
+
if (fs2.existsSync(exactPath)) {
|
|
1556
|
+
return exactPath;
|
|
1557
|
+
}
|
|
1558
|
+
const files = fs2.readdirSync(dir).filter((f) => f.endsWith(".ts"));
|
|
1559
|
+
for (const file of files) {
|
|
1560
|
+
const filePath = path2.join(dir, file);
|
|
1561
|
+
const source = fs2.readFileSync(filePath, "utf-8");
|
|
1562
|
+
const extractedName = extractDefinitionName(source);
|
|
1563
|
+
if (extractedName === name) {
|
|
1564
|
+
return filePath;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
return null;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* List all agents in the workspace.
|
|
1571
|
+
*/
|
|
1572
|
+
listAgents(rootDir) {
|
|
1573
|
+
const agentsDir = path2.join(rootDir, "agents", "agents");
|
|
1574
|
+
if (!fs2.existsSync(agentsDir)) {
|
|
1575
|
+
return [];
|
|
1576
|
+
}
|
|
1577
|
+
const files = fs2.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
|
|
1578
|
+
const agents = [];
|
|
1579
|
+
for (const file of files) {
|
|
1580
|
+
const filePath = path2.join(agentsDir, file);
|
|
1581
|
+
const source = fs2.readFileSync(filePath, "utf-8");
|
|
1582
|
+
const name = extractDefinitionName(source);
|
|
1583
|
+
if (name) {
|
|
1584
|
+
agents.push(name);
|
|
1585
|
+
} else {
|
|
1586
|
+
agents.push(file.replace(".ts", ""));
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return agents;
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
var PackageDiscoveryService = class {
|
|
1593
|
+
config;
|
|
1594
|
+
constructor(config) {
|
|
1595
|
+
this.config = {
|
|
1596
|
+
rootDir: config.rootDir,
|
|
1597
|
+
packedDir: config.packedDir ?? path2.join(config.rootDir, "agents", "packed"),
|
|
1598
|
+
scanNpm: config.scanNpm ?? true,
|
|
1599
|
+
scanLocal: config.scanLocal ?? true
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Discover all packed agent packages.
|
|
1604
|
+
*
|
|
1605
|
+
* @returns Array of discovered packages
|
|
1606
|
+
*/
|
|
1607
|
+
async discoverPackages() {
|
|
1608
|
+
const packages = [];
|
|
1609
|
+
if (this.config.scanNpm) {
|
|
1610
|
+
const npmPackages = await this.discoverNpmPackages();
|
|
1611
|
+
packages.push(...npmPackages);
|
|
1612
|
+
}
|
|
1613
|
+
if (this.config.scanLocal) {
|
|
1614
|
+
const localPackages = await this.discoverLocalPackages();
|
|
1615
|
+
packages.push(...localPackages);
|
|
1616
|
+
}
|
|
1617
|
+
return packages;
|
|
1618
|
+
}
|
|
1619
|
+
/**
|
|
1620
|
+
* Discover npm packages that are Standard Agents packages.
|
|
1621
|
+
*
|
|
1622
|
+
* Looks for packages with:
|
|
1623
|
+
* - "standardagent" keyword in package.json
|
|
1624
|
+
* - "standardagent-*" prefix in name
|
|
1625
|
+
* - "@standardagents/*" scope
|
|
1626
|
+
* - "standardagent" field in package.json
|
|
1627
|
+
*/
|
|
1628
|
+
async discoverNpmPackages() {
|
|
1629
|
+
const packages = [];
|
|
1630
|
+
const nodeModulesDir = path2.join(this.config.rootDir, "node_modules");
|
|
1631
|
+
if (!fs2.existsSync(nodeModulesDir)) {
|
|
1632
|
+
return packages;
|
|
1633
|
+
}
|
|
1634
|
+
const rootEntries = await this.scanDirectory(nodeModulesDir);
|
|
1635
|
+
for (const entry of rootEntries) {
|
|
1636
|
+
if (entry.startsWith(".")) continue;
|
|
1637
|
+
if (entry.startsWith("@")) {
|
|
1638
|
+
const scopeDir = path2.join(nodeModulesDir, entry);
|
|
1639
|
+
const scopeEntries = await this.scanDirectory(scopeDir);
|
|
1640
|
+
for (const scopedPkg of scopeEntries) {
|
|
1641
|
+
if (scopedPkg.startsWith(".")) continue;
|
|
1642
|
+
const pkgDir = path2.join(scopeDir, scopedPkg);
|
|
1643
|
+
const fullName = `${entry}/${scopedPkg}`;
|
|
1644
|
+
const pkg = await this.checkNpmPackage(pkgDir, fullName);
|
|
1645
|
+
if (pkg) {
|
|
1646
|
+
packages.push(pkg);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
} else {
|
|
1650
|
+
const pkgDir = path2.join(nodeModulesDir, entry);
|
|
1651
|
+
const pkg = await this.checkNpmPackage(pkgDir, entry);
|
|
1652
|
+
if (pkg) {
|
|
1653
|
+
packages.push(pkg);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return packages;
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* Check if an npm package is a Standard Agent package.
|
|
1661
|
+
*
|
|
1662
|
+
* Detection is based on the `standardagent` field in package.json,
|
|
1663
|
+
* which must contain `entryAgents` array.
|
|
1664
|
+
*/
|
|
1665
|
+
async checkNpmPackage(pkgDir, pkgName) {
|
|
1666
|
+
const pkgJsonPath = path2.join(pkgDir, "package.json");
|
|
1667
|
+
if (!fs2.existsSync(pkgJsonPath)) {
|
|
1668
|
+
return null;
|
|
1669
|
+
}
|
|
1670
|
+
try {
|
|
1671
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
1672
|
+
const isStandardAgent = (
|
|
1673
|
+
// Has "standardagent" keyword
|
|
1674
|
+
pkgJson.keywords?.includes("standardagent") || // Has "standardagent-*" prefix
|
|
1675
|
+
pkgName.startsWith("standardagent-") || // Has "@standardagents/*" scope
|
|
1676
|
+
pkgName.startsWith("@standardagents/") || // Has "standardagent" field
|
|
1677
|
+
pkgJson.standardagent !== void 0
|
|
1678
|
+
);
|
|
1679
|
+
if (!isStandardAgent) {
|
|
1680
|
+
return null;
|
|
1681
|
+
}
|
|
1682
|
+
if (!pkgJson.standardagent?.entryAgents) {
|
|
1683
|
+
return null;
|
|
1684
|
+
}
|
|
1685
|
+
return {
|
|
1686
|
+
packageId: pkgJson.name || pkgName,
|
|
1687
|
+
version: pkgJson.version || "0.0.0",
|
|
1688
|
+
source: "npm",
|
|
1689
|
+
path: pkgDir,
|
|
1690
|
+
entryAgents: pkgJson.standardagent.entryAgents,
|
|
1691
|
+
description: pkgJson.description
|
|
1692
|
+
};
|
|
1693
|
+
} catch (error) {
|
|
1694
|
+
console.warn(`[PackageDiscovery] Error reading npm package ${pkgName}:`, error);
|
|
1695
|
+
return null;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Discover local packed agents from agents/packed/ directory.
|
|
1700
|
+
* Handles both regular packages and scoped packages (@scope/name).
|
|
1701
|
+
*/
|
|
1702
|
+
async discoverLocalPackages() {
|
|
1703
|
+
const packages = [];
|
|
1704
|
+
if (!fs2.existsSync(this.config.packedDir)) {
|
|
1705
|
+
return packages;
|
|
1706
|
+
}
|
|
1707
|
+
const entries = await this.scanDirectory(this.config.packedDir);
|
|
1708
|
+
for (const entry of entries) {
|
|
1709
|
+
if (entry.startsWith(".")) continue;
|
|
1710
|
+
const pkgDir = path2.join(this.config.packedDir, entry);
|
|
1711
|
+
const stat = fs2.statSync(pkgDir);
|
|
1712
|
+
if (!stat.isDirectory()) continue;
|
|
1713
|
+
if (entry.startsWith("@")) {
|
|
1714
|
+
const scopeEntries = await this.scanDirectory(pkgDir);
|
|
1715
|
+
for (const scopedPkg of scopeEntries) {
|
|
1716
|
+
if (scopedPkg.startsWith(".")) continue;
|
|
1717
|
+
const scopedPkgDir = path2.join(pkgDir, scopedPkg);
|
|
1718
|
+
const scopedStat = fs2.statSync(scopedPkgDir);
|
|
1719
|
+
if (!scopedStat.isDirectory()) continue;
|
|
1720
|
+
const fullName = `${entry}/${scopedPkg}`;
|
|
1721
|
+
const pkg = await this.checkLocalPackage(scopedPkgDir, fullName);
|
|
1722
|
+
if (pkg) {
|
|
1723
|
+
packages.push(pkg);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
} else {
|
|
1727
|
+
const pkg = await this.checkLocalPackage(pkgDir, entry);
|
|
1728
|
+
if (pkg) {
|
|
1729
|
+
packages.push(pkg);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
return packages;
|
|
1734
|
+
}
|
|
1735
|
+
/**
|
|
1736
|
+
* Check if a local directory is a packed agent package.
|
|
1737
|
+
*
|
|
1738
|
+
* Detection is based on the `standardagent` field in package.json.
|
|
1739
|
+
*/
|
|
1740
|
+
async checkLocalPackage(pkgDir, dirName) {
|
|
1741
|
+
const pkgJsonPath = path2.join(pkgDir, "package.json");
|
|
1742
|
+
if (!fs2.existsSync(pkgJsonPath)) {
|
|
1743
|
+
return null;
|
|
1744
|
+
}
|
|
1745
|
+
try {
|
|
1746
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
1747
|
+
if (!pkgJson.standardagent?.entryAgents) {
|
|
1748
|
+
return null;
|
|
1749
|
+
}
|
|
1750
|
+
return {
|
|
1751
|
+
packageId: pkgJson.name || dirName,
|
|
1752
|
+
version: pkgJson.version || "0.0.0",
|
|
1753
|
+
source: "local",
|
|
1754
|
+
path: pkgDir,
|
|
1755
|
+
entryAgents: pkgJson.standardagent.entryAgents,
|
|
1756
|
+
description: pkgJson.description
|
|
1757
|
+
};
|
|
1758
|
+
} catch (error) {
|
|
1759
|
+
console.warn(`[PackageDiscovery] Error reading local package ${dirName}:`, error);
|
|
1760
|
+
return null;
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Scan a directory and return entry names.
|
|
1765
|
+
*/
|
|
1766
|
+
async scanDirectory(dir) {
|
|
1767
|
+
if (!fs2.existsSync(dir)) {
|
|
1768
|
+
return [];
|
|
1769
|
+
}
|
|
1770
|
+
const entries = fs2.readdirSync(dir);
|
|
1771
|
+
return entries;
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Validate a standardagent field structure in package.json.
|
|
1775
|
+
*/
|
|
1776
|
+
static validateStandardAgentField(field) {
|
|
1777
|
+
if (typeof field !== "object" || field === null) {
|
|
1778
|
+
return false;
|
|
1779
|
+
}
|
|
1780
|
+
const f = field;
|
|
1781
|
+
return Array.isArray(f.entryAgents) && f.entryAgents.length > 0 && f.entryAgents.every((e) => typeof e === "string");
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Get a package by ID.
|
|
1785
|
+
*/
|
|
1786
|
+
async getPackage(packageId) {
|
|
1787
|
+
const packages = await this.discoverPackages();
|
|
1788
|
+
return packages.find((p) => p.packageId === packageId) ?? null;
|
|
1789
|
+
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Create a package signature from a discovered package.
|
|
1792
|
+
*
|
|
1793
|
+
* Note: packedAt is set to current time since it's no longer
|
|
1794
|
+
* stored in a manifest file.
|
|
1795
|
+
*/
|
|
1796
|
+
static createSignature(pkg) {
|
|
1797
|
+
return {
|
|
1798
|
+
packageId: pkg.packageId,
|
|
1799
|
+
version: pkg.version,
|
|
1800
|
+
source: pkg.source,
|
|
1801
|
+
packedAt: Date.now()
|
|
1802
|
+
};
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
async function discoverPackages(rootDir) {
|
|
1806
|
+
const service = new PackageDiscoveryService({ rootDir });
|
|
1807
|
+
return service.discoverPackages();
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
// src/packing/unpacking-service.ts
|
|
1811
|
+
var TYPE_TO_DIR = {
|
|
1812
|
+
agent: "agents",
|
|
1813
|
+
prompt: "prompts",
|
|
1814
|
+
tool: "tools",
|
|
1815
|
+
model: "models",
|
|
1816
|
+
hook: "hooks"
|
|
1817
|
+
};
|
|
1818
|
+
var UnpackingService = class {
|
|
1819
|
+
/**
|
|
1820
|
+
* Analyze a package to discover what can be unpacked.
|
|
1821
|
+
*
|
|
1822
|
+
* @param packageId - Package ID to analyze
|
|
1823
|
+
* @param rootDir - Root directory of the agents workspace
|
|
1824
|
+
* @returns Analysis result with items that can be unpacked
|
|
1825
|
+
*/
|
|
1826
|
+
async analyzeUnpack(packageId, rootDir) {
|
|
1827
|
+
const analysis = {
|
|
1828
|
+
packageId,
|
|
1829
|
+
version: "",
|
|
1830
|
+
source: "local",
|
|
1831
|
+
canUnpack: false,
|
|
1832
|
+
items: [],
|
|
1833
|
+
warnings: [],
|
|
1834
|
+
errors: []
|
|
1835
|
+
};
|
|
1836
|
+
try {
|
|
1837
|
+
const pkg = await this.resolvePackage(packageId, rootDir);
|
|
1838
|
+
if (!pkg) {
|
|
1839
|
+
analysis.errors.push(`Package not found: ${packageId}`);
|
|
1840
|
+
return analysis;
|
|
1841
|
+
}
|
|
1842
|
+
analysis.version = pkg.version;
|
|
1843
|
+
analysis.source = pkg.source;
|
|
1844
|
+
const indexPath = path2.join(pkg.path, "dist", "index.js");
|
|
1845
|
+
if (!fs2.existsSync(indexPath)) {
|
|
1846
|
+
analysis.errors.push(`Package index not found: ${indexPath}`);
|
|
1847
|
+
return analysis;
|
|
1848
|
+
}
|
|
1849
|
+
const indexContent = fs2.readFileSync(indexPath, "utf-8");
|
|
1850
|
+
const registryItems = this.parseIndexExports(indexContent);
|
|
1851
|
+
const availableItems = /* @__PURE__ */ new Map();
|
|
1852
|
+
for (const item of registryItems) {
|
|
1853
|
+
availableItems.set(`${item.type}:${item.name}`, item);
|
|
1854
|
+
}
|
|
1855
|
+
const agentsDir = path2.join(rootDir, "agents");
|
|
1856
|
+
const itemsWithRelations = [];
|
|
1857
|
+
for (const item of registryItems) {
|
|
1858
|
+
const targetPath = path2.join(agentsDir, TYPE_TO_DIR[item.type], `${item.name}.ts`);
|
|
1859
|
+
const sourcePath = path2.join(pkg.path, "dist", TYPE_TO_DIR[item.type], `${item.name}.js`);
|
|
1860
|
+
const existsGlobally = this.fileExists(targetPath);
|
|
1861
|
+
const sourceExists = fs2.existsSync(sourcePath);
|
|
1862
|
+
if (!sourceExists) {
|
|
1863
|
+
analysis.warnings.push(`Source file not found for ${item.type} "${item.name}": ${sourcePath}`);
|
|
1864
|
+
continue;
|
|
1865
|
+
}
|
|
1866
|
+
const bundledCode = fs2.readFileSync(sourcePath, "utf-8");
|
|
1867
|
+
const children = this.discoverRelationships(item.type, item.name, bundledCode, availableItems);
|
|
1868
|
+
itemsWithRelations.push({
|
|
1869
|
+
name: item.name,
|
|
1870
|
+
type: item.type,
|
|
1871
|
+
targetPath,
|
|
1872
|
+
existsGlobally,
|
|
1873
|
+
action: existsGlobally ? "skip" : "generate"
|
|
1874
|
+
});
|
|
1875
|
+
for (const child of children) {
|
|
1876
|
+
const childTargetPath = path2.join(agentsDir, TYPE_TO_DIR[child.type], `${child.name}.ts`);
|
|
1877
|
+
const childSourcePath = path2.join(pkg.path, "dist", TYPE_TO_DIR[child.type], `${child.name}.js`);
|
|
1878
|
+
const childExists = this.fileExists(childTargetPath);
|
|
1879
|
+
const childSourceExists = fs2.existsSync(childSourcePath);
|
|
1880
|
+
if (!childSourceExists) {
|
|
1881
|
+
continue;
|
|
1882
|
+
}
|
|
1883
|
+
itemsWithRelations.push({
|
|
1884
|
+
name: child.name,
|
|
1885
|
+
type: child.type,
|
|
1886
|
+
targetPath: childTargetPath,
|
|
1887
|
+
existsGlobally: childExists,
|
|
1888
|
+
action: childExists ? "skip" : "generate",
|
|
1889
|
+
parentKey: `${item.type}:${item.name}`
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
analysis.items = itemsWithRelations;
|
|
1894
|
+
const itemsToGenerate = analysis.items.filter((i) => i.action === "generate");
|
|
1895
|
+
if (itemsToGenerate.length === 0 && analysis.items.length > 0) {
|
|
1896
|
+
analysis.warnings.push("All items already exist in the global namespace. Nothing to unpack.");
|
|
1897
|
+
}
|
|
1898
|
+
analysis.canUnpack = itemsToGenerate.length > 0;
|
|
1899
|
+
} catch (error) {
|
|
1900
|
+
analysis.errors.push(error instanceof Error ? error.message : String(error));
|
|
1901
|
+
}
|
|
1902
|
+
return analysis;
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Discover relationships from a bundled file.
|
|
1906
|
+
* Returns child items that this item references.
|
|
1907
|
+
*/
|
|
1908
|
+
discoverRelationships(type, name, bundledCode, availableItems) {
|
|
1909
|
+
const children = [];
|
|
1910
|
+
if (type === "agent") {
|
|
1911
|
+
const prompts = extractAgentPrompts(bundledCode);
|
|
1912
|
+
if (prompts.sideA && availableItems.has(`prompt:${prompts.sideA}`)) {
|
|
1913
|
+
children.push({ type: "prompt", name: prompts.sideA });
|
|
1914
|
+
}
|
|
1915
|
+
if (prompts.sideB && availableItems.has(`prompt:${prompts.sideB}`)) {
|
|
1916
|
+
children.push({ type: "prompt", name: prompts.sideB });
|
|
1917
|
+
}
|
|
1918
|
+
} else if (type === "prompt") {
|
|
1919
|
+
const toolsResult = extractPromptTools(bundledCode);
|
|
1920
|
+
for (const toolName of toolsResult.tools) {
|
|
1921
|
+
if (availableItems.has(`tool:${toolName}`)) {
|
|
1922
|
+
children.push({ type: "tool", name: toolName });
|
|
1923
|
+
} else if (availableItems.has(`agent:${toolName}`)) {
|
|
1924
|
+
children.push({ type: "agent", name: toolName });
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
const model = extractPromptModel(bundledCode);
|
|
1928
|
+
if (model && availableItems.has(`model:${model}`)) {
|
|
1929
|
+
children.push({ type: "model", name: model });
|
|
1930
|
+
}
|
|
1931
|
+
} else if (type === "tool") {
|
|
1932
|
+
const usesResult = extractToolUses(bundledCode);
|
|
1933
|
+
for (const useName of usesResult.uses) {
|
|
1934
|
+
const colonIndex = useName.indexOf(":");
|
|
1935
|
+
if (colonIndex > 0) {
|
|
1936
|
+
const agentName = useName.substring(0, colonIndex);
|
|
1937
|
+
if (availableItems.has(`agent:${agentName}`)) {
|
|
1938
|
+
children.push({ type: "agent", name: agentName });
|
|
1939
|
+
}
|
|
1940
|
+
} else {
|
|
1941
|
+
if (availableItems.has(`tool:${useName}`)) {
|
|
1942
|
+
children.push({ type: "tool", name: useName });
|
|
1943
|
+
} else if (availableItems.has(`prompt:${useName}`)) {
|
|
1944
|
+
children.push({ type: "prompt", name: useName });
|
|
1945
|
+
} else if (availableItems.has(`agent:${useName}`)) {
|
|
1946
|
+
children.push({ type: "agent", name: useName });
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
return children;
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Unpack a packed agent package by transforming bundled JS back to TypeScript.
|
|
1955
|
+
*
|
|
1956
|
+
* @param options - Unpacking options
|
|
1957
|
+
* @returns Result of the unpacking operation
|
|
1958
|
+
*/
|
|
1959
|
+
async unpack(options) {
|
|
1960
|
+
const { packageId, rootDir, deletePackage = false, itemSelections } = options;
|
|
1961
|
+
const result = {
|
|
1962
|
+
success: false,
|
|
1963
|
+
packageId,
|
|
1964
|
+
filesGenerated: [],
|
|
1965
|
+
filesSkipped: [],
|
|
1966
|
+
packageDeleted: false,
|
|
1967
|
+
warnings: []
|
|
1968
|
+
};
|
|
1969
|
+
try {
|
|
1970
|
+
const analysis = await this.analyzeUnpack(packageId, rootDir);
|
|
1971
|
+
if (analysis.errors.length > 0) {
|
|
1972
|
+
result.error = analysis.errors.join("\n");
|
|
1973
|
+
return result;
|
|
1974
|
+
}
|
|
1975
|
+
result.warnings.push(...analysis.warnings);
|
|
1976
|
+
const pkg = await this.resolvePackage(packageId, rootDir);
|
|
1977
|
+
if (!pkg) {
|
|
1978
|
+
result.error = `Package not found: ${packageId}`;
|
|
1979
|
+
return result;
|
|
1980
|
+
}
|
|
1981
|
+
const itemsToProcess = this.applySelections(analysis.items, itemSelections);
|
|
1982
|
+
const pkgJsonPath = path2.join(pkg.path, "package.json");
|
|
1983
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
1984
|
+
let author = "";
|
|
1985
|
+
if (typeof pkgJson.author === "string") {
|
|
1986
|
+
author = pkgJson.author;
|
|
1987
|
+
} else if (pkgJson.author?.name) {
|
|
1988
|
+
author = pkgJson.author.name;
|
|
1989
|
+
}
|
|
1990
|
+
const agentMetadata = {
|
|
1991
|
+
packageName: pkgJson.name || void 0,
|
|
1992
|
+
version: pkgJson.version || void 0,
|
|
1993
|
+
author: author || void 0,
|
|
1994
|
+
license: pkgJson.license || void 0
|
|
1995
|
+
};
|
|
1996
|
+
const processedItems = /* @__PURE__ */ new Set();
|
|
1997
|
+
for (const item of itemsToProcess) {
|
|
1998
|
+
const itemKey = `${item.type}:${item.name}`;
|
|
1999
|
+
if (processedItems.has(itemKey)) {
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
processedItems.add(itemKey);
|
|
2003
|
+
if (item.action === "skip") {
|
|
2004
|
+
result.filesSkipped.push(item.targetPath);
|
|
2005
|
+
continue;
|
|
2006
|
+
}
|
|
2007
|
+
try {
|
|
2008
|
+
const sourcePath = path2.join(pkg.path, "dist", TYPE_TO_DIR[item.type], `${item.name}.js`);
|
|
2009
|
+
const bundledCode = fs2.readFileSync(sourcePath, "utf-8");
|
|
2010
|
+
let tsCode = transformBundledJs(bundledCode);
|
|
2011
|
+
if (item.type === "agent") {
|
|
2012
|
+
tsCode = injectAgentMetadata(tsCode, agentMetadata);
|
|
2013
|
+
}
|
|
2014
|
+
const dir = path2.dirname(item.targetPath);
|
|
2015
|
+
if (!fs2.existsSync(dir)) {
|
|
2016
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
2017
|
+
}
|
|
2018
|
+
fs2.writeFileSync(item.targetPath, tsCode);
|
|
2019
|
+
result.filesGenerated.push(item.targetPath);
|
|
2020
|
+
} catch (error) {
|
|
2021
|
+
result.warnings.push(
|
|
2022
|
+
`Failed to generate ${item.type} "${item.name}": ${error instanceof Error ? error.message : String(error)}`
|
|
2023
|
+
);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
if (deletePackage && pkg.source === "local") {
|
|
2027
|
+
try {
|
|
2028
|
+
this.deleteDirectory(pkg.path);
|
|
2029
|
+
result.packageDeleted = true;
|
|
2030
|
+
} catch (error) {
|
|
2031
|
+
result.warnings.push(
|
|
2032
|
+
`Failed to delete package: ${error instanceof Error ? error.message : String(error)}`
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
2035
|
+
} else if (deletePackage && pkg.source === "npm") {
|
|
2036
|
+
result.warnings.push("Cannot delete npm packages. Use npm uninstall instead.");
|
|
2037
|
+
}
|
|
2038
|
+
result.success = true;
|
|
2039
|
+
} catch (error) {
|
|
2040
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
2041
|
+
}
|
|
2042
|
+
return result;
|
|
2043
|
+
}
|
|
2044
|
+
/**
|
|
2045
|
+
* Parse the index.js file to extract registry items.
|
|
2046
|
+
*
|
|
2047
|
+
* Looks for patterns like:
|
|
2048
|
+
* ```javascript
|
|
2049
|
+
* export const agents = {
|
|
2050
|
+
* support_agent: async () => (await import('./agents/support_agent.js')).default,
|
|
2051
|
+
* };
|
|
2052
|
+
* ```
|
|
2053
|
+
*/
|
|
2054
|
+
parseIndexExports(indexContent) {
|
|
2055
|
+
const sourceFile = ts.createSourceFile(
|
|
2056
|
+
"index.js",
|
|
2057
|
+
indexContent,
|
|
2058
|
+
ts.ScriptTarget.ESNext,
|
|
2059
|
+
true
|
|
2060
|
+
);
|
|
2061
|
+
const items = [];
|
|
2062
|
+
const registryTypes = ["agent", "prompt", "tool", "model", "hook"];
|
|
2063
|
+
function visit(node) {
|
|
2064
|
+
if (ts.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
2065
|
+
for (const decl of node.declarationList.declarations) {
|
|
2066
|
+
if (!ts.isIdentifier(decl.name)) continue;
|
|
2067
|
+
const varName = decl.name.text;
|
|
2068
|
+
let itemType = null;
|
|
2069
|
+
for (const type of registryTypes) {
|
|
2070
|
+
if (varName === TYPE_TO_DIR[type]) {
|
|
2071
|
+
itemType = type;
|
|
2072
|
+
break;
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
if (itemType && decl.initializer && ts.isObjectLiteralExpression(decl.initializer)) {
|
|
2076
|
+
for (const prop of decl.initializer.properties) {
|
|
2077
|
+
if (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) {
|
|
2078
|
+
let name;
|
|
2079
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
2080
|
+
if (ts.isIdentifier(prop.name)) {
|
|
2081
|
+
name = prop.name.text;
|
|
2082
|
+
} else if (ts.isStringLiteral(prop.name)) {
|
|
2083
|
+
name = prop.name.text;
|
|
2084
|
+
}
|
|
2085
|
+
} else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
2086
|
+
name = prop.name.text;
|
|
2087
|
+
}
|
|
2088
|
+
if (name) {
|
|
2089
|
+
items.push({ name, type: itemType });
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
ts.forEachChild(node, visit);
|
|
2097
|
+
}
|
|
2098
|
+
visit(sourceFile);
|
|
2099
|
+
return items;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Resolve a package identifier to a discovered package.
|
|
2103
|
+
*/
|
|
2104
|
+
async resolvePackage(pkgIdentifier, rootDir) {
|
|
2105
|
+
if (pkgIdentifier.startsWith("/") || pkgIdentifier.startsWith("./")) {
|
|
2106
|
+
const absolutePath = path2.isAbsolute(pkgIdentifier) ? pkgIdentifier : path2.join(rootDir, pkgIdentifier);
|
|
2107
|
+
const pkgJsonPath2 = path2.join(absolutePath, "package.json");
|
|
2108
|
+
if (fs2.existsSync(pkgJsonPath2)) {
|
|
2109
|
+
try {
|
|
2110
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath2, "utf-8"));
|
|
2111
|
+
if (pkgJson.standardagent?.entryAgents) {
|
|
2112
|
+
return {
|
|
2113
|
+
packageId: pkgJson.name || path2.basename(absolutePath),
|
|
2114
|
+
version: pkgJson.version || "0.0.0",
|
|
2115
|
+
source: "local",
|
|
2116
|
+
path: absolutePath,
|
|
2117
|
+
entryAgents: pkgJson.standardagent.entryAgents
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
} catch {
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
const packedDir = path2.join(rootDir, "agents", "packed", pkgIdentifier);
|
|
2126
|
+
const pkgJsonPath = path2.join(packedDir, "package.json");
|
|
2127
|
+
if (fs2.existsSync(pkgJsonPath)) {
|
|
2128
|
+
try {
|
|
2129
|
+
const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
|
|
2130
|
+
if (pkgJson.standardagent?.entryAgents) {
|
|
2131
|
+
return {
|
|
2132
|
+
packageId: pkgJson.name || pkgIdentifier,
|
|
2133
|
+
version: pkgJson.version || "0.0.0",
|
|
2134
|
+
source: "local",
|
|
2135
|
+
path: packedDir,
|
|
2136
|
+
entryAgents: pkgJson.standardagent.entryAgents
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
} catch {
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
const discovery = new PackageDiscoveryService({ rootDir });
|
|
2143
|
+
const packages = await discovery.discoverPackages();
|
|
2144
|
+
const pkg = packages.find(
|
|
2145
|
+
(p) => p.packageId === pkgIdentifier || p.path.endsWith(`node_modules/${pkgIdentifier}`)
|
|
2146
|
+
);
|
|
2147
|
+
return pkg || null;
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2150
|
+
* Apply user selections to items.
|
|
2151
|
+
*/
|
|
2152
|
+
applySelections(items, selections) {
|
|
2153
|
+
if (!selections || selections.length === 0) {
|
|
2154
|
+
return items;
|
|
2155
|
+
}
|
|
2156
|
+
return items.map((item) => {
|
|
2157
|
+
const selection = selections.find(
|
|
2158
|
+
(s) => s.name === item.name && s.type === item.type
|
|
2159
|
+
);
|
|
2160
|
+
if (selection) {
|
|
2161
|
+
return { ...item, action: selection.action };
|
|
2162
|
+
}
|
|
2163
|
+
return item;
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Check if a file exists.
|
|
2168
|
+
*/
|
|
2169
|
+
fileExists(filePath) {
|
|
2170
|
+
if (fs2.existsSync(filePath)) {
|
|
2171
|
+
return true;
|
|
2172
|
+
}
|
|
2173
|
+
const withoutExt = filePath.replace(/\.(ts|js)$/, "");
|
|
2174
|
+
return fs2.existsSync(`${withoutExt}.ts`) || fs2.existsSync(`${withoutExt}.js`);
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* Recursively delete a directory.
|
|
2178
|
+
*/
|
|
2179
|
+
deleteDirectory(dirPath) {
|
|
2180
|
+
if (fs2.existsSync(dirPath)) {
|
|
2181
|
+
fs2.rmSync(dirPath, { recursive: true, force: true });
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* List available packed packages.
|
|
2186
|
+
*/
|
|
2187
|
+
async listPackages(rootDir) {
|
|
2188
|
+
const discovery = new PackageDiscoveryService({ rootDir });
|
|
2189
|
+
const packages = await discovery.discoverPackages();
|
|
2190
|
+
return packages.map((pkg) => ({
|
|
2191
|
+
packageId: pkg.packageId,
|
|
2192
|
+
version: pkg.version,
|
|
2193
|
+
source: pkg.source,
|
|
2194
|
+
entryAgents: pkg.entryAgents,
|
|
2195
|
+
path: pkg.path
|
|
2196
|
+
}));
|
|
2197
|
+
}
|
|
2198
|
+
};
|
|
2199
|
+
|
|
2200
|
+
export { PackageDiscoveryService, PackingService, UnpackingService, discoverPackages };
|
|
2201
|
+
//# sourceMappingURL=packing.js.map
|
|
2202
|
+
//# sourceMappingURL=packing.js.map
|