@standardagents/builder 0.12.9 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as fs2 from 'fs';
2
- import fs2__default from 'fs';
1
+ import * as fs4 from 'fs';
2
+ import fs4__default from 'fs';
3
3
  import * as path8 from 'path';
4
4
  import path8__default from 'path';
5
5
  import { fileURLToPath } from 'url';
@@ -40,15 +40,15 @@ function extractSchemaFields(content) {
40
40
  }
41
41
  function scanPromptsWithSchemas(dir) {
42
42
  const results = [];
43
- if (!fs2__default.existsSync(dir)) {
43
+ if (!fs4__default.existsSync(dir)) {
44
44
  return results;
45
45
  }
46
46
  try {
47
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
47
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
48
48
  for (const entry of entries) {
49
49
  if (entry.isFile() && entry.name.endsWith(".ts")) {
50
50
  const filePath = path8__default.join(dir, entry.name);
51
- const content = fs2__default.readFileSync(filePath, "utf-8");
51
+ const content = fs4__default.readFileSync(filePath, "utf-8");
52
52
  const nameMatch = content.match(/name:\s*['"]([^'"]+)['"]/);
53
53
  if (nameMatch) {
54
54
  const name = nameMatch[1];
@@ -64,15 +64,15 @@ function scanPromptsWithSchemas(dir) {
64
64
  }
65
65
  function scanAgentsWithSideA(dir) {
66
66
  const results = [];
67
- if (!fs2__default.existsSync(dir)) {
67
+ if (!fs4__default.existsSync(dir)) {
68
68
  return results;
69
69
  }
70
70
  try {
71
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
71
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
72
72
  for (const entry of entries) {
73
73
  if (entry.isFile() && entry.name.endsWith(".ts")) {
74
74
  const filePath = path8__default.join(dir, entry.name);
75
- const content = fs2__default.readFileSync(filePath, "utf-8");
75
+ const content = fs4__default.readFileSync(filePath, "utf-8");
76
76
  const nameMatch = content.match(/name:\s*['"]([^'"]+)['"]/);
77
77
  if (nameMatch) {
78
78
  const name = nameMatch[1];
@@ -92,15 +92,15 @@ function scanAgentsWithSideA(dir) {
92
92
  }
93
93
  function scanForNames(dir, useFilename = false) {
94
94
  const names = [];
95
- if (!fs2__default.existsSync(dir)) {
95
+ if (!fs4__default.existsSync(dir)) {
96
96
  return names;
97
97
  }
98
98
  try {
99
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
99
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
100
100
  for (const entry of entries) {
101
101
  if (entry.isFile() && entry.name.endsWith(".ts")) {
102
102
  const filePath = path8__default.join(dir, entry.name);
103
- const content = fs2__default.readFileSync(filePath, "utf-8");
103
+ const content = fs4__default.readFileSync(filePath, "utf-8");
104
104
  if (useFilename) {
105
105
  const toolName = entry.name.replace(/\.ts$/, "");
106
106
  if (content.includes("defineTool")) {
@@ -121,18 +121,18 @@ function scanForNames(dir, useFilename = false) {
121
121
  }
122
122
  function scanHooksForIds(dir) {
123
123
  const hookIds = [];
124
- if (!fs2__default.existsSync(dir)) {
124
+ if (!fs4__default.existsSync(dir)) {
125
125
  return hookIds;
126
126
  }
127
127
  try {
128
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
128
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
129
129
  for (const entry of entries) {
130
130
  if (entry.isFile() && entry.name.endsWith(".ts")) {
131
131
  if (entry.name === "index.ts") {
132
132
  continue;
133
133
  }
134
134
  const filePath = path8__default.join(dir, entry.name);
135
- const content = fs2__default.readFileSync(filePath, "utf-8");
135
+ const content = fs4__default.readFileSync(filePath, "utf-8");
136
136
  const idMatch = content.match(/defineHook\s*\(\s*\{[^}]*id:\s*['"]([^'"]+)['"]/s);
137
137
  if (idMatch) {
138
138
  hookIds.push(idMatch[1]);
@@ -350,6 +350,8 @@ declare module 'virtual:@standardagents/builder' {
350
350
  agent_id: string;
351
351
  user_id: string | null;
352
352
  tags: string[];
353
+ parent?: string | null;
354
+ terminated?: number | null;
353
355
  created_at: number;
354
356
  };
355
357
  agent: {
@@ -403,11 +405,48 @@ declare module 'virtual:@standardagents/builder' {
403
405
  initial_messages?: any[],
404
406
  data?: any
405
407
  ): Promise<Response>;
408
+ executeBlocking(
409
+ threadId: string,
410
+ agentId: string,
411
+ initial_messages?: any[],
412
+ data?: any
413
+ ): Promise<{
414
+ status: 'success' | 'error';
415
+ result?: string;
416
+ error?: string;
417
+ attachments?: unknown[];
418
+ }>;
406
419
  sendMessage(
407
420
  threadId: string,
408
421
  content: string,
409
422
  role?: string
410
423
  ): Promise<Response>;
424
+ queueMessage(
425
+ threadId: string,
426
+ message: {
427
+ role: 'user' | 'assistant';
428
+ content: string;
429
+ attachments?: unknown[];
430
+ silent?: boolean;
431
+ metadata?: Record<string, unknown>;
432
+ }
433
+ ): Promise<void>;
434
+ getChildrenRegistry(threadId: string): Promise<Array<{
435
+ reference: string;
436
+ name: string;
437
+ description: string;
438
+ status: string;
439
+ }>>;
440
+ upsertChildRegistry(threadId: string, entry: {
441
+ reference: string;
442
+ name: string;
443
+ description: string;
444
+ status: string;
445
+ }): Promise<void>;
446
+ updateChildRegistryStatus(threadId: string, reference: string, status: string): Promise<void>;
447
+ removeChildRegistry(threadId: string, reference: string): Promise<void>;
448
+ getTerminated(threadId: string): Promise<number | null>;
449
+ terminateThread(threadId: string): Promise<{ success: boolean; terminated: number }>;
411
450
  stop(): Promise<Response>;
412
451
  shouldStop(): Promise<boolean>;
413
452
 
@@ -468,6 +507,10 @@ declare module 'virtual:@standardagents/builder' {
468
507
  agent_name: string;
469
508
  user_id: string | null;
470
509
  tags: string[] | null;
510
+ tenvs?: Record<string, unknown> | null;
511
+ properties?: Record<string, unknown> | null;
512
+ parent: string | null;
513
+ terminated: number | null;
471
514
  created_at: number;
472
515
  }
473
516
 
@@ -528,6 +571,9 @@ declare module 'virtual:@standardagents/builder' {
528
571
  agent_name: string;
529
572
  user_id?: string;
530
573
  tags?: string[];
574
+ tenvs?: Record<string, unknown>;
575
+ properties?: Record<string, unknown>;
576
+ parent?: string;
531
577
  }): Promise<ThreadRegistryEntry>;
532
578
  getThread(id: string): Promise<ThreadRegistryEntry | null>;
533
579
  listThreads(params?: {
@@ -539,6 +585,7 @@ declare module 'virtual:@standardagents/builder' {
539
585
  limit?: number;
540
586
  offset?: number;
541
587
  }): Promise<{ threads: ThreadRegistryEntry[]; total: number }>;
588
+ getThreadTreeIds(rootThreadId: string): Promise<string[]>;
542
589
  deleteThread(id: string): Promise<boolean>;
543
590
  updateThreadAgent(id: string, agent_name: string): Promise<boolean>;
544
591
  updateThread(id: string, params: UpdateThreadParams): Promise<ThreadRegistryEntry | null>;
@@ -679,35 +726,35 @@ declare module 'virtual:@standardagents/router' {
679
726
  `;
680
727
  }
681
728
  function ensureDir(dir) {
682
- if (!fs2__default.existsSync(dir)) {
683
- fs2__default.mkdirSync(dir, { recursive: true });
729
+ if (!fs4__default.existsSync(dir)) {
730
+ fs4__default.mkdirSync(dir, { recursive: true });
684
731
  }
685
732
  }
686
733
  function generateTypes(config) {
687
734
  ensureDir(config.outputDir);
688
735
  const typesContent = generateTypesContent(config);
689
- fs2__default.writeFileSync(path8__default.join(config.outputDir, "types.d.ts"), typesContent);
736
+ fs4__default.writeFileSync(path8__default.join(config.outputDir, "types.d.ts"), typesContent);
690
737
  const virtualModuleContent = generateVirtualModuleContent();
691
- fs2__default.writeFileSync(path8__default.join(config.outputDir, "virtual-module.d.ts"), virtualModuleContent);
692
- fs2__default.writeFileSync(path8__default.join(config.outputDir, "tsconfig.json"), TSCONFIG_CONTENT);
693
- fs2__default.writeFileSync(path8__default.join(config.outputDir, ".gitignore"), "*\n");
738
+ fs4__default.writeFileSync(path8__default.join(config.outputDir, "virtual-module.d.ts"), virtualModuleContent);
739
+ fs4__default.writeFileSync(path8__default.join(config.outputDir, "tsconfig.json"), TSCONFIG_CONTENT);
740
+ fs4__default.writeFileSync(path8__default.join(config.outputDir, ".gitignore"), "*\n");
694
741
  }
695
742
  function needsRegeneration(config) {
696
743
  const typesPath = path8__default.join(config.outputDir, "types.d.ts");
697
- if (!fs2__default.existsSync(typesPath)) {
744
+ if (!fs4__default.existsSync(typesPath)) {
698
745
  return true;
699
746
  }
700
- const typesMtime = fs2__default.statSync(typesPath).mtime;
747
+ const typesMtime = fs4__default.statSync(typesPath).mtime;
701
748
  const dirs = [config.modelsDir, config.promptsDir, config.agentsDir, config.toolsDir, config.hooksDir];
702
749
  for (const dir of dirs) {
703
- if (!fs2__default.existsSync(dir)) {
750
+ if (!fs4__default.existsSync(dir)) {
704
751
  continue;
705
752
  }
706
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
753
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
707
754
  for (const entry of entries) {
708
755
  if (entry.isFile() && entry.name.endsWith(".ts")) {
709
756
  const filePath = path8__default.join(dir, entry.name);
710
- const fileMtime = fs2__default.statSync(filePath).mtime;
757
+ const fileMtime = fs4__default.statSync(filePath).mtime;
711
758
  if (fileMtime > typesMtime) {
712
759
  return true;
713
760
  }
@@ -982,10 +1029,18 @@ function generatePromptFile(data) {
982
1029
  if (data.toolChoice && data.toolChoice !== "auto") {
983
1030
  lines.push(` toolChoice: '${data.toolChoice}',`);
984
1031
  }
1032
+ if (data.variables && data.variables.length > 0) {
1033
+ const variablesCode = formatVariablesArray(data.variables);
1034
+ lines.push(` variables: ${variablesCode},`);
1035
+ }
985
1036
  if (data.tools && data.tools.length > 0) {
986
1037
  const toolsCode = formatToolsArray(data.tools);
987
1038
  lines.push(` tools: ${toolsCode},`);
988
1039
  }
1040
+ const promptEnv = data.env ?? (data.tenvs || void 0);
1041
+ if (promptEnv && Object.keys(promptEnv).length > 0) {
1042
+ lines.push(` env: ${JSON.stringify(promptEnv)},`);
1043
+ }
989
1044
  if (data.reasoning && hasNonNullProperties(data.reasoning)) {
990
1045
  const reasoningCode = formatReasoningConfig(data.reasoning);
991
1046
  lines.push(` reasoning: ${reasoningCode},`);
@@ -1020,6 +1075,30 @@ function formatToolsArray(tools) {
1020
1075
  ${indented}
1021
1076
  ]`;
1022
1077
  }
1078
+ function formatVariablesArray(variables) {
1079
+ const normalized = variables.filter((entry) => typeof entry.name === "string" && entry.name.trim().length > 0).map((entry) => ({
1080
+ name: entry.name.trim(),
1081
+ type: entry.type === "secret" ? "secret" : "text",
1082
+ required: !!entry.required,
1083
+ description: typeof entry.description === "string" ? entry.description : ""
1084
+ }));
1085
+ if (normalized.length === 0) return "[]";
1086
+ const formatted = normalized.map((entry) => {
1087
+ const parts = [
1088
+ `name: '${escapeString2(entry.name)}'`,
1089
+ `type: '${entry.type}'`,
1090
+ `required: ${entry.required}`,
1091
+ `description: '${escapeString2(entry.description)}'`
1092
+ ];
1093
+ return `{ ${parts.join(", ")} }`;
1094
+ });
1095
+ if (formatted.length === 1) {
1096
+ return `[${formatted[0]}]`;
1097
+ }
1098
+ return `[
1099
+ ${formatted.join(",\n ")}
1100
+ ]`;
1101
+ }
1023
1102
  function formatToolConfig(config) {
1024
1103
  const parts = [];
1025
1104
  parts.push(`name: '${escapeString2(config.name)}'`);
@@ -1038,8 +1117,56 @@ function formatToolConfig(config) {
1038
1117
  if (config.init_attachments_property !== void 0 && config.init_attachments_property !== null) {
1039
1118
  parts.push(`initAttachmentsProperty: '${escapeString2(config.init_attachments_property)}'`);
1040
1119
  }
1041
- if (config.tenvs && Object.keys(config.tenvs).length > 0) {
1042
- parts.push(`tenvs: ${JSON.stringify(config.tenvs)}`);
1120
+ if (config.init_agent_name_property !== void 0 && config.init_agent_name_property !== null) {
1121
+ parts.push(`initAgentNameProperty: '${escapeString2(config.init_agent_name_property)}'`);
1122
+ }
1123
+ if (config.blocking !== void 0 && config.blocking !== true) {
1124
+ parts.push(`blocking: ${config.blocking}`);
1125
+ }
1126
+ if (config.optional !== void 0 && config.optional !== null && config.optional !== "") {
1127
+ parts.push(`optional: '${escapeString2(config.optional)}'`);
1128
+ }
1129
+ if (config.immediate !== void 0) {
1130
+ if (typeof config.immediate === "boolean") {
1131
+ if (config.immediate) {
1132
+ parts.push(`immediate: true`);
1133
+ }
1134
+ } else if (config.immediate && typeof config.immediate === "object") {
1135
+ const immediateParts = [];
1136
+ if (config.immediate.name_env) {
1137
+ immediateParts.push(`nameEnv: '${escapeString2(config.immediate.name_env)}'`);
1138
+ }
1139
+ if (config.immediate.description_env) {
1140
+ immediateParts.push(`descriptionEnv: '${escapeString2(config.immediate.description_env)}'`);
1141
+ }
1142
+ if (config.immediate.scoped_env && config.immediate.scoped_env.length > 0) {
1143
+ const scoped = config.immediate.scoped_env.map((entry) => `'${escapeString2(entry)}'`).join(", ");
1144
+ immediateParts.push(`scopedEnv: [${scoped}]`);
1145
+ }
1146
+ parts.push(`immediate: { ${immediateParts.join(", ")} }`);
1147
+ }
1148
+ }
1149
+ if (config.resumable !== void 0) {
1150
+ if (config.resumable === false) {
1151
+ parts.push(`resumable: false`);
1152
+ } else if (config.resumable && typeof config.resumable === "object") {
1153
+ const resumableParts = [
1154
+ `receives_messages: '${config.resumable.receives_messages}'`
1155
+ ];
1156
+ if (config.resumable.max_instances !== void 0 && config.resumable.max_instances !== null) {
1157
+ resumableParts.push(`maxInstances: ${config.resumable.max_instances}`);
1158
+ }
1159
+ if (config.resumable.parent_communication !== void 0 && config.resumable.parent_communication !== null) {
1160
+ resumableParts.push(
1161
+ `parentCommunication: '${config.resumable.parent_communication}'`
1162
+ );
1163
+ }
1164
+ parts.push(`resumable: { ${resumableParts.join(", ")} }`);
1165
+ }
1166
+ }
1167
+ const env = config.env ?? (config.tenvs || void 0);
1168
+ if (env && Object.keys(env).length > 0) {
1169
+ parts.push(`env: ${JSON.stringify(env)}`);
1043
1170
  }
1044
1171
  return `{ ${parts.join(", ")} }`;
1045
1172
  }
@@ -1120,6 +1247,9 @@ function formatStructuredPrompt(parts) {
1120
1247
  } else if (part.type === "include") {
1121
1248
  const promptName = part.prompt || "";
1122
1249
  return ` { type: 'include', prompt: '${escapeString2(promptName)}' }`;
1250
+ } else if (part.type === "env") {
1251
+ const property = part.property || "";
1252
+ return ` { type: 'env', property: '${escapeString2(property)}' }`;
1123
1253
  }
1124
1254
  return ` // Unknown part type: ${part.type}`;
1125
1255
  });
@@ -1134,6 +1264,9 @@ function normalizePart(part) {
1134
1264
  if (part.type === "include") {
1135
1265
  return { type: "include", prompt: part.prompt || "" };
1136
1266
  }
1267
+ if (part.type === "env") {
1268
+ return { type: "env", property: part.property || part.value || "" };
1269
+ }
1137
1270
  if (part.type === "string") {
1138
1271
  return { type: "text", content: part.value || "" };
1139
1272
  }
@@ -1185,8 +1318,9 @@ function generateAgentFile(data) {
1185
1318
  if (data.toolDescription) {
1186
1319
  lines.push(` toolDescription: '${escapeString3(data.toolDescription)}',`);
1187
1320
  }
1188
- if (data.tenvs && Object.keys(data.tenvs).length > 0) {
1189
- lines.push(` tenvs: ${JSON.stringify(data.tenvs)},`);
1321
+ const env = data.env ?? (data.tenvs || void 0);
1322
+ if (env && Object.keys(env).length > 0) {
1323
+ lines.push(` env: ${JSON.stringify(env)},`);
1190
1324
  }
1191
1325
  lines.push(`});`);
1192
1326
  lines.push("");
@@ -1210,9 +1344,21 @@ function formatSideConfig(config) {
1210
1344
  if (config.maxSteps !== void 0) {
1211
1345
  parts.push(` maxSteps: ${config.maxSteps},`);
1212
1346
  }
1213
- if (config.endSessionTool) {
1347
+ if (config.sessionStop) {
1348
+ parts.push(` sessionStop: ${formatSessionBinding(config.sessionStop)},`);
1349
+ } else if (config.endSessionTool) {
1214
1350
  parts.push(` endSessionTool: '${escapeString3(config.endSessionTool)}',`);
1215
1351
  }
1352
+ if (config.sessionFail) {
1353
+ parts.push(` sessionFail: ${formatSessionBinding(config.sessionFail)},`);
1354
+ } else if (config.failSessionTool) {
1355
+ parts.push(` failSessionTool: '${escapeString3(config.failSessionTool)}',`);
1356
+ }
1357
+ if (config.sessionStatus) {
1358
+ parts.push(` sessionStatus: ${formatSessionBinding(config.sessionStatus)},`);
1359
+ } else if (config.statusTool) {
1360
+ parts.push(` statusTool: '${escapeString3(config.statusTool)}',`);
1361
+ }
1216
1362
  if (config.manualStopCondition) {
1217
1363
  parts.push(` manualStopCondition: ${config.manualStopCondition},`);
1218
1364
  }
@@ -1222,6 +1368,19 @@ function formatSideConfig(config) {
1222
1368
  function escapeString3(str) {
1223
1369
  return str.replace(/'/g, "\\'").replace(/\\/g, "\\\\");
1224
1370
  }
1371
+ function formatSessionBinding(binding) {
1372
+ if (typeof binding === "string") {
1373
+ return `'${escapeString3(binding)}'`;
1374
+ }
1375
+ const parts = [`name: '${escapeString3(binding.name)}'`];
1376
+ if (binding.messageProperty) {
1377
+ parts.push(`messageProperty: '${escapeString3(binding.messageProperty)}'`);
1378
+ }
1379
+ if (binding.attachmentsProperty) {
1380
+ parts.push(`attachmentsProperty: '${escapeString3(binding.attachmentsProperty)}'`);
1381
+ }
1382
+ return `{ ${parts.join(", ")} }`;
1383
+ }
1225
1384
 
1226
1385
  // src/sdk/persistence/index.ts
1227
1386
  var PROVIDER_PACKAGE_MAP = {
@@ -1240,15 +1399,15 @@ function getModelFilePath(modelsDir, name) {
1240
1399
  }
1241
1400
  function modelExists(modelsDir, name) {
1242
1401
  const filePath = getModelFilePath(modelsDir, name);
1243
- return fs2__default.existsSync(filePath);
1402
+ return fs4__default.existsSync(filePath);
1244
1403
  }
1245
1404
  async function saveModel(modelsDir, data, overwrite = false) {
1246
1405
  try {
1247
- if (!fs2__default.existsSync(modelsDir)) {
1248
- fs2__default.mkdirSync(modelsDir, { recursive: true });
1406
+ if (!fs4__default.existsSync(modelsDir)) {
1407
+ fs4__default.mkdirSync(modelsDir, { recursive: true });
1249
1408
  }
1250
1409
  const filePath = getModelFilePath(modelsDir, data.name);
1251
- if (!overwrite && fs2__default.existsSync(filePath)) {
1410
+ if (!overwrite && fs4__default.existsSync(filePath)) {
1252
1411
  return {
1253
1412
  success: false,
1254
1413
  error: `Model file already exists: ${filePath}. Use update to modify existing models.`
@@ -1265,7 +1424,7 @@ async function saveModel(modelsDir, data, overwrite = false) {
1265
1424
  providerName: providerInfo.name,
1266
1425
  providerPackage: providerInfo.package
1267
1426
  });
1268
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
1427
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1269
1428
  return {
1270
1429
  success: true,
1271
1430
  filePath
@@ -1280,13 +1439,13 @@ async function saveModel(modelsDir, data, overwrite = false) {
1280
1439
  async function deleteModel(modelsDir, name) {
1281
1440
  try {
1282
1441
  const filePath = getModelFilePath(modelsDir, name);
1283
- if (!fs2__default.existsSync(filePath)) {
1442
+ if (!fs4__default.existsSync(filePath)) {
1284
1443
  return {
1285
1444
  success: false,
1286
1445
  error: `Model file not found: ${filePath}`
1287
1446
  };
1288
1447
  }
1289
- await fs2__default.promises.unlink(filePath);
1448
+ await fs4__default.promises.unlink(filePath);
1290
1449
  return {
1291
1450
  success: true,
1292
1451
  filePath
@@ -1372,6 +1531,86 @@ function validateModelData(data) {
1372
1531
  }
1373
1532
  return Object.keys(errors).length > 0 ? errors : null;
1374
1533
  }
1534
+ function normalizeStringEnvRecord(value) {
1535
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1536
+ return void 0;
1537
+ }
1538
+ const normalized = {};
1539
+ for (const [key, entry] of Object.entries(value)) {
1540
+ if (!key) continue;
1541
+ if (entry === void 0 || entry === null || entry === "") continue;
1542
+ normalized[key] = String(entry);
1543
+ }
1544
+ return normalized;
1545
+ }
1546
+ function normalizeVariableDeclarations(value) {
1547
+ if (!Array.isArray(value)) {
1548
+ return void 0;
1549
+ }
1550
+ const declarations = value.filter((entry) => !!entry && typeof entry === "object").map((entry) => {
1551
+ const name = typeof entry.name === "string" ? entry.name.trim() : "";
1552
+ const description = typeof entry.description === "string" ? entry.description.trim() : "";
1553
+ return {
1554
+ name,
1555
+ type: entry.type === "secret" ? "secret" : "text",
1556
+ required: !!entry.required,
1557
+ description
1558
+ };
1559
+ }).filter((entry) => entry.name.length > 0);
1560
+ return declarations;
1561
+ }
1562
+ function normalizeStringArray(value) {
1563
+ if (!Array.isArray(value)) return void 0;
1564
+ const normalized = value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
1565
+ return normalized;
1566
+ }
1567
+ function normalizePromptToolConfig(tool) {
1568
+ const next = { ...tool };
1569
+ const toolEnv = normalizeStringEnvRecord(next.env ?? next.tenvs);
1570
+ if (toolEnv) {
1571
+ next.env = toolEnv;
1572
+ }
1573
+ delete next.tenvs;
1574
+ if (typeof next.init_agent_name_property === "string") {
1575
+ next.initAgentNameProperty = next.init_agent_name_property;
1576
+ }
1577
+ delete next.init_agent_name_property;
1578
+ if (next.immediate && typeof next.immediate === "object" && !Array.isArray(next.immediate)) {
1579
+ const immediate = { ...next.immediate };
1580
+ if (typeof immediate.name_env === "string") {
1581
+ immediate.nameEnv = immediate.name_env;
1582
+ }
1583
+ if (typeof immediate.description_env === "string") {
1584
+ immediate.descriptionEnv = immediate.description_env;
1585
+ }
1586
+ const scopedEnv = normalizeStringArray(immediate.scoped_env);
1587
+ if (scopedEnv) {
1588
+ immediate.scopedEnv = scopedEnv;
1589
+ }
1590
+ delete immediate.name_env;
1591
+ delete immediate.description_env;
1592
+ delete immediate.scoped_env;
1593
+ next.immediate = immediate;
1594
+ }
1595
+ if (next.resumable && typeof next.resumable === "object" && !Array.isArray(next.resumable)) {
1596
+ const resumable = { ...next.resumable };
1597
+ if (typeof resumable.max_instances === "number") {
1598
+ resumable.maxInstances = resumable.max_instances;
1599
+ } else if (typeof resumable.max_instances === "string" && resumable.max_instances.trim() !== "") {
1600
+ const parsed = Number(resumable.max_instances);
1601
+ if (!Number.isNaN(parsed)) {
1602
+ resumable.maxInstances = parsed;
1603
+ }
1604
+ }
1605
+ if (typeof resumable.parent_communication === "string") {
1606
+ resumable.parentCommunication = resumable.parent_communication;
1607
+ }
1608
+ delete resumable.max_instances;
1609
+ delete resumable.parent_communication;
1610
+ next.resumable = resumable;
1611
+ }
1612
+ return next;
1613
+ }
1375
1614
  function transformPromptData(data) {
1376
1615
  const transformed = {};
1377
1616
  const fieldMappings = {
@@ -1418,6 +1657,22 @@ function transformPromptData(data) {
1418
1657
  delete transformed.reasoningExclude;
1419
1658
  delete transformed.includeReasoning;
1420
1659
  }
1660
+ if (Array.isArray(transformed.tools)) {
1661
+ transformed.tools = transformed.tools.map((tool) => {
1662
+ if (!tool || typeof tool !== "object" || Array.isArray(tool)) {
1663
+ return tool;
1664
+ }
1665
+ return normalizePromptToolConfig(tool);
1666
+ });
1667
+ }
1668
+ if (transformed.env !== void 0 || transformed.tenvs !== void 0) {
1669
+ transformed.env = normalizeStringEnvRecord(transformed.env ?? transformed.tenvs) ?? {};
1670
+ delete transformed.tenvs;
1671
+ }
1672
+ const normalizedVariables = normalizeVariableDeclarations(transformed.variables);
1673
+ if (normalizedVariables !== void 0) {
1674
+ transformed.variables = normalizedVariables;
1675
+ }
1421
1676
  return transformed;
1422
1677
  }
1423
1678
  function getPromptFilePath(promptsDir, name) {
@@ -1426,22 +1681,22 @@ function getPromptFilePath(promptsDir, name) {
1426
1681
  }
1427
1682
  function promptExists(promptsDir, name) {
1428
1683
  const filePath = getPromptFilePath(promptsDir, name);
1429
- return fs2__default.existsSync(filePath);
1684
+ return fs4__default.existsSync(filePath);
1430
1685
  }
1431
1686
  async function savePrompt(promptsDir, data, overwrite = false) {
1432
1687
  try {
1433
- if (!fs2__default.existsSync(promptsDir)) {
1434
- fs2__default.mkdirSync(promptsDir, { recursive: true });
1688
+ if (!fs4__default.existsSync(promptsDir)) {
1689
+ fs4__default.mkdirSync(promptsDir, { recursive: true });
1435
1690
  }
1436
1691
  const filePath = getPromptFilePath(promptsDir, data.name);
1437
- if (!overwrite && fs2__default.existsSync(filePath)) {
1692
+ if (!overwrite && fs4__default.existsSync(filePath)) {
1438
1693
  return {
1439
1694
  success: false,
1440
1695
  error: `Prompt file already exists: ${filePath}. Use update to modify existing prompts.`
1441
1696
  };
1442
1697
  }
1443
1698
  const content = generatePromptFile(data);
1444
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
1699
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1445
1700
  return {
1446
1701
  success: true,
1447
1702
  filePath
@@ -1456,13 +1711,13 @@ async function savePrompt(promptsDir, data, overwrite = false) {
1456
1711
  async function deletePrompt(promptsDir, name) {
1457
1712
  try {
1458
1713
  const filePath = getPromptFilePath(promptsDir, name);
1459
- if (!fs2__default.existsSync(filePath)) {
1714
+ if (!fs4__default.existsSync(filePath)) {
1460
1715
  return {
1461
1716
  success: false,
1462
1717
  error: `Prompt file not found: ${filePath}`
1463
1718
  };
1464
1719
  }
1465
- await fs2__default.promises.unlink(filePath);
1720
+ await fs4__default.promises.unlink(filePath);
1466
1721
  return {
1467
1722
  success: true,
1468
1723
  filePath
@@ -1478,25 +1733,25 @@ async function renamePrompt(promptsDir, oldName, newName) {
1478
1733
  try {
1479
1734
  const oldFilePath = getPromptFilePath(promptsDir, oldName);
1480
1735
  const newFilePath = getPromptFilePath(promptsDir, newName);
1481
- if (!fs2__default.existsSync(oldFilePath)) {
1736
+ if (!fs4__default.existsSync(oldFilePath)) {
1482
1737
  return {
1483
1738
  success: false,
1484
1739
  error: `Prompt file not found: ${oldFilePath}`
1485
1740
  };
1486
1741
  }
1487
- if (fs2__default.existsSync(newFilePath)) {
1742
+ if (fs4__default.existsSync(newFilePath)) {
1488
1743
  return {
1489
1744
  success: false,
1490
1745
  error: `Prompt file already exists: ${newFilePath}`
1491
1746
  };
1492
1747
  }
1493
- const content = await fs2__default.promises.readFile(oldFilePath, "utf-8");
1748
+ const content = await fs4__default.promises.readFile(oldFilePath, "utf-8");
1494
1749
  const updatedContent = content.replace(
1495
1750
  /name:\s*['"]([^'"]+)['"]/,
1496
1751
  `name: '${newName}'`
1497
1752
  );
1498
- await fs2__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
1499
- await fs2__default.promises.unlink(oldFilePath);
1753
+ await fs4__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
1754
+ await fs4__default.promises.unlink(oldFilePath);
1500
1755
  return {
1501
1756
  success: true,
1502
1757
  filePath: newFilePath
@@ -1521,8 +1776,8 @@ function validatePromptData(data) {
1521
1776
  if (data.toolDescription !== void 0 && typeof data.toolDescription !== "string") {
1522
1777
  errors["tool_description"] = "Tool description must be a string";
1523
1778
  }
1524
- if (data.prompt !== void 0 && typeof data.prompt !== "string") {
1525
- errors["prompt"] = "Prompt must be a string";
1779
+ if (data.prompt !== void 0 && typeof data.prompt !== "string" && !Array.isArray(data.prompt)) {
1780
+ errors["prompt"] = "Prompt must be a string or structured prompt array";
1526
1781
  }
1527
1782
  const booleanFieldMap = {
1528
1783
  includeChat: "include_chat",
@@ -1542,6 +1797,99 @@ function validatePromptData(data) {
1542
1797
  }
1543
1798
  if (data.tools !== void 0 && !Array.isArray(data.tools)) {
1544
1799
  errors["tools"] = "Tools must be an array";
1800
+ } else if (Array.isArray(data.tools)) {
1801
+ for (const tool of data.tools) {
1802
+ if (typeof tool === "string") continue;
1803
+ if (!tool || typeof tool !== "object" || Array.isArray(tool)) {
1804
+ errors["tools"] = "Each tool must be a string or object";
1805
+ break;
1806
+ }
1807
+ if (typeof tool.name !== "string" || tool.name.trim().length === 0) {
1808
+ errors["tools"] = "Each tool config requires a non-empty name";
1809
+ break;
1810
+ }
1811
+ if (tool.blocking !== void 0 && typeof tool.blocking !== "boolean") {
1812
+ errors["tools"] = "Tool blocking must be a boolean";
1813
+ break;
1814
+ }
1815
+ if (tool.optional !== void 0 && typeof tool.optional !== "string") {
1816
+ errors["tools"] = "Tool optional must be a string";
1817
+ break;
1818
+ }
1819
+ if (tool.immediate !== void 0 && typeof tool.immediate !== "boolean" && (typeof tool.immediate !== "object" || Array.isArray(tool.immediate) || tool.immediate === null)) {
1820
+ errors["tools"] = "Tool immediate must be a boolean or object";
1821
+ break;
1822
+ }
1823
+ if (tool.immediate && typeof tool.immediate === "object" && !Array.isArray(tool.immediate)) {
1824
+ const immediate = tool.immediate;
1825
+ if (immediate.nameEnv !== void 0 && typeof immediate.nameEnv !== "string") {
1826
+ errors["tools"] = "Tool immediate.nameEnv must be a string";
1827
+ break;
1828
+ }
1829
+ if (immediate.descriptionEnv !== void 0 && typeof immediate.descriptionEnv !== "string") {
1830
+ errors["tools"] = "Tool immediate.descriptionEnv must be a string";
1831
+ break;
1832
+ }
1833
+ if (immediate.scopedEnv !== void 0 && (!Array.isArray(immediate.scopedEnv) || immediate.scopedEnv.some((entry) => typeof entry !== "string"))) {
1834
+ errors["tools"] = "Tool immediate.scopedEnv must be an array of strings";
1835
+ break;
1836
+ }
1837
+ }
1838
+ if (tool.resumable !== void 0 && tool.resumable !== false && (typeof tool.resumable !== "object" || Array.isArray(tool.resumable) || tool.resumable === null)) {
1839
+ errors["tools"] = "Tool resumable must be false or an object";
1840
+ break;
1841
+ }
1842
+ if (tool.resumable && typeof tool.resumable === "object" && !Array.isArray(tool.resumable)) {
1843
+ const resumable = tool.resumable;
1844
+ if (resumable.receives_messages !== void 0 && resumable.receives_messages !== "side_a" && resumable.receives_messages !== "side_b") {
1845
+ errors["tools"] = 'Tool resumable.receives_messages must be "side_a" or "side_b"';
1846
+ break;
1847
+ }
1848
+ if (resumable.maxInstances !== void 0 && (typeof resumable.maxInstances !== "number" || !Number.isFinite(resumable.maxInstances))) {
1849
+ errors["tools"] = "Tool resumable.maxInstances must be a number";
1850
+ break;
1851
+ }
1852
+ if (resumable.parentCommunication !== void 0 && resumable.parentCommunication !== "implicit" && resumable.parentCommunication !== "explicit") {
1853
+ errors["tools"] = 'Tool resumable.parentCommunication must be "implicit" or "explicit"';
1854
+ break;
1855
+ }
1856
+ }
1857
+ }
1858
+ }
1859
+ if (data.env !== void 0) {
1860
+ if (!data.env || typeof data.env !== "object" || Array.isArray(data.env)) {
1861
+ errors["env"] = "env must be an object of string values";
1862
+ } else if (Object.values(data.env).some((value) => value !== void 0 && value !== null && typeof value !== "string")) {
1863
+ errors["env"] = "env values must be strings";
1864
+ }
1865
+ }
1866
+ if (data.variables !== void 0) {
1867
+ if (!Array.isArray(data.variables)) {
1868
+ errors["variables"] = "variables must be an array";
1869
+ } else {
1870
+ for (const variable of data.variables) {
1871
+ if (!variable || typeof variable !== "object") {
1872
+ errors["variables"] = "Each variable declaration must be an object";
1873
+ break;
1874
+ }
1875
+ if (typeof variable.name !== "string" || variable.name.trim().length === 0) {
1876
+ errors["variables"] = "Each variable declaration requires a non-empty name";
1877
+ break;
1878
+ }
1879
+ if (variable.type !== "text" && variable.type !== "secret") {
1880
+ errors["variables"] = 'Variable type must be "text" or "secret"';
1881
+ break;
1882
+ }
1883
+ if (typeof variable.required !== "boolean") {
1884
+ errors["variables"] = "Variable required must be a boolean";
1885
+ break;
1886
+ }
1887
+ if (typeof variable.description !== "string") {
1888
+ errors["variables"] = "Variable description must be a string";
1889
+ break;
1890
+ }
1891
+ }
1892
+ }
1545
1893
  }
1546
1894
  if (data.reasoning !== void 0) {
1547
1895
  if (typeof data.reasoning !== "object") {
@@ -1564,6 +1912,17 @@ function transformAgentData(data) {
1564
1912
  const transformed = {
1565
1913
  name: data.name
1566
1914
  };
1915
+ const toSessionBinding = (toolName, messageProperty, attachmentsProperty) => {
1916
+ if (!toolName) return void 0;
1917
+ if (messageProperty || attachmentsProperty) {
1918
+ return {
1919
+ name: toolName,
1920
+ ...messageProperty ? { messageProperty } : {},
1921
+ ...attachmentsProperty ? { attachmentsProperty } : {}
1922
+ };
1923
+ }
1924
+ return toolName;
1925
+ };
1567
1926
  if (data.title) {
1568
1927
  transformed.title = data.title;
1569
1928
  }
@@ -1591,9 +1950,36 @@ function transformAgentData(data) {
1591
1950
  if (data.side_a_max_steps !== void 0) {
1592
1951
  transformed.sideA.maxSteps = data.side_a_max_steps;
1593
1952
  }
1594
- if (data.side_a_end_session_tool) {
1953
+ const sideASessionStop = toSessionBinding(
1954
+ data.side_a_session_stop_tool ?? data.side_a_end_session_tool,
1955
+ data.side_a_session_stop_message_property,
1956
+ data.side_a_session_stop_attachments_property
1957
+ );
1958
+ if (sideASessionStop !== void 0) {
1959
+ transformed.sideA.sessionStop = sideASessionStop;
1960
+ } else if (data.side_a_end_session_tool) {
1595
1961
  transformed.sideA.endSessionTool = data.side_a_end_session_tool;
1596
1962
  }
1963
+ const sideASessionFail = toSessionBinding(
1964
+ data.side_a_session_fail_tool ?? data.side_a_fail_session_tool,
1965
+ data.side_a_session_fail_message_property,
1966
+ data.side_a_session_fail_attachments_property
1967
+ );
1968
+ if (sideASessionFail !== void 0) {
1969
+ transformed.sideA.sessionFail = sideASessionFail;
1970
+ } else if (data.side_a_fail_session_tool) {
1971
+ transformed.sideA.failSessionTool = data.side_a_fail_session_tool;
1972
+ }
1973
+ const sideASessionStatus = toSessionBinding(
1974
+ data.side_a_session_status_tool ?? data.side_a_status_tool,
1975
+ data.side_a_session_status_message_property,
1976
+ data.side_a_session_status_attachments_property
1977
+ );
1978
+ if (sideASessionStatus !== void 0) {
1979
+ transformed.sideA.sessionStatus = sideASessionStatus;
1980
+ } else if (data.side_a_status_tool) {
1981
+ transformed.sideA.statusTool = data.side_a_status_tool;
1982
+ }
1597
1983
  if (data.side_a_manual_stop_condition !== void 0) {
1598
1984
  transformed.sideA.manualStopCondition = data.side_a_manual_stop_condition;
1599
1985
  }
@@ -1616,9 +2002,36 @@ function transformAgentData(data) {
1616
2002
  if (data.side_b_max_steps !== void 0) {
1617
2003
  transformed.sideB.maxSteps = data.side_b_max_steps;
1618
2004
  }
1619
- if (data.side_b_end_session_tool) {
2005
+ const sideBSessionStop = toSessionBinding(
2006
+ data.side_b_session_stop_tool ?? data.side_b_end_session_tool,
2007
+ data.side_b_session_stop_message_property,
2008
+ data.side_b_session_stop_attachments_property
2009
+ );
2010
+ if (sideBSessionStop !== void 0) {
2011
+ transformed.sideB.sessionStop = sideBSessionStop;
2012
+ } else if (data.side_b_end_session_tool) {
1620
2013
  transformed.sideB.endSessionTool = data.side_b_end_session_tool;
1621
2014
  }
2015
+ const sideBSessionFail = toSessionBinding(
2016
+ data.side_b_session_fail_tool ?? data.side_b_fail_session_tool,
2017
+ data.side_b_session_fail_message_property,
2018
+ data.side_b_session_fail_attachments_property
2019
+ );
2020
+ if (sideBSessionFail !== void 0) {
2021
+ transformed.sideB.sessionFail = sideBSessionFail;
2022
+ } else if (data.side_b_fail_session_tool) {
2023
+ transformed.sideB.failSessionTool = data.side_b_fail_session_tool;
2024
+ }
2025
+ const sideBSessionStatus = toSessionBinding(
2026
+ data.side_b_session_status_tool ?? data.side_b_status_tool,
2027
+ data.side_b_session_status_message_property,
2028
+ data.side_b_session_status_attachments_property
2029
+ );
2030
+ if (sideBSessionStatus !== void 0) {
2031
+ transformed.sideB.sessionStatus = sideBSessionStatus;
2032
+ } else if (data.side_b_status_tool) {
2033
+ transformed.sideB.statusTool = data.side_b_status_tool;
2034
+ }
1622
2035
  if (data.side_b_manual_stop_condition !== void 0) {
1623
2036
  transformed.sideB.manualStopCondition = data.side_b_manual_stop_condition;
1624
2037
  }
@@ -1629,6 +2042,9 @@ function transformAgentData(data) {
1629
2042
  if (data.tool_description) {
1630
2043
  transformed.toolDescription = data.tool_description;
1631
2044
  }
2045
+ if (data.env !== void 0 || data.tenvs !== void 0) {
2046
+ transformed.env = normalizeStringEnvRecord(data.env ?? data.tenvs) ?? {};
2047
+ }
1632
2048
  return transformed;
1633
2049
  }
1634
2050
  function getAgentFilePath(agentsDir, name) {
@@ -1637,11 +2053,11 @@ function getAgentFilePath(agentsDir, name) {
1637
2053
  }
1638
2054
  function agentExists(agentsDir, name) {
1639
2055
  const filePath = getAgentFilePath(agentsDir, name);
1640
- return fs2__default.existsSync(filePath);
2056
+ return fs4__default.existsSync(filePath);
1641
2057
  }
1642
2058
  function extractAgentMetadata(filePath) {
1643
2059
  try {
1644
- const content = fs2__default.readFileSync(filePath, "utf-8");
2060
+ const content = fs4__default.readFileSync(filePath, "utf-8");
1645
2061
  const metadata = {};
1646
2062
  const packageNameMatch = content.match(/packageName:\s*['"]([^'"]+)['"]/);
1647
2063
  if (packageNameMatch) metadata.packageName = packageNameMatch[1];
@@ -1658,17 +2074,17 @@ function extractAgentMetadata(filePath) {
1658
2074
  }
1659
2075
  async function saveAgent(agentsDir, data, overwrite = false) {
1660
2076
  try {
1661
- if (!fs2__default.existsSync(agentsDir)) {
1662
- fs2__default.mkdirSync(agentsDir, { recursive: true });
2077
+ if (!fs4__default.existsSync(agentsDir)) {
2078
+ fs4__default.mkdirSync(agentsDir, { recursive: true });
1663
2079
  }
1664
2080
  const filePath = getAgentFilePath(agentsDir, data.name);
1665
- if (!overwrite && fs2__default.existsSync(filePath)) {
2081
+ if (!overwrite && fs4__default.existsSync(filePath)) {
1666
2082
  return {
1667
2083
  success: false,
1668
2084
  error: `Agent file already exists: ${filePath}. Use update to modify existing agents.`
1669
2085
  };
1670
2086
  }
1671
- if (overwrite && fs2__default.existsSync(filePath)) {
2087
+ if (overwrite && fs4__default.existsSync(filePath)) {
1672
2088
  const existingMetadata = extractAgentMetadata(filePath);
1673
2089
  if (existingMetadata.packageName && !data.packageName) {
1674
2090
  data.packageName = existingMetadata.packageName;
@@ -1684,7 +2100,7 @@ async function saveAgent(agentsDir, data, overwrite = false) {
1684
2100
  }
1685
2101
  }
1686
2102
  const content = generateAgentFile(data);
1687
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
2103
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1688
2104
  return {
1689
2105
  success: true,
1690
2106
  filePath
@@ -1699,13 +2115,13 @@ async function saveAgent(agentsDir, data, overwrite = false) {
1699
2115
  async function deleteAgent(agentsDir, name) {
1700
2116
  try {
1701
2117
  const filePath = getAgentFilePath(agentsDir, name);
1702
- if (!fs2__default.existsSync(filePath)) {
2118
+ if (!fs4__default.existsSync(filePath)) {
1703
2119
  return {
1704
2120
  success: false,
1705
2121
  error: `Agent file not found: ${filePath}`
1706
2122
  };
1707
2123
  }
1708
- await fs2__default.promises.unlink(filePath);
2124
+ await fs4__default.promises.unlink(filePath);
1709
2125
  return {
1710
2126
  success: true,
1711
2127
  filePath
@@ -1721,25 +2137,25 @@ async function renameModel(modelsDir, oldName, newName) {
1721
2137
  try {
1722
2138
  const oldFilePath = getModelFilePath(modelsDir, oldName);
1723
2139
  const newFilePath = getModelFilePath(modelsDir, newName);
1724
- if (!fs2__default.existsSync(oldFilePath)) {
2140
+ if (!fs4__default.existsSync(oldFilePath)) {
1725
2141
  return {
1726
2142
  success: false,
1727
2143
  error: `Model file not found: ${oldFilePath}`
1728
2144
  };
1729
2145
  }
1730
- if (fs2__default.existsSync(newFilePath)) {
2146
+ if (fs4__default.existsSync(newFilePath)) {
1731
2147
  return {
1732
2148
  success: false,
1733
2149
  error: `Model file already exists: ${newFilePath}`
1734
2150
  };
1735
2151
  }
1736
- const content = await fs2__default.promises.readFile(oldFilePath, "utf-8");
2152
+ const content = await fs4__default.promises.readFile(oldFilePath, "utf-8");
1737
2153
  const updatedContent = content.replace(
1738
2154
  /name:\s*['"]([^'"]+)['"]/,
1739
2155
  `name: '${newName}'`
1740
2156
  );
1741
- await fs2__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
1742
- await fs2__default.promises.unlink(oldFilePath);
2157
+ await fs4__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
2158
+ await fs4__default.promises.unlink(oldFilePath);
1743
2159
  return {
1744
2160
  success: true,
1745
2161
  filePath: newFilePath
@@ -1753,17 +2169,17 @@ async function renameModel(modelsDir, oldName, newName) {
1753
2169
  }
1754
2170
  async function updateModelReferencesInPrompts(promptsDir, oldModelName, newModelName) {
1755
2171
  const updatedFiles = [];
1756
- if (!fs2__default.existsSync(promptsDir)) {
2172
+ if (!fs4__default.existsSync(promptsDir)) {
1757
2173
  return updatedFiles;
1758
2174
  }
1759
- const files = fs2__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
2175
+ const files = fs4__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
1760
2176
  for (const file of files) {
1761
2177
  const filePath = path8__default.join(promptsDir, file);
1762
- let content = await fs2__default.promises.readFile(filePath, "utf-8");
2178
+ let content = await fs4__default.promises.readFile(filePath, "utf-8");
1763
2179
  const modelRegex = new RegExp(`model:\\s*['"]${escapeRegExp(oldModelName)}['"]`, "g");
1764
2180
  if (modelRegex.test(content)) {
1765
2181
  content = content.replace(modelRegex, `model: '${newModelName}'`);
1766
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
2182
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1767
2183
  updatedFiles.push(filePath);
1768
2184
  }
1769
2185
  }
@@ -1771,13 +2187,13 @@ async function updateModelReferencesInPrompts(promptsDir, oldModelName, newModel
1771
2187
  }
1772
2188
  async function updatePromptReferencesInPrompts(promptsDir, oldPromptName, newPromptName) {
1773
2189
  const updatedFiles = [];
1774
- if (!fs2__default.existsSync(promptsDir)) {
2190
+ if (!fs4__default.existsSync(promptsDir)) {
1775
2191
  return updatedFiles;
1776
2192
  }
1777
- const files = fs2__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
2193
+ const files = fs4__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
1778
2194
  for (const file of files) {
1779
2195
  const filePath = path8__default.join(promptsDir, file);
1780
- let content = await fs2__default.promises.readFile(filePath, "utf-8");
2196
+ let content = await fs4__default.promises.readFile(filePath, "utf-8");
1781
2197
  let modified = false;
1782
2198
  const toolsArrayRegex = /tools:\s*\[([^\]]*)\]/gs;
1783
2199
  const newContent = content.replace(toolsArrayRegex, (match) => {
@@ -1790,7 +2206,7 @@ async function updatePromptReferencesInPrompts(promptsDir, oldPromptName, newPro
1790
2206
  return replaced;
1791
2207
  });
1792
2208
  if (modified) {
1793
- await fs2__default.promises.writeFile(filePath, newContent, "utf-8");
2209
+ await fs4__default.promises.writeFile(filePath, newContent, "utf-8");
1794
2210
  updatedFiles.push(filePath);
1795
2211
  }
1796
2212
  }
@@ -1798,17 +2214,17 @@ async function updatePromptReferencesInPrompts(promptsDir, oldPromptName, newPro
1798
2214
  }
1799
2215
  async function updatePromptReferencesInAgents(agentsDir, oldPromptName, newPromptName) {
1800
2216
  const updatedFiles = [];
1801
- if (!fs2__default.existsSync(agentsDir)) {
2217
+ if (!fs4__default.existsSync(agentsDir)) {
1802
2218
  return updatedFiles;
1803
2219
  }
1804
- const files = fs2__default.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
2220
+ const files = fs4__default.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
1805
2221
  for (const file of files) {
1806
2222
  const filePath = path8__default.join(agentsDir, file);
1807
- let content = await fs2__default.promises.readFile(filePath, "utf-8");
2223
+ let content = await fs4__default.promises.readFile(filePath, "utf-8");
1808
2224
  const promptRegex = new RegExp(`prompt:\\s*['"]${escapeRegExp(oldPromptName)}['"]`, "g");
1809
2225
  if (promptRegex.test(content)) {
1810
2226
  content = content.replace(promptRegex, `prompt: '${newPromptName}'`);
1811
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
2227
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1812
2228
  updatedFiles.push(filePath);
1813
2229
  }
1814
2230
  }
@@ -1876,6 +2292,15 @@ function validateAgentData(data) {
1876
2292
  errors["max_session_turns"] = "Max session turns must be a positive number";
1877
2293
  }
1878
2294
  }
2295
+ if (data.env !== void 0) {
2296
+ if (!data.env || typeof data.env !== "object" || Array.isArray(data.env)) {
2297
+ errors["env"] = "env must be an object of string values";
2298
+ } else if (Object.values(data.env).some(
2299
+ (value) => value !== void 0 && value !== null && typeof value !== "string"
2300
+ )) {
2301
+ errors["env"] = "env values must be strings";
2302
+ }
2303
+ }
1879
2304
  return Object.keys(errors).length > 0 ? errors : null;
1880
2305
  }
1881
2306
  var MetadataService = class {
@@ -1896,11 +2321,11 @@ var MetadataService = class {
1896
2321
  */
1897
2322
  async read(agentName) {
1898
2323
  const filePath = this.getMetadataPath(agentName);
1899
- if (!fs2.existsSync(filePath)) {
2324
+ if (!fs4.existsSync(filePath)) {
1900
2325
  return null;
1901
2326
  }
1902
2327
  try {
1903
- const content = fs2.readFileSync(filePath, "utf-8");
2328
+ const content = fs4.readFileSync(filePath, "utf-8");
1904
2329
  return JSON.parse(content);
1905
2330
  } catch {
1906
2331
  return null;
@@ -1913,11 +2338,11 @@ var MetadataService = class {
1913
2338
  * @param metadata - Metadata to write
1914
2339
  */
1915
2340
  async write(agentName, metadata) {
1916
- if (!fs2.existsSync(this.metadataDir)) {
1917
- fs2.mkdirSync(this.metadataDir, { recursive: true });
2341
+ if (!fs4.existsSync(this.metadataDir)) {
2342
+ fs4.mkdirSync(this.metadataDir, { recursive: true });
1918
2343
  }
1919
2344
  const filePath = this.getMetadataPath(agentName);
1920
- fs2.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
2345
+ fs4.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
1921
2346
  }
1922
2347
  /**
1923
2348
  * Delete metadata for an agent.
@@ -1926,8 +2351,8 @@ var MetadataService = class {
1926
2351
  */
1927
2352
  async delete(agentName) {
1928
2353
  const filePath = this.getMetadataPath(agentName);
1929
- if (fs2.existsSync(filePath)) {
1930
- fs2.unlinkSync(filePath);
2354
+ if (fs4.existsSync(filePath)) {
2355
+ fs4.unlinkSync(filePath);
1931
2356
  }
1932
2357
  }
1933
2358
  /**
@@ -2382,7 +2807,7 @@ var PackingService = class {
2382
2807
  resolvePackageVersion(pkgName, rootDir) {
2383
2808
  const pkgJsonPath = path8.join(rootDir, "node_modules", pkgName, "package.json");
2384
2809
  try {
2385
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
2810
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
2386
2811
  return `^${pkgJson.version}`;
2387
2812
  } catch {
2388
2813
  return "*";
@@ -2408,13 +2833,17 @@ var PackingService = class {
2408
2833
  tools: [],
2409
2834
  models: [],
2410
2835
  hooks: [],
2411
- agents: []
2836
+ effects: [],
2837
+ agents: [],
2838
+ threadEndpoints: []
2412
2839
  },
2413
2840
  shared: {
2414
2841
  prompts: [],
2415
2842
  tools: [],
2416
2843
  models: [],
2417
- hooks: []
2844
+ hooks: [],
2845
+ effects: [],
2846
+ threadEndpoints: []
2418
2847
  },
2419
2848
  warnings: [],
2420
2849
  errors: []
@@ -2430,7 +2859,7 @@ var PackingService = class {
2430
2859
  discoveredVia: "static",
2431
2860
  sharedWith: []
2432
2861
  });
2433
- const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
2862
+ const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
2434
2863
  const agentPrompts = await extractAgentPrompts(agentSource);
2435
2864
  if (agentPrompts.sideA) {
2436
2865
  analysis.primaryPrompt = agentPrompts.sideA;
@@ -2439,6 +2868,8 @@ var PackingService = class {
2439
2868
  if (agentPrompts.sideB) {
2440
2869
  await this.analyzePrompt(agentPrompts.sideB, agentsDir, analysis, /* @__PURE__ */ new Set(), `agent:${agentName}`);
2441
2870
  }
2871
+ await this.analyzeThreadEndpoints(agentsDir, analysis);
2872
+ await this.analyzeEffects(agentsDir, analysis);
2442
2873
  await this.checkSharedItems(agentsDir, analysis);
2443
2874
  return analysis;
2444
2875
  }
@@ -2459,7 +2890,7 @@ var PackingService = class {
2459
2890
  const agentItem = analysis.constituents.agents.find((a) => a.name === analysis.agent);
2460
2891
  if (agentItem?.filePath) {
2461
2892
  try {
2462
- const agentSource = fs2.readFileSync(agentItem.filePath, "utf-8");
2893
+ const agentSource = fs4.readFileSync(agentItem.filePath, "utf-8");
2463
2894
  agentDescription = await extractAgentDescription(agentSource) || void 0;
2464
2895
  } catch {
2465
2896
  }
@@ -2476,6 +2907,138 @@ var PackingService = class {
2476
2907
  );
2477
2908
  return { generatedReadme, agentDescription };
2478
2909
  }
2910
+ /**
2911
+ * Analyze thread endpoints from agents/api and include them as packed constituents.
2912
+ *
2913
+ * Thread endpoints are not directly referenced by agent/prompt definitions, so we
2914
+ * include all endpoint modules discovered under agents/api.
2915
+ */
2916
+ async analyzeThreadEndpoints(agentsDir, analysis) {
2917
+ const apiDir = path8.join(agentsDir, "api");
2918
+ const endpoints = this.scanThreadEndpointFiles(apiDir);
2919
+ for (const endpoint of endpoints) {
2920
+ if (analysis.constituents.threadEndpoints.some((item) => item.name === endpoint.name)) {
2921
+ continue;
2922
+ }
2923
+ analysis.constituents.threadEndpoints.push({
2924
+ name: endpoint.name,
2925
+ filePath: endpoint.filePath,
2926
+ discoveredVia: "thread-endpoint",
2927
+ sharedWith: []
2928
+ });
2929
+ }
2930
+ }
2931
+ /**
2932
+ * Recursively scan agents/api for endpoint source files.
2933
+ *
2934
+ * Returns endpoint keys like:
2935
+ * - `status.get`
2936
+ * - `admin/users/[userId]/sync.post`
2937
+ */
2938
+ scanThreadEndpointFiles(apiDir, relativeDir = "") {
2939
+ if (!fs4.existsSync(apiDir)) {
2940
+ return [];
2941
+ }
2942
+ const endpoints = [];
2943
+ const currentDir = relativeDir ? path8.join(apiDir, relativeDir) : apiDir;
2944
+ if (!fs4.existsSync(currentDir)) {
2945
+ return endpoints;
2946
+ }
2947
+ const entries = fs4.readdirSync(currentDir, { withFileTypes: true });
2948
+ if (entries.length > 0 && typeof entries[0] === "string") {
2949
+ return endpoints;
2950
+ }
2951
+ for (const entry of entries) {
2952
+ const entryName = typeof entry === "string" ? entry : entry.name;
2953
+ const isDirectory = typeof entry === "string" ? false : entry.isDirectory();
2954
+ const isFile = typeof entry === "string" ? true : entry.isFile();
2955
+ const entryRelative = relativeDir ? path8.posix.join(relativeDir.replace(/\\/g, "/"), entryName) : entryName;
2956
+ const absolutePath = path8.join(apiDir, entryRelative);
2957
+ if (isDirectory) {
2958
+ endpoints.push(...this.scanThreadEndpointFiles(apiDir, entryRelative));
2959
+ continue;
2960
+ }
2961
+ if (!isFile) {
2962
+ continue;
2963
+ }
2964
+ if (!entryName.endsWith(".ts")) {
2965
+ continue;
2966
+ }
2967
+ const endpointKey = entryRelative.replace(/\.ts$/, "").replace(/\\/g, "/");
2968
+ endpoints.push({
2969
+ name: endpointKey,
2970
+ filePath: absolutePath
2971
+ });
2972
+ }
2973
+ endpoints.sort((a, b) => a.name.localeCompare(b.name));
2974
+ return endpoints;
2975
+ }
2976
+ /**
2977
+ * Analyze effects from agents/effects and include them as packed constituents.
2978
+ *
2979
+ * Effects are referenced by string names at runtime via scheduleEffect(), so we
2980
+ * include all effect modules discovered under agents/effects.
2981
+ */
2982
+ async analyzeEffects(agentsDir, analysis) {
2983
+ const effectsDir = path8.join(agentsDir, "effects");
2984
+ const effects = this.scanEffectFiles(effectsDir);
2985
+ for (const effect of effects) {
2986
+ if (analysis.constituents.effects.some((item) => item.name === effect.name)) {
2987
+ continue;
2988
+ }
2989
+ analysis.constituents.effects.push({
2990
+ name: effect.name,
2991
+ filePath: effect.filePath,
2992
+ discoveredVia: "effect",
2993
+ sharedWith: []
2994
+ });
2995
+ }
2996
+ }
2997
+ /**
2998
+ * Recursively scan agents/effects for effect source files.
2999
+ *
3000
+ * Returns effect keys like:
3001
+ * - `send_email`
3002
+ * - `notifications/digest`
3003
+ */
3004
+ scanEffectFiles(effectsDir, relativeDir = "") {
3005
+ if (!fs4.existsSync(effectsDir)) {
3006
+ return [];
3007
+ }
3008
+ const effects = [];
3009
+ const currentDir = relativeDir ? path8.join(effectsDir, relativeDir) : effectsDir;
3010
+ if (!fs4.existsSync(currentDir)) {
3011
+ return effects;
3012
+ }
3013
+ const entries = fs4.readdirSync(currentDir, { withFileTypes: true });
3014
+ if (entries.length > 0 && typeof entries[0] === "string") {
3015
+ return effects;
3016
+ }
3017
+ for (const entry of entries) {
3018
+ const entryName = typeof entry === "string" ? entry : entry.name;
3019
+ const isDirectory = typeof entry === "string" ? false : entry.isDirectory();
3020
+ const isFile = typeof entry === "string" ? true : entry.isFile();
3021
+ const entryRelative = relativeDir ? path8.posix.join(relativeDir.replace(/\\/g, "/"), entryName) : entryName;
3022
+ const absolutePath = path8.join(effectsDir, entryRelative);
3023
+ if (isDirectory) {
3024
+ effects.push(...this.scanEffectFiles(effectsDir, entryRelative));
3025
+ continue;
3026
+ }
3027
+ if (!isFile || !entryName.endsWith(".ts")) {
3028
+ continue;
3029
+ }
3030
+ if (entryName === "CLAUDE.md" || entryName === "AGENTS.md" || entryName.startsWith("_")) {
3031
+ continue;
3032
+ }
3033
+ const effectKey = entryRelative.replace(/\.ts$/, "").replace(/\\/g, "/");
3034
+ effects.push({
3035
+ name: effectKey,
3036
+ filePath: absolutePath
3037
+ });
3038
+ }
3039
+ effects.sort((a, b) => a.name.localeCompare(b.name));
3040
+ return effects;
3041
+ }
2479
3042
  /**
2480
3043
  * Recursively analyze a prompt and its dependencies.
2481
3044
  */
@@ -2499,7 +3062,7 @@ var PackingService = class {
2499
3062
  return;
2500
3063
  }
2501
3064
  visited.add(`prompt:${promptName}`);
2502
- const promptSource = fs2.readFileSync(promptFilePath, "utf-8");
3065
+ const promptSource = fs4.readFileSync(promptFilePath, "utf-8");
2503
3066
  const modelName = await extractPromptModel(promptSource);
2504
3067
  if (modelName) {
2505
3068
  await this.analyzeModel(modelName, agentsDir, analysis, visited, thisKey);
@@ -2553,7 +3116,7 @@ var PackingService = class {
2553
3116
  return;
2554
3117
  }
2555
3118
  visited.add(`tool:${toolName}`);
2556
- const toolSource = fs2.readFileSync(toolFilePath, "utf-8");
3119
+ const toolSource = fs4.readFileSync(toolFilePath, "utf-8");
2557
3120
  const { uses } = await extractToolUses(toolSource);
2558
3121
  for (const usedItem of uses) {
2559
3122
  await this.analyzeTool(usedItem, agentsDir, analysis, visited, "uses", thisKey);
@@ -2582,7 +3145,7 @@ var PackingService = class {
2582
3145
  return;
2583
3146
  }
2584
3147
  visited.add(`agent:${agentName}`);
2585
- const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
3148
+ const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
2586
3149
  const agentPrompts = await extractAgentPrompts(agentSource);
2587
3150
  if (agentPrompts.sideA) {
2588
3151
  await this.analyzePrompt(agentPrompts.sideA, agentsDir, analysis, visited, thisKey);
@@ -2614,7 +3177,7 @@ var PackingService = class {
2614
3177
  return;
2615
3178
  }
2616
3179
  visited.add(`model:${modelName}`);
2617
- const modelSource = fs2.readFileSync(modelFilePath, "utf-8");
3180
+ const modelSource = fs4.readFileSync(modelFilePath, "utf-8");
2618
3181
  const fallbacks = await extractModelFallbacks(modelSource);
2619
3182
  for (const fallbackName of fallbacks) {
2620
3183
  await this.analyzeModel(fallbackName, agentsDir, analysis, visited, thisKey);
@@ -2625,8 +3188,8 @@ var PackingService = class {
2625
3188
  */
2626
3189
  async checkSharedItems(agentsDir, analysis) {
2627
3190
  const agentsPath = path8.join(agentsDir, "agents");
2628
- if (!fs2.existsSync(agentsPath)) return;
2629
- const agentFiles = fs2.readdirSync(agentsPath).filter((f) => f.endsWith(".ts"));
3191
+ if (!fs4.existsSync(agentsPath)) return;
3192
+ const agentFiles = fs4.readdirSync(agentsPath).filter((f) => f.endsWith(".ts"));
2630
3193
  for (const agentFile of agentFiles) {
2631
3194
  const otherAgentName = agentFile.replace(".ts", "");
2632
3195
  if (otherAgentName === analysis.agent) continue;
@@ -2666,7 +3229,7 @@ var PackingService = class {
2666
3229
  const visited = /* @__PURE__ */ new Set();
2667
3230
  const agentFilePath = await this.findFile(path8.join(agentsDir, "agents"), agentName);
2668
3231
  if (!agentFilePath) return result;
2669
- const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
3232
+ const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
2670
3233
  const agentPrompts = await extractAgentPrompts(agentSource);
2671
3234
  const analyzePromptLight = async (promptName) => {
2672
3235
  if (visited.has(promptName)) return;
@@ -2674,7 +3237,7 @@ var PackingService = class {
2674
3237
  result.prompts.push(promptName);
2675
3238
  const promptFilePath = await this.findFile(path8.join(agentsDir, "prompts"), promptName);
2676
3239
  if (!promptFilePath) return;
2677
- const promptSource = fs2.readFileSync(promptFilePath, "utf-8");
3240
+ const promptSource = fs4.readFileSync(promptFilePath, "utf-8");
2678
3241
  const modelName = await extractPromptModel(promptSource);
2679
3242
  if (modelName && !result.models.includes(modelName)) {
2680
3243
  result.models.push(modelName);
@@ -2699,6 +3262,8 @@ var PackingService = class {
2699
3262
  *
2700
3263
  * The packing format creates:
2701
3264
  * - dist/{type}/{name}.js - Individual bundled files per constituent
3265
+ * - dist/effects/** - Packed effect modules
3266
+ * - dist/thread-endpoints/** - Packed thread endpoint modules
2702
3267
  * - dist/index.js - Re-exports and lazy loaders
2703
3268
  * - dist/index.d.ts - TypeScript type definitions
2704
3269
  * - package.json - With standardagent field and dependencies
@@ -2746,11 +3311,13 @@ var PackingService = class {
2746
3311
  }
2747
3312
  result.warnings = analysis.warnings;
2748
3313
  const pkgOutputDir = path8.join(outputDir, packageId);
2749
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "agents"), { recursive: true });
2750
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "prompts"), { recursive: true });
2751
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "tools"), { recursive: true });
2752
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "models"), { recursive: true });
2753
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "hooks"), { recursive: true });
3314
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "agents"), { recursive: true });
3315
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "prompts"), { recursive: true });
3316
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "tools"), { recursive: true });
3317
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "models"), { recursive: true });
3318
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "hooks"), { recursive: true });
3319
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "effects"), { recursive: true });
3320
+ fs4.mkdirSync(path8.join(pkgOutputDir, "dist", "thread-endpoints"), { recursive: true });
2754
3321
  const seenItems = /* @__PURE__ */ new Set();
2755
3322
  const allItems = [];
2756
3323
  for (const a of analysis.constituents.agents) {
@@ -2788,6 +3355,20 @@ var PackingService = class {
2788
3355
  allItems.push({ ...h, type: "hook" });
2789
3356
  }
2790
3357
  }
3358
+ for (const effect of analysis.constituents.effects) {
3359
+ const key = `effect:${effect.name}`;
3360
+ if (!seenItems.has(key)) {
3361
+ seenItems.add(key);
3362
+ allItems.push({ ...effect, type: "effect" });
3363
+ }
3364
+ }
3365
+ for (const endpoint of analysis.constituents.threadEndpoints) {
3366
+ const key = `thread-endpoint:${endpoint.name}`;
3367
+ if (!seenItems.has(key)) {
3368
+ seenItems.add(key);
3369
+ allItems.push({ ...endpoint, type: "thread-endpoint" });
3370
+ }
3371
+ }
2791
3372
  const externalDeps = /* @__PURE__ */ new Map();
2792
3373
  for (const item of allItems) {
2793
3374
  const outputPath = path8.join(
@@ -2796,6 +3377,7 @@ var PackingService = class {
2796
3377
  this.getTypeDir(item.type),
2797
3378
  `${item.name}.js`
2798
3379
  );
3380
+ fs4.mkdirSync(path8.dirname(outputPath), { recursive: true });
2799
3381
  const deps = await this.bundleFile(item.filePath, outputPath, rootDir);
2800
3382
  for (const [depName, depVersion] of deps) {
2801
3383
  if (!externalDeps.has(depName)) {
@@ -2806,28 +3388,30 @@ var PackingService = class {
2806
3388
  }
2807
3389
  const indexJs = this.generateReExportIndex(analysis, meta);
2808
3390
  const indexJsPath = path8.join(pkgOutputDir, "dist", "index.js");
2809
- fs2.writeFileSync(indexJsPath, indexJs);
3391
+ fs4.writeFileSync(indexJsPath, indexJs);
2810
3392
  result.filesCreated.push(indexJsPath);
2811
3393
  const indexDts = this.generateIndexDts(analysis);
2812
3394
  const indexDtsPath = path8.join(pkgOutputDir, "dist", "index.d.ts");
2813
- fs2.writeFileSync(indexDtsPath, indexDts);
3395
+ fs4.writeFileSync(indexDtsPath, indexDts);
2814
3396
  result.filesCreated.push(indexDtsPath);
2815
3397
  const pkgJson = this.generatePackageJson(
2816
3398
  finalPackageName,
2817
3399
  version,
2818
3400
  agentName,
3401
+ this.deduplicateConstituents(analysis).effects.map((effect) => effect.name),
3402
+ this.deduplicateConstituents(analysis).threadEndpoints.map((endpoint) => endpoint.name),
2819
3403
  externalDeps,
2820
3404
  rootDir,
2821
3405
  license,
2822
3406
  licenseOwner
2823
3407
  );
2824
3408
  const pkgJsonPath = path8.join(pkgOutputDir, "package.json");
2825
- fs2.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
3409
+ fs4.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
2826
3410
  result.filesCreated.push(pkgJsonPath);
2827
3411
  if (license) {
2828
3412
  const licenseContent = this.generateLicenseFile(license, licenseOwner);
2829
3413
  const licensePath = path8.join(pkgOutputDir, "LICENSE");
2830
- fs2.writeFileSync(licensePath, licenseContent);
3414
+ fs4.writeFileSync(licensePath, licenseContent);
2831
3415
  result.filesCreated.push(licensePath);
2832
3416
  }
2833
3417
  let readmeContent = readme;
@@ -2835,7 +3419,7 @@ var PackingService = class {
2835
3419
  const agentItem = analysis.constituents.agents.find((a) => a.name === agentName);
2836
3420
  let agentDescription;
2837
3421
  if (agentItem?.filePath) {
2838
- const agentSource = fs2.readFileSync(agentItem.filePath, "utf-8");
3422
+ const agentSource = fs4.readFileSync(agentItem.filePath, "utf-8");
2839
3423
  agentDescription = await extractAgentDescription(agentSource) || void 0;
2840
3424
  }
2841
3425
  readmeContent = this.generateReadme(
@@ -2847,15 +3431,15 @@ var PackingService = class {
2847
3431
  );
2848
3432
  }
2849
3433
  const readmePath = path8.join(pkgOutputDir, "README.md");
2850
- fs2.writeFileSync(readmePath, readmeContent);
3434
+ fs4.writeFileSync(readmePath, readmeContent);
2851
3435
  result.filesCreated.push(readmePath);
2852
3436
  if (removeOriginals || itemSelections) {
2853
3437
  result.filesRemoved = [];
2854
3438
  for (const item of allItems) {
2855
3439
  const selection = itemSelections?.find((s) => s.name === item.name && s.type === item.type);
2856
- const shouldRemove = selection ? selection.mode === "extract" : removeOriginals && item.sharedWith.length === 0;
2857
- if (shouldRemove && fs2.existsSync(item.filePath)) {
2858
- fs2.unlinkSync(item.filePath);
3440
+ const shouldRemove = selection ? selection.mode === "extract" : removeOriginals && item.sharedWith.length === 0 && item.type !== "thread-endpoint" && item.type !== "effect";
3441
+ if (shouldRemove && fs4.existsSync(item.filePath)) {
3442
+ fs4.unlinkSync(item.filePath);
2859
3443
  result.filesRemoved.push(item.filePath);
2860
3444
  }
2861
3445
  }
@@ -2906,11 +3490,11 @@ var PackingService = class {
2906
3490
  const resolved = path8.resolve(path8.dirname(importer), source);
2907
3491
  let tsResolved = resolved;
2908
3492
  if (!resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
2909
- if (fs2.existsSync(`${resolved}.ts`)) {
3493
+ if (fs4.existsSync(`${resolved}.ts`)) {
2910
3494
  tsResolved = `${resolved}.ts`;
2911
- } else if (fs2.existsSync(`${resolved}.js`)) {
3495
+ } else if (fs4.existsSync(`${resolved}.js`)) {
2912
3496
  tsResolved = `${resolved}.js`;
2913
- } else if (fs2.existsSync(`${resolved}/index.ts`)) {
3497
+ } else if (fs4.existsSync(`${resolved}/index.ts`)) {
2914
3498
  tsResolved = `${resolved}/index.ts`;
2915
3499
  }
2916
3500
  }
@@ -2963,7 +3547,7 @@ var PackingService = class {
2963
3547
  // Local dependencies have been inlined
2964
3548
 
2965
3549
  `;
2966
- fs2.writeFileSync(outputPath, header + bundledCode);
3550
+ fs4.writeFileSync(outputPath, header + bundledCode);
2967
3551
  await bundle.close();
2968
3552
  } catch (error) {
2969
3553
  await bundle.close();
@@ -2986,6 +3570,10 @@ var PackingService = class {
2986
3570
  return "models";
2987
3571
  case "hook":
2988
3572
  return "hooks";
3573
+ case "effect":
3574
+ return "effects";
3575
+ case "thread-endpoint":
3576
+ return "thread-endpoints";
2989
3577
  }
2990
3578
  }
2991
3579
  /**
@@ -3005,7 +3593,9 @@ var PackingService = class {
3005
3593
  prompts: dedupe(analysis.constituents.prompts),
3006
3594
  tools: dedupe(analysis.constituents.tools),
3007
3595
  models: dedupe(analysis.constituents.models),
3008
- hooks: dedupe(analysis.constituents.hooks)
3596
+ hooks: dedupe(analysis.constituents.hooks),
3597
+ effects: dedupe(analysis.constituents.effects),
3598
+ threadEndpoints: dedupe(analysis.constituents.threadEndpoints)
3009
3599
  };
3010
3600
  }
3011
3601
  /**
@@ -3050,6 +3640,9 @@ var PackingService = class {
3050
3640
  for (const hook of constituents.hooks) {
3051
3641
  lines.push(`export { default as ${this.quoteName(hook.name)} } from './hooks/${hook.name}.js';`);
3052
3642
  }
3643
+ for (const effect of constituents.effects) {
3644
+ lines.push(`export { default as ${this.quoteName(effect.name)} } from './effects/${effect.name}.js';`);
3645
+ }
3053
3646
  lines.push("");
3054
3647
  lines.push("// Registry exports for lazy loading");
3055
3648
  lines.push("export const agents = {");
@@ -3082,6 +3675,18 @@ var PackingService = class {
3082
3675
  }
3083
3676
  lines.push("};");
3084
3677
  lines.push("");
3678
+ lines.push("export const effects = {");
3679
+ for (const effect of constituents.effects) {
3680
+ lines.push(` ${this.quoteName(effect.name)}: async () => (await import('./effects/${effect.name}.js')).default,`);
3681
+ }
3682
+ lines.push("};");
3683
+ lines.push("");
3684
+ lines.push("export const threadEndpoints = {");
3685
+ for (const endpoint of constituents.threadEndpoints) {
3686
+ lines.push(` ${this.quoteName(endpoint.name)}: async () => (await import('./thread-endpoints/${endpoint.name}.js')).default,`);
3687
+ }
3688
+ lines.push("};");
3689
+ lines.push("");
3085
3690
  lines.push("export const __meta = " + JSON.stringify(meta, null, 2) + ";");
3086
3691
  lines.push("");
3087
3692
  return lines.join("\n");
@@ -3097,6 +3702,9 @@ var PackingService = class {
3097
3702
  " PromptDefinition,",
3098
3703
  " ToolDefinition,",
3099
3704
  " ModelDefinition,",
3705
+ " EffectDefinition,",
3706
+ " Controller,",
3707
+ " MarkedThreadEndpoint,",
3100
3708
  " PackedMeta,",
3101
3709
  "} from '@standardagents/spec';",
3102
3710
  "",
@@ -3128,6 +3736,11 @@ var PackingService = class {
3128
3736
  lines.push(`export declare const ${hook.name}: unknown;`);
3129
3737
  }
3130
3738
  }
3739
+ for (const effect of constituents.effects) {
3740
+ if (this.isValidIdentifier(effect.name)) {
3741
+ lines.push(`export declare const ${effect.name}: EffectDefinition<any, any>;`);
3742
+ }
3743
+ }
3131
3744
  lines.push("");
3132
3745
  lines.push("export declare const agents: {");
3133
3746
  for (const agent of constituents.agents) {
@@ -3159,6 +3772,18 @@ var PackingService = class {
3159
3772
  }
3160
3773
  lines.push("};");
3161
3774
  lines.push("");
3775
+ lines.push("export declare const effects: {");
3776
+ for (const effect of constituents.effects) {
3777
+ lines.push(` readonly ${this.quoteName(effect.name)}: DefinitionLoader<EffectDefinition<any, any>>;`);
3778
+ }
3779
+ lines.push("};");
3780
+ lines.push("");
3781
+ lines.push("export declare const threadEndpoints: {");
3782
+ for (const endpoint of constituents.threadEndpoints) {
3783
+ lines.push(` readonly ${this.quoteName(endpoint.name)}: DefinitionLoader<MarkedThreadEndpoint | Controller>;`);
3784
+ }
3785
+ lines.push("};");
3786
+ lines.push("");
3162
3787
  lines.push("export declare const __meta: PackedMeta;");
3163
3788
  lines.push("");
3164
3789
  return lines.join("\n");
@@ -3166,7 +3791,7 @@ var PackingService = class {
3166
3791
  /**
3167
3792
  * Generate the package.json file with dependencies.
3168
3793
  */
3169
- generatePackageJson(packageName, version, agentName, externalDeps, rootDir, license, licenseOwner) {
3794
+ generatePackageJson(packageName, version, agentName, effects, threadEndpoints, externalDeps, rootDir, license, licenseOwner) {
3170
3795
  const dependencies = {
3171
3796
  "@standardagents/spec": this.resolvePackageVersion("@standardagents/spec", rootDir)
3172
3797
  };
@@ -3187,7 +3812,9 @@ var PackingService = class {
3187
3812
  },
3188
3813
  keywords: ["standardagent"],
3189
3814
  standardagent: {
3190
- entryAgents: [agentName]
3815
+ entryAgents: [agentName],
3816
+ ...effects.length > 0 ? { effects } : {},
3817
+ ...threadEndpoints.length > 0 ? { threadEndpoints } : {}
3191
3818
  },
3192
3819
  files: license ? ["dist", "LICENSE", "README.md"] : ["dist", "README.md"],
3193
3820
  dependencies
@@ -3347,11 +3974,11 @@ Copyright (c) ${year} ${copyrightHolder}
3347
3974
  getPackedInfo(packageId, rootDir) {
3348
3975
  const packedDir = path8.join(rootDir, "agents", "packed");
3349
3976
  let packageDir = path8.join(packedDir, packageId);
3350
- if (!fs2.existsSync(packageDir)) {
3351
- if (!fs2.existsSync(packedDir)) {
3977
+ if (!fs4.existsSync(packageDir)) {
3978
+ if (!fs4.existsSync(packedDir)) {
3352
3979
  return null;
3353
3980
  }
3354
- const dirs = fs2.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
3981
+ const dirs = fs4.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
3355
3982
  const matchingDir = dirs.find(
3356
3983
  (d) => d === packageId || d === `standardagent-${packageId}` || d === `standardagent-${packageId.replace(/_/g, "-")}`
3357
3984
  );
@@ -3361,14 +3988,14 @@ Copyright (c) ${year} ${copyrightHolder}
3361
3988
  packageDir = path8.join(packedDir, matchingDir);
3362
3989
  }
3363
3990
  const pkgJsonPath = path8.join(packageDir, "package.json");
3364
- if (!fs2.existsSync(pkgJsonPath)) {
3991
+ if (!fs4.existsSync(pkgJsonPath)) {
3365
3992
  return null;
3366
3993
  }
3367
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
3994
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3368
3995
  let readme;
3369
3996
  const readmePath = path8.join(packageDir, "README.md");
3370
- if (fs2.existsSync(readmePath)) {
3371
- readme = fs2.readFileSync(readmePath, "utf-8");
3997
+ if (fs4.existsSync(readmePath)) {
3998
+ readme = fs4.readFileSync(readmePath, "utf-8");
3372
3999
  }
3373
4000
  return {
3374
4001
  packageName: pkgJson.name,
@@ -3387,10 +4014,10 @@ Copyright (c) ${year} ${copyrightHolder}
3387
4014
  */
3388
4015
  listPackedPackages(rootDir) {
3389
4016
  const packedDir = path8.join(rootDir, "agents", "packed");
3390
- if (!fs2.existsSync(packedDir)) {
4017
+ if (!fs4.existsSync(packedDir)) {
3391
4018
  return [];
3392
4019
  }
3393
- return fs2.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
4020
+ return fs4.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
3394
4021
  }
3395
4022
  /**
3396
4023
  * Generate README.md content for a packed agent.
@@ -3437,17 +4064,17 @@ ${license || "See LICENSE file"}
3437
4064
  * Find a file by name in a directory.
3438
4065
  */
3439
4066
  async findFile(dir, name) {
3440
- if (!fs2.existsSync(dir)) {
4067
+ if (!fs4.existsSync(dir)) {
3441
4068
  return null;
3442
4069
  }
3443
4070
  const exactPath = path8.join(dir, `${name}.ts`);
3444
- if (fs2.existsSync(exactPath)) {
4071
+ if (fs4.existsSync(exactPath)) {
3445
4072
  return exactPath;
3446
4073
  }
3447
- const files = fs2.readdirSync(dir).filter((f) => f.endsWith(".ts"));
4074
+ const files = fs4.readdirSync(dir).filter((f) => f.endsWith(".ts"));
3448
4075
  for (const file of files) {
3449
4076
  const filePath = path8.join(dir, file);
3450
- const source = fs2.readFileSync(filePath, "utf-8");
4077
+ const source = fs4.readFileSync(filePath, "utf-8");
3451
4078
  const extractedName = await extractDefinitionName(source);
3452
4079
  if (extractedName === name) {
3453
4080
  return filePath;
@@ -3460,14 +4087,14 @@ ${license || "See LICENSE file"}
3460
4087
  */
3461
4088
  async listAgents(rootDir) {
3462
4089
  const agentsDir = path8.join(rootDir, "agents", "agents");
3463
- if (!fs2.existsSync(agentsDir)) {
4090
+ if (!fs4.existsSync(agentsDir)) {
3464
4091
  return [];
3465
4092
  }
3466
- const files = fs2.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
4093
+ const files = fs4.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
3467
4094
  const agents = [];
3468
4095
  for (const file of files) {
3469
4096
  const filePath = path8.join(agentsDir, file);
3470
- const source = fs2.readFileSync(filePath, "utf-8");
4097
+ const source = fs4.readFileSync(filePath, "utf-8");
3471
4098
  const name = await extractDefinitionName(source);
3472
4099
  if (name) {
3473
4100
  agents.push(name);
@@ -3517,7 +4144,7 @@ var PackageDiscoveryService = class {
3517
4144
  async discoverNpmPackages() {
3518
4145
  const packages = [];
3519
4146
  const nodeModulesDir = path8.join(this.config.rootDir, "node_modules");
3520
- if (!fs2.existsSync(nodeModulesDir)) {
4147
+ if (!fs4.existsSync(nodeModulesDir)) {
3521
4148
  return packages;
3522
4149
  }
3523
4150
  const rootEntries = await this.scanDirectory(nodeModulesDir);
@@ -3553,11 +4180,11 @@ var PackageDiscoveryService = class {
3553
4180
  */
3554
4181
  async checkNpmPackage(pkgDir, pkgName) {
3555
4182
  const pkgJsonPath = path8.join(pkgDir, "package.json");
3556
- if (!fs2.existsSync(pkgJsonPath)) {
4183
+ if (!fs4.existsSync(pkgJsonPath)) {
3557
4184
  return null;
3558
4185
  }
3559
4186
  try {
3560
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4187
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3561
4188
  const isStandardAgent = (
3562
4189
  // Has "standardagent" keyword
3563
4190
  pkgJson.keywords?.includes("standardagent") || // Has "standardagent-*" prefix
@@ -3571,12 +4198,16 @@ var PackageDiscoveryService = class {
3571
4198
  if (!pkgJson.standardagent?.entryAgents) {
3572
4199
  return null;
3573
4200
  }
4201
+ const effects = Array.isArray(pkgJson.standardagent.effects) && pkgJson.standardagent.effects.every((effectName) => typeof effectName === "string") ? pkgJson.standardagent.effects : void 0;
4202
+ const threadEndpoints = Array.isArray(pkgJson.standardagent.threadEndpoints) && pkgJson.standardagent.threadEndpoints.every((endpoint) => typeof endpoint === "string") ? pkgJson.standardagent.threadEndpoints : void 0;
3574
4203
  return {
3575
4204
  packageId: pkgJson.name || pkgName,
3576
4205
  version: pkgJson.version || "0.0.0",
3577
4206
  source: "npm",
3578
4207
  path: pkgDir,
3579
4208
  entryAgents: pkgJson.standardagent.entryAgents,
4209
+ ...effects ? { effects } : {},
4210
+ ...threadEndpoints ? { threadEndpoints } : {},
3580
4211
  description: pkgJson.description
3581
4212
  };
3582
4213
  } catch (error) {
@@ -3590,21 +4221,21 @@ var PackageDiscoveryService = class {
3590
4221
  */
3591
4222
  async discoverLocalPackages() {
3592
4223
  const packages = [];
3593
- if (!fs2.existsSync(this.config.packedDir)) {
4224
+ if (!fs4.existsSync(this.config.packedDir)) {
3594
4225
  return packages;
3595
4226
  }
3596
4227
  const entries = await this.scanDirectory(this.config.packedDir);
3597
4228
  for (const entry of entries) {
3598
4229
  if (entry.startsWith(".")) continue;
3599
4230
  const pkgDir = path8.join(this.config.packedDir, entry);
3600
- const stat = fs2.statSync(pkgDir);
4231
+ const stat = fs4.statSync(pkgDir);
3601
4232
  if (!stat.isDirectory()) continue;
3602
4233
  if (entry.startsWith("@")) {
3603
4234
  const scopeEntries = await this.scanDirectory(pkgDir);
3604
4235
  for (const scopedPkg of scopeEntries) {
3605
4236
  if (scopedPkg.startsWith(".")) continue;
3606
4237
  const scopedPkgDir = path8.join(pkgDir, scopedPkg);
3607
- const scopedStat = fs2.statSync(scopedPkgDir);
4238
+ const scopedStat = fs4.statSync(scopedPkgDir);
3608
4239
  if (!scopedStat.isDirectory()) continue;
3609
4240
  const fullName = `${entry}/${scopedPkg}`;
3610
4241
  const pkg = await this.checkLocalPackage(scopedPkgDir, fullName);
@@ -3628,20 +4259,24 @@ var PackageDiscoveryService = class {
3628
4259
  */
3629
4260
  async checkLocalPackage(pkgDir, dirName) {
3630
4261
  const pkgJsonPath = path8.join(pkgDir, "package.json");
3631
- if (!fs2.existsSync(pkgJsonPath)) {
4262
+ if (!fs4.existsSync(pkgJsonPath)) {
3632
4263
  return null;
3633
4264
  }
3634
4265
  try {
3635
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4266
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3636
4267
  if (!pkgJson.standardagent?.entryAgents) {
3637
4268
  return null;
3638
4269
  }
4270
+ const effects = Array.isArray(pkgJson.standardagent.effects) && pkgJson.standardagent.effects.every((effectName) => typeof effectName === "string") ? pkgJson.standardagent.effects : void 0;
4271
+ const threadEndpoints = Array.isArray(pkgJson.standardagent.threadEndpoints) && pkgJson.standardagent.threadEndpoints.every((endpoint) => typeof endpoint === "string") ? pkgJson.standardagent.threadEndpoints : void 0;
3639
4272
  return {
3640
4273
  packageId: pkgJson.name || dirName,
3641
4274
  version: pkgJson.version || "0.0.0",
3642
4275
  source: "local",
3643
4276
  path: pkgDir,
3644
4277
  entryAgents: pkgJson.standardagent.entryAgents,
4278
+ ...effects ? { effects } : {},
4279
+ ...threadEndpoints ? { threadEndpoints } : {},
3645
4280
  description: pkgJson.description
3646
4281
  };
3647
4282
  } catch (error) {
@@ -3653,10 +4288,10 @@ var PackageDiscoveryService = class {
3653
4288
  * Scan a directory and return entry names.
3654
4289
  */
3655
4290
  async scanDirectory(dir) {
3656
- if (!fs2.existsSync(dir)) {
4291
+ if (!fs4.existsSync(dir)) {
3657
4292
  return [];
3658
4293
  }
3659
- const entries = fs2.readdirSync(dir);
4294
+ const entries = fs4.readdirSync(dir);
3660
4295
  return entries;
3661
4296
  }
3662
4297
  /**
@@ -3667,7 +4302,10 @@ var PackageDiscoveryService = class {
3667
4302
  return false;
3668
4303
  }
3669
4304
  const f = field;
3670
- return Array.isArray(f.entryAgents) && f.entryAgents.length > 0 && f.entryAgents.every((e) => typeof e === "string");
4305
+ const hasValidEntryAgents = Array.isArray(f.entryAgents) && f.entryAgents.length > 0 && f.entryAgents.every((e) => typeof e === "string");
4306
+ const hasValidEffects = f.effects === void 0 || Array.isArray(f.effects) && f.effects.every((effectName) => typeof effectName === "string");
4307
+ const hasValidThreadEndpoints = f.threadEndpoints === void 0 || Array.isArray(f.threadEndpoints) && f.threadEndpoints.every((endpoint) => typeof endpoint === "string");
4308
+ return hasValidEntryAgents && hasValidEffects && hasValidThreadEndpoints;
3671
4309
  }
3672
4310
  /**
3673
4311
  * Get a package by ID.
@@ -3698,7 +4336,27 @@ var TYPE_TO_DIR = {
3698
4336
  prompt: "prompts",
3699
4337
  tool: "tools",
3700
4338
  model: "models",
3701
- hook: "hooks"
4339
+ hook: "hooks",
4340
+ effect: "effects",
4341
+ "thread-endpoint": "thread-endpoints"
4342
+ };
4343
+ var TYPE_TO_TARGET_DIR = {
4344
+ agent: "agents",
4345
+ prompt: "prompts",
4346
+ tool: "tools",
4347
+ model: "models",
4348
+ hook: "hooks",
4349
+ effect: "effects",
4350
+ "thread-endpoint": "api"
4351
+ };
4352
+ var TYPE_TO_REGISTRY_NAME = {
4353
+ agent: "agents",
4354
+ prompt: "prompts",
4355
+ tool: "tools",
4356
+ model: "models",
4357
+ hook: "hooks",
4358
+ effect: "effects",
4359
+ "thread-endpoint": "threadEndpoints"
3702
4360
  };
3703
4361
  var UnpackingService = class {
3704
4362
  /**
@@ -3727,11 +4385,11 @@ var UnpackingService = class {
3727
4385
  analysis.version = pkg.version;
3728
4386
  analysis.source = pkg.source;
3729
4387
  const indexPath = path8.join(pkg.path, "dist", "index.js");
3730
- if (!fs2.existsSync(indexPath)) {
4388
+ if (!fs4.existsSync(indexPath)) {
3731
4389
  analysis.errors.push(`Package index not found: ${indexPath}`);
3732
4390
  return analysis;
3733
4391
  }
3734
- const indexContent = fs2.readFileSync(indexPath, "utf-8");
4392
+ const indexContent = fs4.readFileSync(indexPath, "utf-8");
3735
4393
  const registryItems = await this.parseIndexExports(indexContent);
3736
4394
  const availableItems = /* @__PURE__ */ new Map();
3737
4395
  for (const item of registryItems) {
@@ -3740,15 +4398,15 @@ var UnpackingService = class {
3740
4398
  const agentsDir = path8.join(rootDir, "agents");
3741
4399
  const itemsWithRelations = [];
3742
4400
  for (const item of registryItems) {
3743
- const targetPath = path8.join(agentsDir, TYPE_TO_DIR[item.type], `${item.name}.ts`);
4401
+ const targetPath = path8.join(agentsDir, TYPE_TO_TARGET_DIR[item.type], `${item.name}.ts`);
3744
4402
  const sourcePath = path8.join(pkg.path, "dist", TYPE_TO_DIR[item.type], `${item.name}.js`);
3745
4403
  const existsGlobally = this.fileExists(targetPath);
3746
- const sourceExists = fs2.existsSync(sourcePath);
4404
+ const sourceExists = fs4.existsSync(sourcePath);
3747
4405
  if (!sourceExists) {
3748
4406
  analysis.warnings.push(`Source file not found for ${item.type} "${item.name}": ${sourcePath}`);
3749
4407
  continue;
3750
4408
  }
3751
- const bundledCode = fs2.readFileSync(sourcePath, "utf-8");
4409
+ const bundledCode = fs4.readFileSync(sourcePath, "utf-8");
3752
4410
  const children = await this.discoverRelationships(item.type, item.name, bundledCode, availableItems);
3753
4411
  itemsWithRelations.push({
3754
4412
  name: item.name,
@@ -3758,10 +4416,10 @@ var UnpackingService = class {
3758
4416
  action: existsGlobally ? "skip" : "generate"
3759
4417
  });
3760
4418
  for (const child of children) {
3761
- const childTargetPath = path8.join(agentsDir, TYPE_TO_DIR[child.type], `${child.name}.ts`);
4419
+ const childTargetPath = path8.join(agentsDir, TYPE_TO_TARGET_DIR[child.type], `${child.name}.ts`);
3762
4420
  const childSourcePath = path8.join(pkg.path, "dist", TYPE_TO_DIR[child.type], `${child.name}.js`);
3763
4421
  const childExists = this.fileExists(childTargetPath);
3764
- const childSourceExists = fs2.existsSync(childSourcePath);
4422
+ const childSourceExists = fs4.existsSync(childSourcePath);
3765
4423
  if (!childSourceExists) {
3766
4424
  continue;
3767
4425
  }
@@ -3865,7 +4523,7 @@ var UnpackingService = class {
3865
4523
  }
3866
4524
  const itemsToProcess = this.applySelections(analysis.items, itemSelections);
3867
4525
  const pkgJsonPath = path8.join(pkg.path, "package.json");
3868
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4526
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3869
4527
  let author = "";
3870
4528
  if (typeof pkgJson.author === "string") {
3871
4529
  author = pkgJson.author;
@@ -3891,16 +4549,16 @@ var UnpackingService = class {
3891
4549
  }
3892
4550
  try {
3893
4551
  const sourcePath = path8.join(pkg.path, "dist", TYPE_TO_DIR[item.type], `${item.name}.js`);
3894
- const bundledCode = fs2.readFileSync(sourcePath, "utf-8");
4552
+ const bundledCode = fs4.readFileSync(sourcePath, "utf-8");
3895
4553
  let tsCode = await transformBundledJs(bundledCode);
3896
4554
  if (item.type === "agent") {
3897
4555
  tsCode = await injectAgentMetadata(tsCode, agentMetadata);
3898
4556
  }
3899
4557
  const dir = path8.dirname(item.targetPath);
3900
- if (!fs2.existsSync(dir)) {
3901
- fs2.mkdirSync(dir, { recursive: true });
4558
+ if (!fs4.existsSync(dir)) {
4559
+ fs4.mkdirSync(dir, { recursive: true });
3902
4560
  }
3903
- fs2.writeFileSync(item.targetPath, tsCode);
4561
+ fs4.writeFileSync(item.targetPath, tsCode);
3904
4562
  result.filesGenerated.push(item.targetPath);
3905
4563
  } catch (error) {
3906
4564
  result.warnings.push(
@@ -3945,7 +4603,7 @@ var UnpackingService = class {
3945
4603
  true
3946
4604
  );
3947
4605
  const items = [];
3948
- const registryTypes = ["agent", "prompt", "tool", "model", "hook"];
4606
+ const registryTypes = ["agent", "prompt", "tool", "model", "hook", "effect", "thread-endpoint"];
3949
4607
  function visit(node) {
3950
4608
  if (ts.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
3951
4609
  for (const decl of node.declarationList.declarations) {
@@ -3953,7 +4611,7 @@ var UnpackingService = class {
3953
4611
  const varName = decl.name.text;
3954
4612
  let itemType = null;
3955
4613
  for (const type of registryTypes) {
3956
- if (varName === TYPE_TO_DIR[type]) {
4614
+ if (varName === TYPE_TO_REGISTRY_NAME[type]) {
3957
4615
  itemType = type;
3958
4616
  break;
3959
4617
  }
@@ -3991,9 +4649,9 @@ var UnpackingService = class {
3991
4649
  if (pkgIdentifier.startsWith("/") || pkgIdentifier.startsWith("./")) {
3992
4650
  const absolutePath = path8.isAbsolute(pkgIdentifier) ? pkgIdentifier : path8.join(rootDir, pkgIdentifier);
3993
4651
  const pkgJsonPath2 = path8.join(absolutePath, "package.json");
3994
- if (fs2.existsSync(pkgJsonPath2)) {
4652
+ if (fs4.existsSync(pkgJsonPath2)) {
3995
4653
  try {
3996
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath2, "utf-8"));
4654
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath2, "utf-8"));
3997
4655
  if (pkgJson.standardagent?.entryAgents) {
3998
4656
  return {
3999
4657
  packageId: pkgJson.name || path8.basename(absolutePath),
@@ -4010,9 +4668,9 @@ var UnpackingService = class {
4010
4668
  }
4011
4669
  const packedDir = path8.join(rootDir, "agents", "packed", pkgIdentifier);
4012
4670
  const pkgJsonPath = path8.join(packedDir, "package.json");
4013
- if (fs2.existsSync(pkgJsonPath)) {
4671
+ if (fs4.existsSync(pkgJsonPath)) {
4014
4672
  try {
4015
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4673
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
4016
4674
  if (pkgJson.standardagent?.entryAgents) {
4017
4675
  return {
4018
4676
  packageId: pkgJson.name || pkgIdentifier,
@@ -4053,18 +4711,18 @@ var UnpackingService = class {
4053
4711
  * Check if a file exists.
4054
4712
  */
4055
4713
  fileExists(filePath) {
4056
- if (fs2.existsSync(filePath)) {
4714
+ if (fs4.existsSync(filePath)) {
4057
4715
  return true;
4058
4716
  }
4059
4717
  const withoutExt = filePath.replace(/\.(ts|js)$/, "");
4060
- return fs2.existsSync(`${withoutExt}.ts`) || fs2.existsSync(`${withoutExt}.js`);
4718
+ return fs4.existsSync(`${withoutExt}.ts`) || fs4.existsSync(`${withoutExt}.js`);
4061
4719
  }
4062
4720
  /**
4063
4721
  * Recursively delete a directory.
4064
4722
  */
4065
4723
  deleteDirectory(dirPath) {
4066
- if (fs2.existsSync(dirPath)) {
4067
- fs2.rmSync(dirPath, { recursive: true, force: true });
4724
+ if (fs4.existsSync(dirPath)) {
4725
+ fs4.rmSync(dirPath, { recursive: true, force: true });
4068
4726
  }
4069
4727
  }
4070
4728
  /**
@@ -4141,7 +4799,7 @@ var NpmPublishService = class {
4141
4799
  };
4142
4800
  }
4143
4801
  const pkgJsonPath = path8.join(packageDir, "package.json");
4144
- if (!fs2.existsSync(pkgJsonPath)) {
4802
+ if (!fs4.existsSync(pkgJsonPath)) {
4145
4803
  return {
4146
4804
  success: false,
4147
4805
  output: "",
@@ -4151,7 +4809,7 @@ var NpmPublishService = class {
4151
4809
  let packageName;
4152
4810
  let version;
4153
4811
  try {
4154
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4812
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
4155
4813
  packageName = pkgJson.name;
4156
4814
  version = pkgJson.version;
4157
4815
  } catch (e) {
@@ -4167,7 +4825,7 @@ var NpmPublishService = class {
4167
4825
  registry=${registry}
4168
4826
  `;
4169
4827
  try {
4170
- fs2.writeFileSync(npmrcPath, npmrcContent, { mode: 384 });
4828
+ fs4.writeFileSync(npmrcPath, npmrcContent, { mode: 384 });
4171
4829
  const args = ["publish"];
4172
4830
  if (dryRun) {
4173
4831
  args.push("--dry-run");
@@ -4199,8 +4857,8 @@ registry=${registry}
4199
4857
  };
4200
4858
  } finally {
4201
4859
  try {
4202
- if (fs2.existsSync(npmrcPath)) {
4203
- fs2.unlinkSync(npmrcPath);
4860
+ if (fs4.existsSync(npmrcPath)) {
4861
+ fs4.unlinkSync(npmrcPath);
4204
4862
  }
4205
4863
  } catch {
4206
4864
  }
@@ -4267,11 +4925,11 @@ var VIRTUAL_BUILDER_ID = "virtual:@standardagents/builder";
4267
4925
  var RESOLVED_VIRTUAL_BUILDER_ID = "\0" + VIRTUAL_BUILDER_ID;
4268
4926
  function scanApiDirectory(dir, baseRoute = "") {
4269
4927
  const routes = [];
4270
- if (!fs2__default.existsSync(dir)) {
4928
+ if (!fs4__default.existsSync(dir)) {
4271
4929
  return routes;
4272
4930
  }
4273
4931
  try {
4274
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
4932
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
4275
4933
  for (const entry of entries) {
4276
4934
  const fullPath = path8__default.join(dir, entry.name);
4277
4935
  if (entry.isDirectory()) {
@@ -4318,12 +4976,114 @@ function scanApiDirectory(dir, baseRoute = "") {
4318
4976
  return [];
4319
4977
  }
4320
4978
  }
4979
+ function parseThreadEndpointKey(endpointKey) {
4980
+ const normalized = endpointKey.replace(/\\/g, "/");
4981
+ const parts = normalized.split("/");
4982
+ const rawFileName = parts.pop() || "index";
4983
+ const convertedSegments = parts.filter(Boolean).map((segment) => segment.replace(/\[([^\]]+)\]/g, ":$1"));
4984
+ let routePath = convertedSegments.length > 0 ? `/${convertedSegments.join("/")}` : "";
4985
+ let method = "";
4986
+ if (rawFileName.includes(".")) {
4987
+ const fileParts = rawFileName.split(".");
4988
+ const methodPart = fileParts[fileParts.length - 1].toUpperCase();
4989
+ if (["GET", "POST", "PUT", "DELETE", "PATCH"].includes(methodPart)) {
4990
+ method = methodPart;
4991
+ const pathPart = fileParts.slice(0, -1).join(".");
4992
+ if (pathPart !== "index") {
4993
+ const convertedPath = pathPart.replace(/\[([^\]]+)\]/g, ":$1");
4994
+ routePath += `/${convertedPath}`;
4995
+ }
4996
+ } else if (rawFileName !== "index") {
4997
+ const convertedPath = rawFileName.replace(/\[([^\]]+)\]/g, ":$1");
4998
+ routePath += `/${convertedPath}`;
4999
+ }
5000
+ } else if (rawFileName !== "index") {
5001
+ const convertedPath = rawFileName.replace(/\[([^\]]+)\]/g, ":$1");
5002
+ routePath += `/${convertedPath}`;
5003
+ }
5004
+ return {
5005
+ method,
5006
+ route: routePath || "/"
5007
+ };
5008
+ }
5009
+ function discoverPackedPackageDirectories(packedDir) {
5010
+ if (!fs4__default.existsSync(packedDir)) {
5011
+ return [];
5012
+ }
5013
+ const packageDirs = [];
5014
+ const entries = fs4__default.readdirSync(packedDir, { withFileTypes: true }).filter((entry) => entry.isDirectory());
5015
+ for (const entry of entries) {
5016
+ const fullPath = path8__default.join(packedDir, entry.name);
5017
+ const packageJsonPath = path8__default.join(fullPath, "package.json");
5018
+ if (fs4__default.existsSync(packageJsonPath)) {
5019
+ packageDirs.push(fullPath);
5020
+ continue;
5021
+ }
5022
+ if (!entry.name.startsWith("@")) {
5023
+ continue;
5024
+ }
5025
+ const scopedEntries = fs4__default.readdirSync(fullPath, { withFileTypes: true }).filter((scopedEntry) => scopedEntry.isDirectory());
5026
+ for (const scopedEntry of scopedEntries) {
5027
+ const scopedPackagePath = path8__default.join(fullPath, scopedEntry.name);
5028
+ const scopedPackageJson = path8__default.join(scopedPackagePath, "package.json");
5029
+ if (fs4__default.existsSync(scopedPackageJson)) {
5030
+ packageDirs.push(scopedPackagePath);
5031
+ }
5032
+ }
5033
+ }
5034
+ return packageDirs;
5035
+ }
5036
+ function scanPackedDistDirectory(packagePath, outputDir, subDir) {
5037
+ const fullPath = path8__default.join(packagePath, outputDir, subDir);
5038
+ if (!fs4__default.existsSync(fullPath)) {
5039
+ return [];
5040
+ }
5041
+ return fs4__default.readdirSync(fullPath).filter((fileName) => fileName.endsWith(".js") || fileName.endsWith(".ts")).map((fileName) => ({
5042
+ name: fileName.replace(/\.(js|ts)$/, ""),
5043
+ path: path8__default.join(fullPath, fileName).replace(/\\/g, "/")
5044
+ }));
5045
+ }
5046
+ function scanPackedThreadEndpoints(packagePath, outputDir) {
5047
+ const rootDir = path8__default.join(packagePath, outputDir, "thread-endpoints");
5048
+ if (!fs4__default.existsSync(rootDir)) {
5049
+ return [];
5050
+ }
5051
+ const endpoints = [];
5052
+ const scan = (dir, relativeDir = "") => {
5053
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
5054
+ for (const entry of entries) {
5055
+ const nextRelative = relativeDir ? path8__default.posix.join(relativeDir, entry.name) : entry.name;
5056
+ const absolutePath = path8__default.join(dir, entry.name);
5057
+ if (entry.isDirectory()) {
5058
+ scan(absolutePath, nextRelative);
5059
+ continue;
5060
+ }
5061
+ if (!entry.isFile()) {
5062
+ continue;
5063
+ }
5064
+ if (!entry.name.endsWith(".js") && !entry.name.endsWith(".ts")) {
5065
+ continue;
5066
+ }
5067
+ const key = nextRelative.replace(/\.(js|ts)$/, "").replace(/\\/g, "/");
5068
+ const parsed = parseThreadEndpointKey(key);
5069
+ endpoints.push({
5070
+ name: key,
5071
+ path: absolutePath.replace(/\\/g, "/"),
5072
+ method: parsed.method,
5073
+ route: parsed.route
5074
+ });
5075
+ }
5076
+ };
5077
+ scan(rootDir);
5078
+ endpoints.sort((a, b) => a.name.localeCompare(b.name));
5079
+ return endpoints;
5080
+ }
4321
5081
  function isSnakeCase(str) {
4322
5082
  return /^[a-z][a-z0-9_]*[a-z0-9]$/.test(str) || /^[a-z]$/.test(str);
4323
5083
  }
4324
5084
  function validateToolFile(filePath, fileName) {
4325
5085
  try {
4326
- const content = fs2__default.readFileSync(filePath, "utf-8");
5086
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4327
5087
  const hasDefaultExport = /export\s+default\s+defineTool/.test(content);
4328
5088
  if (!hasDefaultExport) {
4329
5089
  return `Tool file '${fileName}.ts' must have a default export using defineTool()`;
@@ -4335,10 +5095,10 @@ function validateToolFile(filePath, fileName) {
4335
5095
  }
4336
5096
  async function scanToolsDirectory(dir) {
4337
5097
  const tools = [];
4338
- if (!fs2__default.existsSync(dir)) {
5098
+ if (!fs4__default.existsSync(dir)) {
4339
5099
  return tools;
4340
5100
  }
4341
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5101
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4342
5102
  for (const entry of entries) {
4343
5103
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4344
5104
  const fileName = entry.name.replace(".ts", "");
@@ -4370,10 +5130,10 @@ async function scanToolsDirectory(dir) {
4370
5130
  }
4371
5131
  async function scanHooksDirectory(dir) {
4372
5132
  const hooks = [];
4373
- if (!fs2__default.existsSync(dir)) {
5133
+ if (!fs4__default.existsSync(dir)) {
4374
5134
  return hooks;
4375
5135
  }
4376
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5136
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4377
5137
  for (const entry of entries) {
4378
5138
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4379
5139
  const fileName = entry.name.replace(".ts", "");
@@ -4383,7 +5143,7 @@ async function scanHooksDirectory(dir) {
4383
5143
  const filePath = path8__default.join(dir, entry.name);
4384
5144
  const importPath = "./" + path8__default.relative(process.cwd(), filePath).replace(/\\/g, "/");
4385
5145
  try {
4386
- const content = fs2__default.readFileSync(filePath, "utf-8");
5146
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4387
5147
  const idMatch = content.match(/id:\s*['"]([^'"]+)['"]/);
4388
5148
  const hookMatch = content.match(/hook:\s*['"]([^'"]+)['"]/);
4389
5149
  if (idMatch && hookMatch) {
@@ -4406,16 +5166,16 @@ async function scanHooksDirectory(dir) {
4406
5166
  }
4407
5167
  async function scanConfigDirectory(dir, definePattern) {
4408
5168
  const items = [];
4409
- if (!fs2__default.existsSync(dir)) {
5169
+ if (!fs4__default.existsSync(dir)) {
4410
5170
  return items;
4411
5171
  }
4412
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5172
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4413
5173
  for (const entry of entries) {
4414
5174
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4415
5175
  const filePath = path8__default.join(dir, entry.name);
4416
5176
  const importPath = "./" + path8__default.relative(process.cwd(), filePath).replace(/\\/g, "/");
4417
5177
  try {
4418
- const content = fs2__default.readFileSync(filePath, "utf-8");
5178
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4419
5179
  const hasDefaultExport = definePattern.test(content);
4420
5180
  if (!hasDefaultExport) {
4421
5181
  items.push({
@@ -4457,10 +5217,10 @@ async function scanAgentsDirectory(dir) {
4457
5217
  }
4458
5218
  async function scanEffectsDirectory(dir) {
4459
5219
  const effects = [];
4460
- if (!fs2__default.existsSync(dir)) {
5220
+ if (!fs4__default.existsSync(dir)) {
4461
5221
  return effects;
4462
5222
  }
4463
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5223
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4464
5224
  for (const entry of entries) {
4465
5225
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4466
5226
  const fileName = entry.name.replace(".ts", "");
@@ -4470,7 +5230,7 @@ async function scanEffectsDirectory(dir) {
4470
5230
  continue;
4471
5231
  }
4472
5232
  try {
4473
- const content = fs2__default.readFileSync(filePath, "utf-8");
5233
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4474
5234
  if (!content.includes("defineEffect")) {
4475
5235
  continue;
4476
5236
  }
@@ -4532,7 +5292,7 @@ function agentbuilder(options = {}) {
4532
5292
  const rou3Path = path8__default.join(__dirname, "../dist/rou3.js");
4533
5293
  let rou3Code = "";
4534
5294
  try {
4535
- rou3Code = fs2__default.readFileSync(rou3Path, "utf-8").replace(/^export \{[^}]+\};?\s*$/gm, "").replace(/\/\/# sourceMappingURL=.+$/gm, "").trim();
5295
+ rou3Code = fs4__default.readFileSync(rou3Path, "utf-8").replace(/^export \{[^}]+\};?\s*$/gm, "").replace(/\/\/# sourceMappingURL=.+$/gm, "").trim();
4536
5296
  } catch (err) {
4537
5297
  console.warn("[vite-plugin-agent] Could not read rou3.js for inlining:", err);
4538
5298
  }
@@ -4883,7 +5643,7 @@ function agentbuilder(options = {}) {
4883
5643
  );
4884
5644
  return {
4885
5645
  // Set publicDir to builder's client assets so Cloudflare plugin preserves assets config
4886
- publicDir: fs2__default.existsSync(builderClientDir) ? builderClientDir : void 0,
5646
+ publicDir: fs4__default.existsSync(builderClientDir) ? builderClientDir : void 0,
4887
5647
  build: {
4888
5648
  rollupOptions: {
4889
5649
  // The packing system dynamically imports rollup, typescript, and related
@@ -5051,6 +5811,7 @@ ${toolsCode}
5051
5811
  }
5052
5812
  if (id === RESOLVED_VIRTUAL_ROUTES_ID) {
5053
5813
  const threadRoutes = scanApiDirectory(threadApiDir);
5814
+ const toAbsolutePath = (inputPath) => path8__default.resolve(process.cwd(), inputPath).replace(/\\/g, "/");
5054
5815
  const threadRouteCode = threadRoutes.map(({ method, route, importPath }) => {
5055
5816
  const apiRoute = `/api/threads/:id${route}`;
5056
5817
  return ` addRoute(
@@ -5058,6 +5819,44 @@ ${toolsCode}
5058
5819
  "${method}",
5059
5820
  "${apiRoute}",
5060
5821
  /* v${routesVersion} */ async () => (await import("${importPath}")).default
5822
+ );`;
5823
+ }).join("\n");
5824
+ const packedThreadRoutes = [];
5825
+ const packedDir = path8__default.resolve(process.cwd(), "agents/packed");
5826
+ const packedPackageDirs = discoverPackedPackageDirectories(packedDir);
5827
+ for (const packagePath of packedPackageDirs) {
5828
+ const packageJsonPath = path8__default.join(packagePath, "package.json");
5829
+ if (!fs4__default.existsSync(packageJsonPath)) {
5830
+ continue;
5831
+ }
5832
+ try {
5833
+ const packageJson = JSON.parse(fs4__default.readFileSync(packageJsonPath, "utf-8"));
5834
+ if (!packageJson.standardagent) {
5835
+ continue;
5836
+ }
5837
+ const packageId = String(packageJson.name || path8__default.basename(packagePath));
5838
+ const packageIdSegment = encodeURIComponent(packageId);
5839
+ const mainEntry = packageJson.main || "./dist/index.js";
5840
+ const outputDir2 = path8__default.dirname(mainEntry).replace(/^\.\//, "");
5841
+ const threadEndpoints = scanPackedThreadEndpoints(packagePath, outputDir2);
5842
+ for (const endpoint of threadEndpoints) {
5843
+ const apiRoute = `/api/packages/${packageIdSegment}/threads/:id${endpoint.route}`;
5844
+ packedThreadRoutes.push({
5845
+ method: endpoint.method,
5846
+ route: apiRoute,
5847
+ importPath: endpoint.path
5848
+ });
5849
+ }
5850
+ } catch (error) {
5851
+ console.warn(`[vite-plugin-agent] Failed to parse packed package routes in ${packagePath}:`, error);
5852
+ }
5853
+ }
5854
+ const packedThreadRouteCode = packedThreadRoutes.map(({ method, route, importPath }) => {
5855
+ return ` addRoute(
5856
+ router,
5857
+ "${method}",
5858
+ "${route}",
5859
+ /* v${routesVersion} */ async () => (await import("${toAbsolutePath(importPath)}")).default
5061
5860
  );`;
5062
5861
  }).join("\n");
5063
5862
  return `// Inline rou3 router code (no external imports) /* v${routesVersion} */
@@ -5099,6 +5898,11 @@ function isPublicRoute(routePath) {
5099
5898
  return true;
5100
5899
  }
5101
5900
 
5901
+ // Packed thread routes are also public
5902
+ if (routePath.startsWith('/api/packages/') && routePath.includes('/threads/')) {
5903
+ return true;
5904
+ }
5905
+
5102
5906
  // Provider icon routes are public (used by <img src>)
5103
5907
  if (routePath.startsWith('/api/providers/') && routePath.includes('/icon')) {
5104
5908
  return true;
@@ -5181,6 +5985,9 @@ export async function router(request, env) {
5181
5985
  // Register user thread API routes
5182
5986
  ${threadRouteCode}
5183
5987
 
5988
+ // Register packed thread API routes
5989
+ ${packedThreadRouteCode}
5990
+
5184
5991
  const routeMatch = findRoute(
5185
5992
  router,
5186
5993
  request.method.toUpperCase(),
@@ -5468,6 +6275,7 @@ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package
5468
6275
  const models = await scanModelsDirectory(modelsDir);
5469
6276
  const prompts = await scanPromptsDirectory(promptsDir);
5470
6277
  const agents = await scanAgentsDirectory(agentsDir);
6278
+ const effects = await scanEffectsDirectory(effectsDir);
5471
6279
  const toAbsolutePath = (relativePath) => {
5472
6280
  if (relativePath.startsWith("./")) {
5473
6281
  return path8__default.resolve(process.cwd(), relativePath).replace(/\\/g, "/");
@@ -5494,49 +6302,45 @@ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package
5494
6302
  const absPath = toAbsolutePath(importPath);
5495
6303
  return ` "${id2}": async () => (await import("${absPath}")).default,`;
5496
6304
  }).join("\n");
6305
+ const globalEffectsCode = effects.filter((e) => !e.error).map(({ name, importPath }) => {
6306
+ const absPath = toAbsolutePath(importPath);
6307
+ return ` "${name}": async () => (await import("${absPath}")).default,`;
6308
+ }).join("\n");
5497
6309
  const packedDir = path8__default.resolve(process.cwd(), "agents/packed");
5498
6310
  const packedPackages = [];
5499
- if (fs2__default.existsSync(packedDir)) {
6311
+ if (fs4__default.existsSync(packedDir)) {
5500
6312
  console.log(`[vite-plugin-agent] Scanning packed directory: ${packedDir}`);
5501
- const pkgDirs = fs2__default.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
5502
- console.log(`[vite-plugin-agent] Found package dirs: ${pkgDirs.join(", ")}`);
5503
- for (const pkgDirName of pkgDirs) {
5504
- const pkgPath = path8__default.join(packedDir, pkgDirName);
6313
+ const packageDirs = discoverPackedPackageDirectories(packedDir);
6314
+ console.log(`[vite-plugin-agent] Found package dirs: ${packageDirs.join(", ")}`);
6315
+ for (const pkgPath of packageDirs) {
5505
6316
  const pkgJsonPath = path8__default.join(pkgPath, "package.json");
5506
- if (fs2__default.existsSync(pkgJsonPath)) {
6317
+ if (fs4__default.existsSync(pkgJsonPath)) {
5507
6318
  try {
5508
- const pkgJson = JSON.parse(fs2__default.readFileSync(pkgJsonPath, "utf-8"));
5509
- console.log(`[vite-plugin-agent] Loaded ${pkgDirName} package.json, standardagent:`, pkgJson.standardagent);
6319
+ const pkgJson = JSON.parse(fs4__default.readFileSync(pkgJsonPath, "utf-8"));
6320
+ console.log(`[vite-plugin-agent] Loaded ${pkgPath} package.json, standardagent:`, pkgJson.standardagent);
5510
6321
  if (!pkgJson.standardagent) {
5511
6322
  continue;
5512
6323
  }
5513
6324
  const mainEntry = pkgJson.main || "./dist/index.js";
5514
6325
  const outputDir2 = path8__default.dirname(mainEntry).replace(/^\.\//, "");
5515
- const scanPackedDir = async (subDir) => {
5516
- const fullPath = path8__default.join(pkgPath, outputDir2, subDir);
5517
- if (!fs2__default.existsSync(fullPath)) return [];
5518
- const files = fs2__default.readdirSync(fullPath).filter((f) => f.endsWith(".js") || f.endsWith(".ts")).map((f) => ({
5519
- name: f.replace(/\.(js|ts)$/, ""),
5520
- path: path8__default.join(fullPath, f).replace(/\\/g, "/")
5521
- }));
5522
- return files;
5523
- };
5524
6326
  const pkg = {
5525
6327
  packageId: pkgJson.name,
5526
6328
  version: pkgJson.version,
5527
6329
  entryAgents: pkgJson.standardagent.entryAgents || [],
5528
6330
  items: {
5529
- agents: await scanPackedDir("agents"),
5530
- prompts: await scanPackedDir("prompts"),
5531
- tools: await scanPackedDir("tools"),
5532
- models: await scanPackedDir("models"),
5533
- hooks: await scanPackedDir("hooks")
6331
+ agents: scanPackedDistDirectory(pkgPath, outputDir2, "agents"),
6332
+ prompts: scanPackedDistDirectory(pkgPath, outputDir2, "prompts"),
6333
+ tools: scanPackedDistDirectory(pkgPath, outputDir2, "tools"),
6334
+ models: scanPackedDistDirectory(pkgPath, outputDir2, "models"),
6335
+ hooks: scanPackedDistDirectory(pkgPath, outputDir2, "hooks"),
6336
+ effects: scanPackedDistDirectory(pkgPath, outputDir2, "effects"),
6337
+ threadEndpoints: scanPackedThreadEndpoints(pkgPath, outputDir2)
5534
6338
  }
5535
6339
  };
5536
6340
  console.log(`[vite-plugin-agent] Scanned package ${pkgJson.name}:`, pkg.items.agents);
5537
6341
  packedPackages.push(pkg);
5538
6342
  } catch (err) {
5539
- console.warn(`[vite-plugin-agent] Failed to load packed package ${pkgDirName}:`, err);
6343
+ console.warn(`[vite-plugin-agent] Failed to load packed package ${pkgPath}:`, err);
5540
6344
  }
5541
6345
  }
5542
6346
  }
@@ -5557,6 +6361,12 @@ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package
5557
6361
  return { ...mod.default, __package: ${signature} };
5558
6362
  },`
5559
6363
  ).join("\n");
6364
+ const genThreadEndpointLoaders = (items) => items.map(
6365
+ (item) => ` "${item.name}": async () => (await import("${item.path}")).default,`
6366
+ ).join("\n");
6367
+ const genEffectLoaders = (items) => items.map(
6368
+ (item) => ` "${item.name}": async () => (await import("${item.path}")).default,`
6369
+ ).join("\n");
5560
6370
  return ` "${pkg.packageId}": {
5561
6371
  agents: {
5562
6372
  ${genLoaders(pkg.items.agents)}
@@ -5572,6 +6382,12 @@ ${genLoaders(pkg.items.models)}
5572
6382
  },
5573
6383
  hooks: {
5574
6384
  ${genLoaders(pkg.items.hooks)}
6385
+ },
6386
+ effects: {
6387
+ ${genEffectLoaders(pkg.items.effects)}
6388
+ },
6389
+ threadEndpoints: {
6390
+ ${genThreadEndpointLoaders(pkg.items.threadEndpoints)}
5575
6391
  },
5576
6392
  entryAgents: ${JSON.stringify(pkg.entryAgents)},
5577
6393
  signature: ${signature},
@@ -5597,6 +6413,10 @@ ${globalModelsCode}
5597
6413
  hooks: {
5598
6414
  ${globalHooksCode}
5599
6415
  },
6416
+ effects: {
6417
+ ${globalEffectsCode}
6418
+ },
6419
+ threadEndpoints: {},
5600
6420
  },
5601
6421
  packages: {
5602
6422
  ${packagesCode}
@@ -6414,14 +7234,14 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6414
7234
  const rootDir = process.cwd();
6415
7235
  const packedDir = path8__default.join(rootDir, "agents", "packed");
6416
7236
  let packageDir = path8__default.join(packedDir, packageId);
6417
- if (!fs2__default.existsSync(packageDir)) {
6418
- if (!fs2__default.existsSync(packedDir)) {
7237
+ if (!fs4__default.existsSync(packageDir)) {
7238
+ if (!fs4__default.existsSync(packedDir)) {
6419
7239
  res.statusCode = 400;
6420
7240
  res.setHeader("Content-Type", "application/json");
6421
7241
  res.end(JSON.stringify({ error: "No packed packages found. Pack the agent first." }));
6422
7242
  return;
6423
7243
  }
6424
- const dirs = fs2__default.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
7244
+ const dirs = fs4__default.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
6425
7245
  const matchingDir = dirs.find(
6426
7246
  (d) => d === packageId || d === `standardagent-${packageId}` || d === `standardagent-${packageId.replace(/_/g, "-")}`
6427
7247
  );
@@ -6439,8 +7259,8 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6439
7259
  let tokenSource = body.token ? "provided" : "environment";
6440
7260
  if (!token) {
6441
7261
  const devVarsPath = path8__default.join(rootDir, ".dev.vars");
6442
- if (fs2__default.existsSync(devVarsPath)) {
6443
- const devVars = fs2__default.readFileSync(devVarsPath, "utf-8");
7262
+ if (fs4__default.existsSync(devVarsPath)) {
7263
+ const devVars = fs4__default.readFileSync(devVarsPath, "utf-8");
6444
7264
  const match = devVars.match(/^NPM_TOKEN=(.+)$/m);
6445
7265
  if (match) {
6446
7266
  token = match[1].trim();
@@ -6592,8 +7412,8 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6592
7412
  filePath = path8__default.join(clientDir, "index.html");
6593
7413
  }
6594
7414
  try {
6595
- if (fs2__default.existsSync(filePath)) {
6596
- let content = fs2__default.readFileSync(filePath);
7415
+ if (fs4__default.existsSync(filePath)) {
7416
+ let content = fs4__default.readFileSync(filePath);
6597
7417
  const ext = path8__default.extname(filePath).toLowerCase();
6598
7418
  if (ext === ".html") {
6599
7419
  const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { mountPoint: "${mountPoint}", devMode: true };</script>`;
@@ -6639,21 +7459,21 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6639
7459
  currentDir,
6640
7460
  isInDist ? "./client" : "../dist/client"
6641
7461
  );
6642
- if (!fs2__default.existsSync(clientDir)) {
7462
+ if (!fs4__default.existsSync(clientDir)) {
6643
7463
  console.warn(`[agentbuilder] Client directory not found at ${clientDir}`);
6644
7464
  return;
6645
7465
  }
6646
- fs2__default.mkdirSync(mountDir, { recursive: true });
7466
+ fs4__default.mkdirSync(mountDir, { recursive: true });
6647
7467
  function copyRecursive(src, dest) {
6648
- const entries = fs2__default.readdirSync(src, { withFileTypes: true });
7468
+ const entries = fs4__default.readdirSync(src, { withFileTypes: true });
6649
7469
  for (const entry of entries) {
6650
7470
  const srcPath = path8__default.join(src, entry.name);
6651
7471
  const destPath = path8__default.join(dest, entry.name);
6652
7472
  if (entry.isDirectory()) {
6653
- fs2__default.mkdirSync(destPath, { recursive: true });
7473
+ fs4__default.mkdirSync(destPath, { recursive: true });
6654
7474
  copyRecursive(srcPath, destPath);
6655
7475
  } else {
6656
- let content = fs2__default.readFileSync(srcPath);
7476
+ let content = fs4__default.readFileSync(srcPath);
6657
7477
  if (entry.name === "index.html") {
6658
7478
  const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { mountPoint: "${mountPoint}" };</script>`;
6659
7479
  let htmlContent = content.toString();
@@ -6662,7 +7482,7 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6662
7482
  htmlContent = htmlContent.replace("</head>", `${configScript}</head>`);
6663
7483
  content = Buffer.from(htmlContent);
6664
7484
  }
6665
- fs2__default.writeFileSync(destPath, content);
7485
+ fs4__default.writeFileSync(destPath, content);
6666
7486
  }
6667
7487
  }
6668
7488
  }