@standardagents/builder 0.12.8 → 0.13.0-next.c55f029

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
@@ -1322,49 +1481,135 @@ function transformModelData(data) {
1322
1481
  return transformed;
1323
1482
  }
1324
1483
  function validateModelData(data) {
1484
+ const errors = {};
1325
1485
  if (!data.name || typeof data.name !== "string") {
1326
- return "Model name is required and must be a string";
1486
+ errors["name"] = "Model name is required";
1327
1487
  }
1328
1488
  if (!data.provider || typeof data.provider !== "string") {
1329
- return "Model provider is required and must be a string";
1330
- }
1331
- const validProviders = Object.keys(PROVIDER_PACKAGE_MAP);
1332
- if (!validProviders.includes(data.provider)) {
1333
- return `Invalid provider '${data.provider}'. Must be one of: ${validProviders.join(", ")}`;
1489
+ errors["provider"] = "Provider is required";
1490
+ } else {
1491
+ const validProviders = Object.keys(PROVIDER_PACKAGE_MAP);
1492
+ if (!validProviders.includes(data.provider)) {
1493
+ errors["provider"] = `Invalid provider '${data.provider}'. Must be one of: ${validProviders.join(", ")}`;
1494
+ }
1334
1495
  }
1335
1496
  if (!data.model || typeof data.model !== "string") {
1336
- return "Model ID is required and must be a string";
1497
+ errors["model"] = "Model ID is required";
1337
1498
  }
1338
1499
  if (data.inputPrice !== void 0 && typeof data.inputPrice !== "number") {
1339
- return "inputPrice must be a number";
1500
+ errors["input_price"] = "Input price must be a number";
1340
1501
  }
1341
1502
  if (data.outputPrice !== void 0 && typeof data.outputPrice !== "number") {
1342
- return "outputPrice must be a number";
1503
+ errors["output_price"] = "Output price must be a number";
1343
1504
  }
1344
1505
  if (data.cachedPrice !== void 0 && typeof data.cachedPrice !== "number") {
1345
- return "cachedPrice must be a number";
1506
+ errors["cached_price"] = "Cached price must be a number";
1346
1507
  }
1347
1508
  if (data.fallbacks !== void 0) {
1348
1509
  if (!Array.isArray(data.fallbacks)) {
1349
- return "fallbacks must be an array";
1350
- }
1351
- for (const fallback of data.fallbacks) {
1352
- if (typeof fallback !== "string") {
1353
- return "Each fallback must be a string (model name)";
1510
+ errors["fallbacks"] = "Fallbacks must be an array";
1511
+ } else {
1512
+ for (const fallback of data.fallbacks) {
1513
+ if (typeof fallback !== "string") {
1514
+ errors["fallbacks"] = "Each fallback must be a string (model name)";
1515
+ break;
1516
+ }
1354
1517
  }
1355
1518
  }
1356
1519
  }
1357
1520
  if (data.includedProviders !== void 0) {
1358
1521
  if (!Array.isArray(data.includedProviders)) {
1359
- return "includedProviders must be an array";
1360
- }
1361
- for (const provider of data.includedProviders) {
1362
- if (typeof provider !== "string") {
1363
- return "Each includedProvider must be a string";
1522
+ errors["included_providers"] = "Included providers must be an array";
1523
+ } else {
1524
+ for (const provider of data.includedProviders) {
1525
+ if (typeof provider !== "string") {
1526
+ errors["included_providers"] = "Each included provider must be a string";
1527
+ break;
1528
+ }
1364
1529
  }
1365
1530
  }
1366
1531
  }
1367
- return null;
1532
+ return Object.keys(errors).length > 0 ? errors : null;
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;
1368
1613
  }
1369
1614
  function transformPromptData(data) {
1370
1615
  const transformed = {};
@@ -1395,8 +1640,11 @@ function transformPromptData(data) {
1395
1640
  if (transformed.reasoningEffort) {
1396
1641
  transformed.reasoning.effort = transformed.reasoningEffort;
1397
1642
  }
1398
- if (transformed.reasoningMaxTokens) {
1399
- transformed.reasoning.maxTokens = transformed.reasoningMaxTokens;
1643
+ if (transformed.reasoningMaxTokens !== void 0 && transformed.reasoningMaxTokens !== null && transformed.reasoningMaxTokens !== "") {
1644
+ const num = Number(transformed.reasoningMaxTokens);
1645
+ if (!isNaN(num)) {
1646
+ transformed.reasoning.maxTokens = num;
1647
+ }
1400
1648
  }
1401
1649
  if (transformed.reasoningExclude !== void 0) {
1402
1650
  transformed.reasoning.exclude = transformed.reasoningExclude;
@@ -1409,6 +1657,22 @@ function transformPromptData(data) {
1409
1657
  delete transformed.reasoningExclude;
1410
1658
  delete transformed.includeReasoning;
1411
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
+ }
1412
1676
  return transformed;
1413
1677
  }
1414
1678
  function getPromptFilePath(promptsDir, name) {
@@ -1417,22 +1681,22 @@ function getPromptFilePath(promptsDir, name) {
1417
1681
  }
1418
1682
  function promptExists(promptsDir, name) {
1419
1683
  const filePath = getPromptFilePath(promptsDir, name);
1420
- return fs2__default.existsSync(filePath);
1684
+ return fs4__default.existsSync(filePath);
1421
1685
  }
1422
1686
  async function savePrompt(promptsDir, data, overwrite = false) {
1423
1687
  try {
1424
- if (!fs2__default.existsSync(promptsDir)) {
1425
- fs2__default.mkdirSync(promptsDir, { recursive: true });
1688
+ if (!fs4__default.existsSync(promptsDir)) {
1689
+ fs4__default.mkdirSync(promptsDir, { recursive: true });
1426
1690
  }
1427
1691
  const filePath = getPromptFilePath(promptsDir, data.name);
1428
- if (!overwrite && fs2__default.existsSync(filePath)) {
1692
+ if (!overwrite && fs4__default.existsSync(filePath)) {
1429
1693
  return {
1430
1694
  success: false,
1431
1695
  error: `Prompt file already exists: ${filePath}. Use update to modify existing prompts.`
1432
1696
  };
1433
1697
  }
1434
1698
  const content = generatePromptFile(data);
1435
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
1699
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1436
1700
  return {
1437
1701
  success: true,
1438
1702
  filePath
@@ -1447,13 +1711,13 @@ async function savePrompt(promptsDir, data, overwrite = false) {
1447
1711
  async function deletePrompt(promptsDir, name) {
1448
1712
  try {
1449
1713
  const filePath = getPromptFilePath(promptsDir, name);
1450
- if (!fs2__default.existsSync(filePath)) {
1714
+ if (!fs4__default.existsSync(filePath)) {
1451
1715
  return {
1452
1716
  success: false,
1453
1717
  error: `Prompt file not found: ${filePath}`
1454
1718
  };
1455
1719
  }
1456
- await fs2__default.promises.unlink(filePath);
1720
+ await fs4__default.promises.unlink(filePath);
1457
1721
  return {
1458
1722
  success: true,
1459
1723
  filePath
@@ -1469,25 +1733,25 @@ async function renamePrompt(promptsDir, oldName, newName) {
1469
1733
  try {
1470
1734
  const oldFilePath = getPromptFilePath(promptsDir, oldName);
1471
1735
  const newFilePath = getPromptFilePath(promptsDir, newName);
1472
- if (!fs2__default.existsSync(oldFilePath)) {
1736
+ if (!fs4__default.existsSync(oldFilePath)) {
1473
1737
  return {
1474
1738
  success: false,
1475
1739
  error: `Prompt file not found: ${oldFilePath}`
1476
1740
  };
1477
1741
  }
1478
- if (fs2__default.existsSync(newFilePath)) {
1742
+ if (fs4__default.existsSync(newFilePath)) {
1479
1743
  return {
1480
1744
  success: false,
1481
1745
  error: `Prompt file already exists: ${newFilePath}`
1482
1746
  };
1483
1747
  }
1484
- const content = await fs2__default.promises.readFile(oldFilePath, "utf-8");
1748
+ const content = await fs4__default.promises.readFile(oldFilePath, "utf-8");
1485
1749
  const updatedContent = content.replace(
1486
1750
  /name:\s*['"]([^'"]+)['"]/,
1487
1751
  `name: '${newName}'`
1488
1752
  );
1489
- await fs2__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
1490
- await fs2__default.promises.unlink(oldFilePath);
1753
+ await fs4__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
1754
+ await fs4__default.promises.unlink(oldFilePath);
1491
1755
  return {
1492
1756
  success: true,
1493
1757
  filePath: newFilePath
@@ -1500,56 +1764,165 @@ async function renamePrompt(promptsDir, oldName, newName) {
1500
1764
  }
1501
1765
  }
1502
1766
  function validatePromptData(data) {
1767
+ const errors = {};
1503
1768
  if (!data.name || typeof data.name !== "string") {
1504
- return "Prompt name is required and must be a string";
1505
- }
1506
- if (data.name.includes("/")) {
1507
- return "Prompt name cannot contain '/'. Reserved for namespace qualification.";
1769
+ errors["name"] = "Prompt name is required";
1770
+ } else if (data.name.includes("/")) {
1771
+ errors["name"] = "Prompt name cannot contain '/'";
1508
1772
  }
1509
1773
  if (!data.model || typeof data.model !== "string") {
1510
- return "Prompt model is required and must be a string";
1774
+ errors["model_id"] = "Model is required";
1511
1775
  }
1512
1776
  if (data.toolDescription !== void 0 && typeof data.toolDescription !== "string") {
1513
- return "toolDescription must be a string";
1777
+ errors["tool_description"] = "Tool description must be a string";
1514
1778
  }
1515
- if (data.prompt !== void 0 && typeof data.prompt !== "string") {
1516
- return "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";
1517
1781
  }
1518
- const booleanFields = ["includeChat", "includePastTools", "parallelToolCalls"];
1519
- for (const field of booleanFields) {
1520
- if (data[field] !== void 0 && typeof data[field] !== "boolean") {
1521
- return `${field} must be a boolean`;
1782
+ const booleanFieldMap = {
1783
+ includeChat: "include_chat",
1784
+ includePastTools: "include_past_tools",
1785
+ parallelToolCalls: "parallel_tool_calls"
1786
+ };
1787
+ for (const [camelField, snakeField] of Object.entries(booleanFieldMap)) {
1788
+ if (data[camelField] !== void 0 && typeof data[camelField] !== "boolean") {
1789
+ errors[snakeField] = `${snakeField} must be a boolean`;
1522
1790
  }
1523
1791
  }
1524
1792
  if (data.toolChoice !== void 0) {
1525
1793
  const validChoices = ["auto", "none", "required"];
1526
1794
  if (!validChoices.includes(data.toolChoice)) {
1527
- return `Invalid toolChoice '${data.toolChoice}'. Must be one of: ${validChoices.join(", ")}`;
1795
+ errors["tool_choice"] = `Invalid tool choice '${data.toolChoice}'. Must be one of: ${validChoices.join(", ")}`;
1528
1796
  }
1529
1797
  }
1530
1798
  if (data.tools !== void 0 && !Array.isArray(data.tools)) {
1531
- return "tools must be an array";
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
+ }
1532
1858
  }
1533
- if (data.reasoning !== void 0) {
1534
- if (typeof data.reasoning !== "object") {
1535
- return "reasoning must be an object";
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";
1536
1864
  }
1537
- if (data.reasoning.effort !== void 0) {
1538
- const validEfforts = ["low", "medium", "high"];
1539
- if (!validEfforts.includes(data.reasoning.effort)) {
1540
- return `Invalid reasoning.effort '${data.reasoning.effort}'. Must be one of: ${validEfforts.join(", ")}`;
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
+ }
1541
1891
  }
1542
1892
  }
1543
- if (data.reasoning.maxTokens !== void 0 && typeof data.reasoning.maxTokens !== "number") {
1544
- return "reasoning.maxTokens must be a number";
1893
+ }
1894
+ if (data.reasoning !== void 0) {
1895
+ if (typeof data.reasoning !== "object") {
1896
+ errors["reasoning_effort"] = "Reasoning configuration is invalid";
1897
+ } else {
1898
+ if (data.reasoning.effort !== void 0) {
1899
+ const validEfforts = ["low", "medium", "high"];
1900
+ if (!validEfforts.includes(data.reasoning.effort)) {
1901
+ errors["reasoning_effort"] = `Invalid reasoning effort '${data.reasoning.effort}'. Must be one of: ${validEfforts.join(", ")}`;
1902
+ }
1903
+ }
1904
+ if (data.reasoning.maxTokens !== void 0 && typeof data.reasoning.maxTokens !== "number") {
1905
+ errors["reasoning_max_tokens"] = "Max reasoning tokens must be a number";
1906
+ }
1545
1907
  }
1546
1908
  }
1547
- return null;
1909
+ return Object.keys(errors).length > 0 ? errors : null;
1548
1910
  }
1549
1911
  function transformAgentData(data) {
1550
1912
  const transformed = {
1551
1913
  name: data.name
1552
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
+ };
1553
1926
  if (data.title) {
1554
1927
  transformed.title = data.title;
1555
1928
  }
@@ -1577,9 +1950,36 @@ function transformAgentData(data) {
1577
1950
  if (data.side_a_max_steps !== void 0) {
1578
1951
  transformed.sideA.maxSteps = data.side_a_max_steps;
1579
1952
  }
1580
- 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) {
1581
1961
  transformed.sideA.endSessionTool = data.side_a_end_session_tool;
1582
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
+ }
1583
1983
  if (data.side_a_manual_stop_condition !== void 0) {
1584
1984
  transformed.sideA.manualStopCondition = data.side_a_manual_stop_condition;
1585
1985
  }
@@ -1602,9 +2002,36 @@ function transformAgentData(data) {
1602
2002
  if (data.side_b_max_steps !== void 0) {
1603
2003
  transformed.sideB.maxSteps = data.side_b_max_steps;
1604
2004
  }
1605
- 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) {
1606
2013
  transformed.sideB.endSessionTool = data.side_b_end_session_tool;
1607
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
+ }
1608
2035
  if (data.side_b_manual_stop_condition !== void 0) {
1609
2036
  transformed.sideB.manualStopCondition = data.side_b_manual_stop_condition;
1610
2037
  }
@@ -1615,6 +2042,9 @@ function transformAgentData(data) {
1615
2042
  if (data.tool_description) {
1616
2043
  transformed.toolDescription = data.tool_description;
1617
2044
  }
2045
+ if (data.env !== void 0 || data.tenvs !== void 0) {
2046
+ transformed.env = normalizeStringEnvRecord(data.env ?? data.tenvs) ?? {};
2047
+ }
1618
2048
  return transformed;
1619
2049
  }
1620
2050
  function getAgentFilePath(agentsDir, name) {
@@ -1623,11 +2053,11 @@ function getAgentFilePath(agentsDir, name) {
1623
2053
  }
1624
2054
  function agentExists(agentsDir, name) {
1625
2055
  const filePath = getAgentFilePath(agentsDir, name);
1626
- return fs2__default.existsSync(filePath);
2056
+ return fs4__default.existsSync(filePath);
1627
2057
  }
1628
2058
  function extractAgentMetadata(filePath) {
1629
2059
  try {
1630
- const content = fs2__default.readFileSync(filePath, "utf-8");
2060
+ const content = fs4__default.readFileSync(filePath, "utf-8");
1631
2061
  const metadata = {};
1632
2062
  const packageNameMatch = content.match(/packageName:\s*['"]([^'"]+)['"]/);
1633
2063
  if (packageNameMatch) metadata.packageName = packageNameMatch[1];
@@ -1644,17 +2074,17 @@ function extractAgentMetadata(filePath) {
1644
2074
  }
1645
2075
  async function saveAgent(agentsDir, data, overwrite = false) {
1646
2076
  try {
1647
- if (!fs2__default.existsSync(agentsDir)) {
1648
- fs2__default.mkdirSync(agentsDir, { recursive: true });
2077
+ if (!fs4__default.existsSync(agentsDir)) {
2078
+ fs4__default.mkdirSync(agentsDir, { recursive: true });
1649
2079
  }
1650
2080
  const filePath = getAgentFilePath(agentsDir, data.name);
1651
- if (!overwrite && fs2__default.existsSync(filePath)) {
2081
+ if (!overwrite && fs4__default.existsSync(filePath)) {
1652
2082
  return {
1653
2083
  success: false,
1654
2084
  error: `Agent file already exists: ${filePath}. Use update to modify existing agents.`
1655
2085
  };
1656
2086
  }
1657
- if (overwrite && fs2__default.existsSync(filePath)) {
2087
+ if (overwrite && fs4__default.existsSync(filePath)) {
1658
2088
  const existingMetadata = extractAgentMetadata(filePath);
1659
2089
  if (existingMetadata.packageName && !data.packageName) {
1660
2090
  data.packageName = existingMetadata.packageName;
@@ -1670,7 +2100,7 @@ async function saveAgent(agentsDir, data, overwrite = false) {
1670
2100
  }
1671
2101
  }
1672
2102
  const content = generateAgentFile(data);
1673
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
2103
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1674
2104
  return {
1675
2105
  success: true,
1676
2106
  filePath
@@ -1685,13 +2115,13 @@ async function saveAgent(agentsDir, data, overwrite = false) {
1685
2115
  async function deleteAgent(agentsDir, name) {
1686
2116
  try {
1687
2117
  const filePath = getAgentFilePath(agentsDir, name);
1688
- if (!fs2__default.existsSync(filePath)) {
2118
+ if (!fs4__default.existsSync(filePath)) {
1689
2119
  return {
1690
2120
  success: false,
1691
2121
  error: `Agent file not found: ${filePath}`
1692
2122
  };
1693
2123
  }
1694
- await fs2__default.promises.unlink(filePath);
2124
+ await fs4__default.promises.unlink(filePath);
1695
2125
  return {
1696
2126
  success: true,
1697
2127
  filePath
@@ -1707,25 +2137,25 @@ async function renameModel(modelsDir, oldName, newName) {
1707
2137
  try {
1708
2138
  const oldFilePath = getModelFilePath(modelsDir, oldName);
1709
2139
  const newFilePath = getModelFilePath(modelsDir, newName);
1710
- if (!fs2__default.existsSync(oldFilePath)) {
2140
+ if (!fs4__default.existsSync(oldFilePath)) {
1711
2141
  return {
1712
2142
  success: false,
1713
2143
  error: `Model file not found: ${oldFilePath}`
1714
2144
  };
1715
2145
  }
1716
- if (fs2__default.existsSync(newFilePath)) {
2146
+ if (fs4__default.existsSync(newFilePath)) {
1717
2147
  return {
1718
2148
  success: false,
1719
2149
  error: `Model file already exists: ${newFilePath}`
1720
2150
  };
1721
2151
  }
1722
- const content = await fs2__default.promises.readFile(oldFilePath, "utf-8");
2152
+ const content = await fs4__default.promises.readFile(oldFilePath, "utf-8");
1723
2153
  const updatedContent = content.replace(
1724
2154
  /name:\s*['"]([^'"]+)['"]/,
1725
2155
  `name: '${newName}'`
1726
2156
  );
1727
- await fs2__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
1728
- await fs2__default.promises.unlink(oldFilePath);
2157
+ await fs4__default.promises.writeFile(newFilePath, updatedContent, "utf-8");
2158
+ await fs4__default.promises.unlink(oldFilePath);
1729
2159
  return {
1730
2160
  success: true,
1731
2161
  filePath: newFilePath
@@ -1739,17 +2169,17 @@ async function renameModel(modelsDir, oldName, newName) {
1739
2169
  }
1740
2170
  async function updateModelReferencesInPrompts(promptsDir, oldModelName, newModelName) {
1741
2171
  const updatedFiles = [];
1742
- if (!fs2__default.existsSync(promptsDir)) {
2172
+ if (!fs4__default.existsSync(promptsDir)) {
1743
2173
  return updatedFiles;
1744
2174
  }
1745
- const files = fs2__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
2175
+ const files = fs4__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
1746
2176
  for (const file of files) {
1747
2177
  const filePath = path8__default.join(promptsDir, file);
1748
- let content = await fs2__default.promises.readFile(filePath, "utf-8");
2178
+ let content = await fs4__default.promises.readFile(filePath, "utf-8");
1749
2179
  const modelRegex = new RegExp(`model:\\s*['"]${escapeRegExp(oldModelName)}['"]`, "g");
1750
2180
  if (modelRegex.test(content)) {
1751
2181
  content = content.replace(modelRegex, `model: '${newModelName}'`);
1752
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
2182
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1753
2183
  updatedFiles.push(filePath);
1754
2184
  }
1755
2185
  }
@@ -1757,13 +2187,13 @@ async function updateModelReferencesInPrompts(promptsDir, oldModelName, newModel
1757
2187
  }
1758
2188
  async function updatePromptReferencesInPrompts(promptsDir, oldPromptName, newPromptName) {
1759
2189
  const updatedFiles = [];
1760
- if (!fs2__default.existsSync(promptsDir)) {
2190
+ if (!fs4__default.existsSync(promptsDir)) {
1761
2191
  return updatedFiles;
1762
2192
  }
1763
- const files = fs2__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
2193
+ const files = fs4__default.readdirSync(promptsDir).filter((f) => f.endsWith(".ts"));
1764
2194
  for (const file of files) {
1765
2195
  const filePath = path8__default.join(promptsDir, file);
1766
- let content = await fs2__default.promises.readFile(filePath, "utf-8");
2196
+ let content = await fs4__default.promises.readFile(filePath, "utf-8");
1767
2197
  let modified = false;
1768
2198
  const toolsArrayRegex = /tools:\s*\[([^\]]*)\]/gs;
1769
2199
  const newContent = content.replace(toolsArrayRegex, (match) => {
@@ -1776,7 +2206,7 @@ async function updatePromptReferencesInPrompts(promptsDir, oldPromptName, newPro
1776
2206
  return replaced;
1777
2207
  });
1778
2208
  if (modified) {
1779
- await fs2__default.promises.writeFile(filePath, newContent, "utf-8");
2209
+ await fs4__default.promises.writeFile(filePath, newContent, "utf-8");
1780
2210
  updatedFiles.push(filePath);
1781
2211
  }
1782
2212
  }
@@ -1784,17 +2214,17 @@ async function updatePromptReferencesInPrompts(promptsDir, oldPromptName, newPro
1784
2214
  }
1785
2215
  async function updatePromptReferencesInAgents(agentsDir, oldPromptName, newPromptName) {
1786
2216
  const updatedFiles = [];
1787
- if (!fs2__default.existsSync(agentsDir)) {
2217
+ if (!fs4__default.existsSync(agentsDir)) {
1788
2218
  return updatedFiles;
1789
2219
  }
1790
- const files = fs2__default.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
2220
+ const files = fs4__default.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
1791
2221
  for (const file of files) {
1792
2222
  const filePath = path8__default.join(agentsDir, file);
1793
- let content = await fs2__default.promises.readFile(filePath, "utf-8");
2223
+ let content = await fs4__default.promises.readFile(filePath, "utf-8");
1794
2224
  const promptRegex = new RegExp(`prompt:\\s*['"]${escapeRegExp(oldPromptName)}['"]`, "g");
1795
2225
  if (promptRegex.test(content)) {
1796
2226
  content = content.replace(promptRegex, `prompt: '${newPromptName}'`);
1797
- await fs2__default.promises.writeFile(filePath, content, "utf-8");
2227
+ await fs4__default.promises.writeFile(filePath, content, "utf-8");
1798
2228
  updatedFiles.push(filePath);
1799
2229
  }
1800
2230
  }
@@ -1804,69 +2234,74 @@ function escapeRegExp(string) {
1804
2234
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1805
2235
  }
1806
2236
  function validateAgentData(data) {
2237
+ const errors = {};
1807
2238
  if (!data.name || typeof data.name !== "string") {
1808
- return "Agent name is required and must be a string";
1809
- }
1810
- if (data.name.includes("/")) {
1811
- return "Agent name cannot contain '/'. Reserved for namespace qualification.";
2239
+ errors["name"] = "Agent name is required";
2240
+ } else if (data.name.includes("/")) {
2241
+ errors["name"] = "Agent name cannot contain '/'";
1812
2242
  }
1813
2243
  if (data.title !== void 0 && typeof data.title !== "string") {
1814
- return "Agent title must be a string if provided";
2244
+ errors["title"] = "Agent title must be a string";
1815
2245
  }
1816
2246
  if (data.type !== void 0) {
1817
2247
  const validTypes = ["ai_human", "dual_ai"];
1818
2248
  if (!validTypes.includes(data.type)) {
1819
- return `Invalid type '${data.type}'. Must be one of: ${validTypes.join(", ")}`;
2249
+ errors["type"] = `Invalid type '${data.type}'. Must be one of: ${validTypes.join(", ")}`;
1820
2250
  }
1821
2251
  }
1822
2252
  if (!data.sideA || typeof data.sideA !== "object") {
1823
- return "sideA configuration is required";
1824
- }
1825
- if (!data.sideA.prompt || typeof data.sideA.prompt !== "string") {
1826
- return "sideA.prompt is required and must be a string";
1827
- }
1828
- if (data.sideA.label !== void 0 && typeof data.sideA.label !== "string") {
1829
- return "sideA.label must be a string";
1830
- }
1831
- if (data.sideA.stopOnResponse !== void 0 && typeof data.sideA.stopOnResponse !== "boolean") {
1832
- return "sideA.stopOnResponse must be a boolean";
1833
- }
1834
- if (data.sideA.stopTool !== void 0 && typeof data.sideA.stopTool !== "string") {
1835
- return "sideA.stopTool must be a string";
1836
- }
1837
- if (data.sideA.stopTool && !data.sideA.stopToolResponseProperty) {
1838
- return "sideA.stopToolResponseProperty is required when sideA.stopTool is set";
1839
- }
1840
- if (data.sideA.maxSteps !== void 0) {
1841
- if (typeof data.sideA.maxSteps !== "number" || data.sideA.maxSteps <= 0) {
1842
- return "sideA.maxSteps must be a positive number";
2253
+ errors["side_a_agent_prompt"] = "Side A configuration is required";
2254
+ } else {
2255
+ if (!data.sideA.prompt || typeof data.sideA.prompt !== "string") {
2256
+ errors["side_a_agent_prompt"] = "Side A prompt is required";
1843
2257
  }
1844
- }
1845
- if (data.type === "dual_ai") {
1846
- if (!data.sideB || typeof data.sideB !== "object") {
1847
- return "sideB configuration is required for dual_ai type";
2258
+ if (data.sideA.label !== void 0 && typeof data.sideA.label !== "string") {
2259
+ errors["side_a_label"] = "Side A label must be a string";
1848
2260
  }
1849
- if (!data.sideB.prompt || typeof data.sideB.prompt !== "string") {
1850
- return "sideB.prompt is required for dual_ai type";
2261
+ if (data.sideA.stopTool && !data.sideA.stopToolResponseProperty) {
2262
+ errors["side_a_stop_tool_response_property"] = "Response property is required when stop tool is set";
1851
2263
  }
1852
- if (data.sideB.stopTool && !data.sideB.stopToolResponseProperty) {
1853
- return "sideB.stopToolResponseProperty is required when sideB.stopTool is set";
2264
+ if (data.sideA.maxSteps !== void 0) {
2265
+ if (typeof data.sideA.maxSteps !== "number" || data.sideA.maxSteps <= 0) {
2266
+ errors["side_a_max_steps"] = "Max steps must be a positive number";
2267
+ }
1854
2268
  }
1855
- if (data.sideB.maxSteps !== void 0) {
1856
- if (typeof data.sideB.maxSteps !== "number" || data.sideB.maxSteps <= 0) {
1857
- return "sideB.maxSteps must be a positive number";
2269
+ }
2270
+ if (data.type === "dual_ai") {
2271
+ if (!data.sideB || typeof data.sideB !== "object") {
2272
+ errors["side_b_agent_prompt"] = "Side B configuration is required for dual_ai type";
2273
+ } else {
2274
+ if (!data.sideB.prompt || typeof data.sideB.prompt !== "string") {
2275
+ errors["side_b_agent_prompt"] = "Side B prompt is required for dual_ai type";
2276
+ }
2277
+ if (data.sideB.stopTool && !data.sideB.stopToolResponseProperty) {
2278
+ errors["side_b_stop_tool_response_property"] = "Response property is required when stop tool is set";
2279
+ }
2280
+ if (data.sideB.maxSteps !== void 0) {
2281
+ if (typeof data.sideB.maxSteps !== "number" || data.sideB.maxSteps <= 0) {
2282
+ errors["side_b_max_steps"] = "Max steps must be a positive number";
2283
+ }
1858
2284
  }
1859
2285
  }
1860
2286
  }
1861
2287
  if (data.exposeAsTool && !data.toolDescription) {
1862
- return "toolDescription is required when exposeAsTool is true";
2288
+ errors["tool_description"] = "Tool description is required when expose as tool is enabled";
1863
2289
  }
1864
2290
  if (data.maxSessionTurns !== void 0 && data.maxSessionTurns !== null) {
1865
2291
  if (typeof data.maxSessionTurns !== "number" || data.maxSessionTurns <= 0) {
1866
- return "maxSessionTurns must be a positive number";
2292
+ errors["max_session_turns"] = "Max session turns must be a positive number";
1867
2293
  }
1868
2294
  }
1869
- return null;
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
+ }
2304
+ return Object.keys(errors).length > 0 ? errors : null;
1870
2305
  }
1871
2306
  var MetadataService = class {
1872
2307
  metadataDir;
@@ -1886,11 +2321,11 @@ var MetadataService = class {
1886
2321
  */
1887
2322
  async read(agentName) {
1888
2323
  const filePath = this.getMetadataPath(agentName);
1889
- if (!fs2.existsSync(filePath)) {
2324
+ if (!fs4.existsSync(filePath)) {
1890
2325
  return null;
1891
2326
  }
1892
2327
  try {
1893
- const content = fs2.readFileSync(filePath, "utf-8");
2328
+ const content = fs4.readFileSync(filePath, "utf-8");
1894
2329
  return JSON.parse(content);
1895
2330
  } catch {
1896
2331
  return null;
@@ -1903,11 +2338,11 @@ var MetadataService = class {
1903
2338
  * @param metadata - Metadata to write
1904
2339
  */
1905
2340
  async write(agentName, metadata) {
1906
- if (!fs2.existsSync(this.metadataDir)) {
1907
- fs2.mkdirSync(this.metadataDir, { recursive: true });
2341
+ if (!fs4.existsSync(this.metadataDir)) {
2342
+ fs4.mkdirSync(this.metadataDir, { recursive: true });
1908
2343
  }
1909
2344
  const filePath = this.getMetadataPath(agentName);
1910
- fs2.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
2345
+ fs4.writeFileSync(filePath, JSON.stringify(metadata, null, 2));
1911
2346
  }
1912
2347
  /**
1913
2348
  * Delete metadata for an agent.
@@ -1916,8 +2351,8 @@ var MetadataService = class {
1916
2351
  */
1917
2352
  async delete(agentName) {
1918
2353
  const filePath = this.getMetadataPath(agentName);
1919
- if (fs2.existsSync(filePath)) {
1920
- fs2.unlinkSync(filePath);
2354
+ if (fs4.existsSync(filePath)) {
2355
+ fs4.unlinkSync(filePath);
1921
2356
  }
1922
2357
  }
1923
2358
  /**
@@ -2372,7 +2807,7 @@ var PackingService = class {
2372
2807
  resolvePackageVersion(pkgName, rootDir) {
2373
2808
  const pkgJsonPath = path8.join(rootDir, "node_modules", pkgName, "package.json");
2374
2809
  try {
2375
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
2810
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
2376
2811
  return `^${pkgJson.version}`;
2377
2812
  } catch {
2378
2813
  return "*";
@@ -2398,13 +2833,17 @@ var PackingService = class {
2398
2833
  tools: [],
2399
2834
  models: [],
2400
2835
  hooks: [],
2401
- agents: []
2836
+ effects: [],
2837
+ agents: [],
2838
+ threadEndpoints: []
2402
2839
  },
2403
2840
  shared: {
2404
2841
  prompts: [],
2405
2842
  tools: [],
2406
2843
  models: [],
2407
- hooks: []
2844
+ hooks: [],
2845
+ effects: [],
2846
+ threadEndpoints: []
2408
2847
  },
2409
2848
  warnings: [],
2410
2849
  errors: []
@@ -2420,7 +2859,7 @@ var PackingService = class {
2420
2859
  discoveredVia: "static",
2421
2860
  sharedWith: []
2422
2861
  });
2423
- const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
2862
+ const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
2424
2863
  const agentPrompts = await extractAgentPrompts(agentSource);
2425
2864
  if (agentPrompts.sideA) {
2426
2865
  analysis.primaryPrompt = agentPrompts.sideA;
@@ -2429,6 +2868,8 @@ var PackingService = class {
2429
2868
  if (agentPrompts.sideB) {
2430
2869
  await this.analyzePrompt(agentPrompts.sideB, agentsDir, analysis, /* @__PURE__ */ new Set(), `agent:${agentName}`);
2431
2870
  }
2871
+ await this.analyzeThreadEndpoints(agentsDir, analysis);
2872
+ await this.analyzeEffects(agentsDir, analysis);
2432
2873
  await this.checkSharedItems(agentsDir, analysis);
2433
2874
  return analysis;
2434
2875
  }
@@ -2449,7 +2890,7 @@ var PackingService = class {
2449
2890
  const agentItem = analysis.constituents.agents.find((a) => a.name === analysis.agent);
2450
2891
  if (agentItem?.filePath) {
2451
2892
  try {
2452
- const agentSource = fs2.readFileSync(agentItem.filePath, "utf-8");
2893
+ const agentSource = fs4.readFileSync(agentItem.filePath, "utf-8");
2453
2894
  agentDescription = await extractAgentDescription(agentSource) || void 0;
2454
2895
  } catch {
2455
2896
  }
@@ -2466,6 +2907,138 @@ var PackingService = class {
2466
2907
  );
2467
2908
  return { generatedReadme, agentDescription };
2468
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
+ }
2469
3042
  /**
2470
3043
  * Recursively analyze a prompt and its dependencies.
2471
3044
  */
@@ -2489,7 +3062,7 @@ var PackingService = class {
2489
3062
  return;
2490
3063
  }
2491
3064
  visited.add(`prompt:${promptName}`);
2492
- const promptSource = fs2.readFileSync(promptFilePath, "utf-8");
3065
+ const promptSource = fs4.readFileSync(promptFilePath, "utf-8");
2493
3066
  const modelName = await extractPromptModel(promptSource);
2494
3067
  if (modelName) {
2495
3068
  await this.analyzeModel(modelName, agentsDir, analysis, visited, thisKey);
@@ -2543,7 +3116,7 @@ var PackingService = class {
2543
3116
  return;
2544
3117
  }
2545
3118
  visited.add(`tool:${toolName}`);
2546
- const toolSource = fs2.readFileSync(toolFilePath, "utf-8");
3119
+ const toolSource = fs4.readFileSync(toolFilePath, "utf-8");
2547
3120
  const { uses } = await extractToolUses(toolSource);
2548
3121
  for (const usedItem of uses) {
2549
3122
  await this.analyzeTool(usedItem, agentsDir, analysis, visited, "uses", thisKey);
@@ -2572,7 +3145,7 @@ var PackingService = class {
2572
3145
  return;
2573
3146
  }
2574
3147
  visited.add(`agent:${agentName}`);
2575
- const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
3148
+ const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
2576
3149
  const agentPrompts = await extractAgentPrompts(agentSource);
2577
3150
  if (agentPrompts.sideA) {
2578
3151
  await this.analyzePrompt(agentPrompts.sideA, agentsDir, analysis, visited, thisKey);
@@ -2604,7 +3177,7 @@ var PackingService = class {
2604
3177
  return;
2605
3178
  }
2606
3179
  visited.add(`model:${modelName}`);
2607
- const modelSource = fs2.readFileSync(modelFilePath, "utf-8");
3180
+ const modelSource = fs4.readFileSync(modelFilePath, "utf-8");
2608
3181
  const fallbacks = await extractModelFallbacks(modelSource);
2609
3182
  for (const fallbackName of fallbacks) {
2610
3183
  await this.analyzeModel(fallbackName, agentsDir, analysis, visited, thisKey);
@@ -2615,8 +3188,8 @@ var PackingService = class {
2615
3188
  */
2616
3189
  async checkSharedItems(agentsDir, analysis) {
2617
3190
  const agentsPath = path8.join(agentsDir, "agents");
2618
- if (!fs2.existsSync(agentsPath)) return;
2619
- 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"));
2620
3193
  for (const agentFile of agentFiles) {
2621
3194
  const otherAgentName = agentFile.replace(".ts", "");
2622
3195
  if (otherAgentName === analysis.agent) continue;
@@ -2656,7 +3229,7 @@ var PackingService = class {
2656
3229
  const visited = /* @__PURE__ */ new Set();
2657
3230
  const agentFilePath = await this.findFile(path8.join(agentsDir, "agents"), agentName);
2658
3231
  if (!agentFilePath) return result;
2659
- const agentSource = fs2.readFileSync(agentFilePath, "utf-8");
3232
+ const agentSource = fs4.readFileSync(agentFilePath, "utf-8");
2660
3233
  const agentPrompts = await extractAgentPrompts(agentSource);
2661
3234
  const analyzePromptLight = async (promptName) => {
2662
3235
  if (visited.has(promptName)) return;
@@ -2664,7 +3237,7 @@ var PackingService = class {
2664
3237
  result.prompts.push(promptName);
2665
3238
  const promptFilePath = await this.findFile(path8.join(agentsDir, "prompts"), promptName);
2666
3239
  if (!promptFilePath) return;
2667
- const promptSource = fs2.readFileSync(promptFilePath, "utf-8");
3240
+ const promptSource = fs4.readFileSync(promptFilePath, "utf-8");
2668
3241
  const modelName = await extractPromptModel(promptSource);
2669
3242
  if (modelName && !result.models.includes(modelName)) {
2670
3243
  result.models.push(modelName);
@@ -2689,6 +3262,8 @@ var PackingService = class {
2689
3262
  *
2690
3263
  * The packing format creates:
2691
3264
  * - dist/{type}/{name}.js - Individual bundled files per constituent
3265
+ * - dist/effects/** - Packed effect modules
3266
+ * - dist/thread-endpoints/** - Packed thread endpoint modules
2692
3267
  * - dist/index.js - Re-exports and lazy loaders
2693
3268
  * - dist/index.d.ts - TypeScript type definitions
2694
3269
  * - package.json - With standardagent field and dependencies
@@ -2736,11 +3311,13 @@ var PackingService = class {
2736
3311
  }
2737
3312
  result.warnings = analysis.warnings;
2738
3313
  const pkgOutputDir = path8.join(outputDir, packageId);
2739
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "agents"), { recursive: true });
2740
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "prompts"), { recursive: true });
2741
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "tools"), { recursive: true });
2742
- fs2.mkdirSync(path8.join(pkgOutputDir, "dist", "models"), { recursive: true });
2743
- 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 });
2744
3321
  const seenItems = /* @__PURE__ */ new Set();
2745
3322
  const allItems = [];
2746
3323
  for (const a of analysis.constituents.agents) {
@@ -2778,6 +3355,20 @@ var PackingService = class {
2778
3355
  allItems.push({ ...h, type: "hook" });
2779
3356
  }
2780
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
+ }
2781
3372
  const externalDeps = /* @__PURE__ */ new Map();
2782
3373
  for (const item of allItems) {
2783
3374
  const outputPath = path8.join(
@@ -2786,6 +3377,7 @@ var PackingService = class {
2786
3377
  this.getTypeDir(item.type),
2787
3378
  `${item.name}.js`
2788
3379
  );
3380
+ fs4.mkdirSync(path8.dirname(outputPath), { recursive: true });
2789
3381
  const deps = await this.bundleFile(item.filePath, outputPath, rootDir);
2790
3382
  for (const [depName, depVersion] of deps) {
2791
3383
  if (!externalDeps.has(depName)) {
@@ -2796,28 +3388,30 @@ var PackingService = class {
2796
3388
  }
2797
3389
  const indexJs = this.generateReExportIndex(analysis, meta);
2798
3390
  const indexJsPath = path8.join(pkgOutputDir, "dist", "index.js");
2799
- fs2.writeFileSync(indexJsPath, indexJs);
3391
+ fs4.writeFileSync(indexJsPath, indexJs);
2800
3392
  result.filesCreated.push(indexJsPath);
2801
3393
  const indexDts = this.generateIndexDts(analysis);
2802
3394
  const indexDtsPath = path8.join(pkgOutputDir, "dist", "index.d.ts");
2803
- fs2.writeFileSync(indexDtsPath, indexDts);
3395
+ fs4.writeFileSync(indexDtsPath, indexDts);
2804
3396
  result.filesCreated.push(indexDtsPath);
2805
3397
  const pkgJson = this.generatePackageJson(
2806
3398
  finalPackageName,
2807
3399
  version,
2808
3400
  agentName,
3401
+ this.deduplicateConstituents(analysis).effects.map((effect) => effect.name),
3402
+ this.deduplicateConstituents(analysis).threadEndpoints.map((endpoint) => endpoint.name),
2809
3403
  externalDeps,
2810
3404
  rootDir,
2811
3405
  license,
2812
3406
  licenseOwner
2813
3407
  );
2814
3408
  const pkgJsonPath = path8.join(pkgOutputDir, "package.json");
2815
- fs2.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
3409
+ fs4.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
2816
3410
  result.filesCreated.push(pkgJsonPath);
2817
3411
  if (license) {
2818
3412
  const licenseContent = this.generateLicenseFile(license, licenseOwner);
2819
3413
  const licensePath = path8.join(pkgOutputDir, "LICENSE");
2820
- fs2.writeFileSync(licensePath, licenseContent);
3414
+ fs4.writeFileSync(licensePath, licenseContent);
2821
3415
  result.filesCreated.push(licensePath);
2822
3416
  }
2823
3417
  let readmeContent = readme;
@@ -2825,7 +3419,7 @@ var PackingService = class {
2825
3419
  const agentItem = analysis.constituents.agents.find((a) => a.name === agentName);
2826
3420
  let agentDescription;
2827
3421
  if (agentItem?.filePath) {
2828
- const agentSource = fs2.readFileSync(agentItem.filePath, "utf-8");
3422
+ const agentSource = fs4.readFileSync(agentItem.filePath, "utf-8");
2829
3423
  agentDescription = await extractAgentDescription(agentSource) || void 0;
2830
3424
  }
2831
3425
  readmeContent = this.generateReadme(
@@ -2837,15 +3431,15 @@ var PackingService = class {
2837
3431
  );
2838
3432
  }
2839
3433
  const readmePath = path8.join(pkgOutputDir, "README.md");
2840
- fs2.writeFileSync(readmePath, readmeContent);
3434
+ fs4.writeFileSync(readmePath, readmeContent);
2841
3435
  result.filesCreated.push(readmePath);
2842
3436
  if (removeOriginals || itemSelections) {
2843
3437
  result.filesRemoved = [];
2844
3438
  for (const item of allItems) {
2845
3439
  const selection = itemSelections?.find((s) => s.name === item.name && s.type === item.type);
2846
- const shouldRemove = selection ? selection.mode === "extract" : removeOriginals && item.sharedWith.length === 0;
2847
- if (shouldRemove && fs2.existsSync(item.filePath)) {
2848
- 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);
2849
3443
  result.filesRemoved.push(item.filePath);
2850
3444
  }
2851
3445
  }
@@ -2896,11 +3490,11 @@ var PackingService = class {
2896
3490
  const resolved = path8.resolve(path8.dirname(importer), source);
2897
3491
  let tsResolved = resolved;
2898
3492
  if (!resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
2899
- if (fs2.existsSync(`${resolved}.ts`)) {
3493
+ if (fs4.existsSync(`${resolved}.ts`)) {
2900
3494
  tsResolved = `${resolved}.ts`;
2901
- } else if (fs2.existsSync(`${resolved}.js`)) {
3495
+ } else if (fs4.existsSync(`${resolved}.js`)) {
2902
3496
  tsResolved = `${resolved}.js`;
2903
- } else if (fs2.existsSync(`${resolved}/index.ts`)) {
3497
+ } else if (fs4.existsSync(`${resolved}/index.ts`)) {
2904
3498
  tsResolved = `${resolved}/index.ts`;
2905
3499
  }
2906
3500
  }
@@ -2953,7 +3547,7 @@ var PackingService = class {
2953
3547
  // Local dependencies have been inlined
2954
3548
 
2955
3549
  `;
2956
- fs2.writeFileSync(outputPath, header + bundledCode);
3550
+ fs4.writeFileSync(outputPath, header + bundledCode);
2957
3551
  await bundle.close();
2958
3552
  } catch (error) {
2959
3553
  await bundle.close();
@@ -2976,6 +3570,10 @@ var PackingService = class {
2976
3570
  return "models";
2977
3571
  case "hook":
2978
3572
  return "hooks";
3573
+ case "effect":
3574
+ return "effects";
3575
+ case "thread-endpoint":
3576
+ return "thread-endpoints";
2979
3577
  }
2980
3578
  }
2981
3579
  /**
@@ -2995,7 +3593,9 @@ var PackingService = class {
2995
3593
  prompts: dedupe(analysis.constituents.prompts),
2996
3594
  tools: dedupe(analysis.constituents.tools),
2997
3595
  models: dedupe(analysis.constituents.models),
2998
- hooks: dedupe(analysis.constituents.hooks)
3596
+ hooks: dedupe(analysis.constituents.hooks),
3597
+ effects: dedupe(analysis.constituents.effects),
3598
+ threadEndpoints: dedupe(analysis.constituents.threadEndpoints)
2999
3599
  };
3000
3600
  }
3001
3601
  /**
@@ -3040,6 +3640,9 @@ var PackingService = class {
3040
3640
  for (const hook of constituents.hooks) {
3041
3641
  lines.push(`export { default as ${this.quoteName(hook.name)} } from './hooks/${hook.name}.js';`);
3042
3642
  }
3643
+ for (const effect of constituents.effects) {
3644
+ lines.push(`export { default as ${this.quoteName(effect.name)} } from './effects/${effect.name}.js';`);
3645
+ }
3043
3646
  lines.push("");
3044
3647
  lines.push("// Registry exports for lazy loading");
3045
3648
  lines.push("export const agents = {");
@@ -3072,6 +3675,18 @@ var PackingService = class {
3072
3675
  }
3073
3676
  lines.push("};");
3074
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("");
3075
3690
  lines.push("export const __meta = " + JSON.stringify(meta, null, 2) + ";");
3076
3691
  lines.push("");
3077
3692
  return lines.join("\n");
@@ -3087,6 +3702,9 @@ var PackingService = class {
3087
3702
  " PromptDefinition,",
3088
3703
  " ToolDefinition,",
3089
3704
  " ModelDefinition,",
3705
+ " EffectDefinition,",
3706
+ " Controller,",
3707
+ " MarkedThreadEndpoint,",
3090
3708
  " PackedMeta,",
3091
3709
  "} from '@standardagents/spec';",
3092
3710
  "",
@@ -3118,6 +3736,11 @@ var PackingService = class {
3118
3736
  lines.push(`export declare const ${hook.name}: unknown;`);
3119
3737
  }
3120
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
+ }
3121
3744
  lines.push("");
3122
3745
  lines.push("export declare const agents: {");
3123
3746
  for (const agent of constituents.agents) {
@@ -3149,6 +3772,18 @@ var PackingService = class {
3149
3772
  }
3150
3773
  lines.push("};");
3151
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("");
3152
3787
  lines.push("export declare const __meta: PackedMeta;");
3153
3788
  lines.push("");
3154
3789
  return lines.join("\n");
@@ -3156,7 +3791,7 @@ var PackingService = class {
3156
3791
  /**
3157
3792
  * Generate the package.json file with dependencies.
3158
3793
  */
3159
- generatePackageJson(packageName, version, agentName, externalDeps, rootDir, license, licenseOwner) {
3794
+ generatePackageJson(packageName, version, agentName, effects, threadEndpoints, externalDeps, rootDir, license, licenseOwner) {
3160
3795
  const dependencies = {
3161
3796
  "@standardagents/spec": this.resolvePackageVersion("@standardagents/spec", rootDir)
3162
3797
  };
@@ -3177,7 +3812,9 @@ var PackingService = class {
3177
3812
  },
3178
3813
  keywords: ["standardagent"],
3179
3814
  standardagent: {
3180
- entryAgents: [agentName]
3815
+ entryAgents: [agentName],
3816
+ ...effects.length > 0 ? { effects } : {},
3817
+ ...threadEndpoints.length > 0 ? { threadEndpoints } : {}
3181
3818
  },
3182
3819
  files: license ? ["dist", "LICENSE", "README.md"] : ["dist", "README.md"],
3183
3820
  dependencies
@@ -3337,11 +3974,11 @@ Copyright (c) ${year} ${copyrightHolder}
3337
3974
  getPackedInfo(packageId, rootDir) {
3338
3975
  const packedDir = path8.join(rootDir, "agents", "packed");
3339
3976
  let packageDir = path8.join(packedDir, packageId);
3340
- if (!fs2.existsSync(packageDir)) {
3341
- if (!fs2.existsSync(packedDir)) {
3977
+ if (!fs4.existsSync(packageDir)) {
3978
+ if (!fs4.existsSync(packedDir)) {
3342
3979
  return null;
3343
3980
  }
3344
- 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);
3345
3982
  const matchingDir = dirs.find(
3346
3983
  (d) => d === packageId || d === `standardagent-${packageId}` || d === `standardagent-${packageId.replace(/_/g, "-")}`
3347
3984
  );
@@ -3351,14 +3988,14 @@ Copyright (c) ${year} ${copyrightHolder}
3351
3988
  packageDir = path8.join(packedDir, matchingDir);
3352
3989
  }
3353
3990
  const pkgJsonPath = path8.join(packageDir, "package.json");
3354
- if (!fs2.existsSync(pkgJsonPath)) {
3991
+ if (!fs4.existsSync(pkgJsonPath)) {
3355
3992
  return null;
3356
3993
  }
3357
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
3994
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3358
3995
  let readme;
3359
3996
  const readmePath = path8.join(packageDir, "README.md");
3360
- if (fs2.existsSync(readmePath)) {
3361
- readme = fs2.readFileSync(readmePath, "utf-8");
3997
+ if (fs4.existsSync(readmePath)) {
3998
+ readme = fs4.readFileSync(readmePath, "utf-8");
3362
3999
  }
3363
4000
  return {
3364
4001
  packageName: pkgJson.name,
@@ -3377,10 +4014,10 @@ Copyright (c) ${year} ${copyrightHolder}
3377
4014
  */
3378
4015
  listPackedPackages(rootDir) {
3379
4016
  const packedDir = path8.join(rootDir, "agents", "packed");
3380
- if (!fs2.existsSync(packedDir)) {
4017
+ if (!fs4.existsSync(packedDir)) {
3381
4018
  return [];
3382
4019
  }
3383
- 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);
3384
4021
  }
3385
4022
  /**
3386
4023
  * Generate README.md content for a packed agent.
@@ -3427,17 +4064,17 @@ ${license || "See LICENSE file"}
3427
4064
  * Find a file by name in a directory.
3428
4065
  */
3429
4066
  async findFile(dir, name) {
3430
- if (!fs2.existsSync(dir)) {
4067
+ if (!fs4.existsSync(dir)) {
3431
4068
  return null;
3432
4069
  }
3433
4070
  const exactPath = path8.join(dir, `${name}.ts`);
3434
- if (fs2.existsSync(exactPath)) {
4071
+ if (fs4.existsSync(exactPath)) {
3435
4072
  return exactPath;
3436
4073
  }
3437
- const files = fs2.readdirSync(dir).filter((f) => f.endsWith(".ts"));
4074
+ const files = fs4.readdirSync(dir).filter((f) => f.endsWith(".ts"));
3438
4075
  for (const file of files) {
3439
4076
  const filePath = path8.join(dir, file);
3440
- const source = fs2.readFileSync(filePath, "utf-8");
4077
+ const source = fs4.readFileSync(filePath, "utf-8");
3441
4078
  const extractedName = await extractDefinitionName(source);
3442
4079
  if (extractedName === name) {
3443
4080
  return filePath;
@@ -3450,14 +4087,14 @@ ${license || "See LICENSE file"}
3450
4087
  */
3451
4088
  async listAgents(rootDir) {
3452
4089
  const agentsDir = path8.join(rootDir, "agents", "agents");
3453
- if (!fs2.existsSync(agentsDir)) {
4090
+ if (!fs4.existsSync(agentsDir)) {
3454
4091
  return [];
3455
4092
  }
3456
- const files = fs2.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
4093
+ const files = fs4.readdirSync(agentsDir).filter((f) => f.endsWith(".ts"));
3457
4094
  const agents = [];
3458
4095
  for (const file of files) {
3459
4096
  const filePath = path8.join(agentsDir, file);
3460
- const source = fs2.readFileSync(filePath, "utf-8");
4097
+ const source = fs4.readFileSync(filePath, "utf-8");
3461
4098
  const name = await extractDefinitionName(source);
3462
4099
  if (name) {
3463
4100
  agents.push(name);
@@ -3507,7 +4144,7 @@ var PackageDiscoveryService = class {
3507
4144
  async discoverNpmPackages() {
3508
4145
  const packages = [];
3509
4146
  const nodeModulesDir = path8.join(this.config.rootDir, "node_modules");
3510
- if (!fs2.existsSync(nodeModulesDir)) {
4147
+ if (!fs4.existsSync(nodeModulesDir)) {
3511
4148
  return packages;
3512
4149
  }
3513
4150
  const rootEntries = await this.scanDirectory(nodeModulesDir);
@@ -3543,11 +4180,11 @@ var PackageDiscoveryService = class {
3543
4180
  */
3544
4181
  async checkNpmPackage(pkgDir, pkgName) {
3545
4182
  const pkgJsonPath = path8.join(pkgDir, "package.json");
3546
- if (!fs2.existsSync(pkgJsonPath)) {
4183
+ if (!fs4.existsSync(pkgJsonPath)) {
3547
4184
  return null;
3548
4185
  }
3549
4186
  try {
3550
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4187
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3551
4188
  const isStandardAgent = (
3552
4189
  // Has "standardagent" keyword
3553
4190
  pkgJson.keywords?.includes("standardagent") || // Has "standardagent-*" prefix
@@ -3561,12 +4198,16 @@ var PackageDiscoveryService = class {
3561
4198
  if (!pkgJson.standardagent?.entryAgents) {
3562
4199
  return null;
3563
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;
3564
4203
  return {
3565
4204
  packageId: pkgJson.name || pkgName,
3566
4205
  version: pkgJson.version || "0.0.0",
3567
4206
  source: "npm",
3568
4207
  path: pkgDir,
3569
4208
  entryAgents: pkgJson.standardagent.entryAgents,
4209
+ ...effects ? { effects } : {},
4210
+ ...threadEndpoints ? { threadEndpoints } : {},
3570
4211
  description: pkgJson.description
3571
4212
  };
3572
4213
  } catch (error) {
@@ -3580,21 +4221,21 @@ var PackageDiscoveryService = class {
3580
4221
  */
3581
4222
  async discoverLocalPackages() {
3582
4223
  const packages = [];
3583
- if (!fs2.existsSync(this.config.packedDir)) {
4224
+ if (!fs4.existsSync(this.config.packedDir)) {
3584
4225
  return packages;
3585
4226
  }
3586
4227
  const entries = await this.scanDirectory(this.config.packedDir);
3587
4228
  for (const entry of entries) {
3588
4229
  if (entry.startsWith(".")) continue;
3589
4230
  const pkgDir = path8.join(this.config.packedDir, entry);
3590
- const stat = fs2.statSync(pkgDir);
4231
+ const stat = fs4.statSync(pkgDir);
3591
4232
  if (!stat.isDirectory()) continue;
3592
4233
  if (entry.startsWith("@")) {
3593
4234
  const scopeEntries = await this.scanDirectory(pkgDir);
3594
4235
  for (const scopedPkg of scopeEntries) {
3595
4236
  if (scopedPkg.startsWith(".")) continue;
3596
4237
  const scopedPkgDir = path8.join(pkgDir, scopedPkg);
3597
- const scopedStat = fs2.statSync(scopedPkgDir);
4238
+ const scopedStat = fs4.statSync(scopedPkgDir);
3598
4239
  if (!scopedStat.isDirectory()) continue;
3599
4240
  const fullName = `${entry}/${scopedPkg}`;
3600
4241
  const pkg = await this.checkLocalPackage(scopedPkgDir, fullName);
@@ -3618,20 +4259,24 @@ var PackageDiscoveryService = class {
3618
4259
  */
3619
4260
  async checkLocalPackage(pkgDir, dirName) {
3620
4261
  const pkgJsonPath = path8.join(pkgDir, "package.json");
3621
- if (!fs2.existsSync(pkgJsonPath)) {
4262
+ if (!fs4.existsSync(pkgJsonPath)) {
3622
4263
  return null;
3623
4264
  }
3624
4265
  try {
3625
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4266
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3626
4267
  if (!pkgJson.standardagent?.entryAgents) {
3627
4268
  return null;
3628
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;
3629
4272
  return {
3630
4273
  packageId: pkgJson.name || dirName,
3631
4274
  version: pkgJson.version || "0.0.0",
3632
4275
  source: "local",
3633
4276
  path: pkgDir,
3634
4277
  entryAgents: pkgJson.standardagent.entryAgents,
4278
+ ...effects ? { effects } : {},
4279
+ ...threadEndpoints ? { threadEndpoints } : {},
3635
4280
  description: pkgJson.description
3636
4281
  };
3637
4282
  } catch (error) {
@@ -3643,10 +4288,10 @@ var PackageDiscoveryService = class {
3643
4288
  * Scan a directory and return entry names.
3644
4289
  */
3645
4290
  async scanDirectory(dir) {
3646
- if (!fs2.existsSync(dir)) {
4291
+ if (!fs4.existsSync(dir)) {
3647
4292
  return [];
3648
4293
  }
3649
- const entries = fs2.readdirSync(dir);
4294
+ const entries = fs4.readdirSync(dir);
3650
4295
  return entries;
3651
4296
  }
3652
4297
  /**
@@ -3657,7 +4302,10 @@ var PackageDiscoveryService = class {
3657
4302
  return false;
3658
4303
  }
3659
4304
  const f = field;
3660
- 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;
3661
4309
  }
3662
4310
  /**
3663
4311
  * Get a package by ID.
@@ -3688,7 +4336,27 @@ var TYPE_TO_DIR = {
3688
4336
  prompt: "prompts",
3689
4337
  tool: "tools",
3690
4338
  model: "models",
3691
- 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"
3692
4360
  };
3693
4361
  var UnpackingService = class {
3694
4362
  /**
@@ -3717,11 +4385,11 @@ var UnpackingService = class {
3717
4385
  analysis.version = pkg.version;
3718
4386
  analysis.source = pkg.source;
3719
4387
  const indexPath = path8.join(pkg.path, "dist", "index.js");
3720
- if (!fs2.existsSync(indexPath)) {
4388
+ if (!fs4.existsSync(indexPath)) {
3721
4389
  analysis.errors.push(`Package index not found: ${indexPath}`);
3722
4390
  return analysis;
3723
4391
  }
3724
- const indexContent = fs2.readFileSync(indexPath, "utf-8");
4392
+ const indexContent = fs4.readFileSync(indexPath, "utf-8");
3725
4393
  const registryItems = await this.parseIndexExports(indexContent);
3726
4394
  const availableItems = /* @__PURE__ */ new Map();
3727
4395
  for (const item of registryItems) {
@@ -3730,15 +4398,15 @@ var UnpackingService = class {
3730
4398
  const agentsDir = path8.join(rootDir, "agents");
3731
4399
  const itemsWithRelations = [];
3732
4400
  for (const item of registryItems) {
3733
- 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`);
3734
4402
  const sourcePath = path8.join(pkg.path, "dist", TYPE_TO_DIR[item.type], `${item.name}.js`);
3735
4403
  const existsGlobally = this.fileExists(targetPath);
3736
- const sourceExists = fs2.existsSync(sourcePath);
4404
+ const sourceExists = fs4.existsSync(sourcePath);
3737
4405
  if (!sourceExists) {
3738
4406
  analysis.warnings.push(`Source file not found for ${item.type} "${item.name}": ${sourcePath}`);
3739
4407
  continue;
3740
4408
  }
3741
- const bundledCode = fs2.readFileSync(sourcePath, "utf-8");
4409
+ const bundledCode = fs4.readFileSync(sourcePath, "utf-8");
3742
4410
  const children = await this.discoverRelationships(item.type, item.name, bundledCode, availableItems);
3743
4411
  itemsWithRelations.push({
3744
4412
  name: item.name,
@@ -3748,10 +4416,10 @@ var UnpackingService = class {
3748
4416
  action: existsGlobally ? "skip" : "generate"
3749
4417
  });
3750
4418
  for (const child of children) {
3751
- 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`);
3752
4420
  const childSourcePath = path8.join(pkg.path, "dist", TYPE_TO_DIR[child.type], `${child.name}.js`);
3753
4421
  const childExists = this.fileExists(childTargetPath);
3754
- const childSourceExists = fs2.existsSync(childSourcePath);
4422
+ const childSourceExists = fs4.existsSync(childSourcePath);
3755
4423
  if (!childSourceExists) {
3756
4424
  continue;
3757
4425
  }
@@ -3855,7 +4523,7 @@ var UnpackingService = class {
3855
4523
  }
3856
4524
  const itemsToProcess = this.applySelections(analysis.items, itemSelections);
3857
4525
  const pkgJsonPath = path8.join(pkg.path, "package.json");
3858
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4526
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
3859
4527
  let author = "";
3860
4528
  if (typeof pkgJson.author === "string") {
3861
4529
  author = pkgJson.author;
@@ -3881,16 +4549,16 @@ var UnpackingService = class {
3881
4549
  }
3882
4550
  try {
3883
4551
  const sourcePath = path8.join(pkg.path, "dist", TYPE_TO_DIR[item.type], `${item.name}.js`);
3884
- const bundledCode = fs2.readFileSync(sourcePath, "utf-8");
4552
+ const bundledCode = fs4.readFileSync(sourcePath, "utf-8");
3885
4553
  let tsCode = await transformBundledJs(bundledCode);
3886
4554
  if (item.type === "agent") {
3887
4555
  tsCode = await injectAgentMetadata(tsCode, agentMetadata);
3888
4556
  }
3889
4557
  const dir = path8.dirname(item.targetPath);
3890
- if (!fs2.existsSync(dir)) {
3891
- fs2.mkdirSync(dir, { recursive: true });
4558
+ if (!fs4.existsSync(dir)) {
4559
+ fs4.mkdirSync(dir, { recursive: true });
3892
4560
  }
3893
- fs2.writeFileSync(item.targetPath, tsCode);
4561
+ fs4.writeFileSync(item.targetPath, tsCode);
3894
4562
  result.filesGenerated.push(item.targetPath);
3895
4563
  } catch (error) {
3896
4564
  result.warnings.push(
@@ -3935,7 +4603,7 @@ var UnpackingService = class {
3935
4603
  true
3936
4604
  );
3937
4605
  const items = [];
3938
- const registryTypes = ["agent", "prompt", "tool", "model", "hook"];
4606
+ const registryTypes = ["agent", "prompt", "tool", "model", "hook", "effect", "thread-endpoint"];
3939
4607
  function visit(node) {
3940
4608
  if (ts.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
3941
4609
  for (const decl of node.declarationList.declarations) {
@@ -3943,7 +4611,7 @@ var UnpackingService = class {
3943
4611
  const varName = decl.name.text;
3944
4612
  let itemType = null;
3945
4613
  for (const type of registryTypes) {
3946
- if (varName === TYPE_TO_DIR[type]) {
4614
+ if (varName === TYPE_TO_REGISTRY_NAME[type]) {
3947
4615
  itemType = type;
3948
4616
  break;
3949
4617
  }
@@ -3981,9 +4649,9 @@ var UnpackingService = class {
3981
4649
  if (pkgIdentifier.startsWith("/") || pkgIdentifier.startsWith("./")) {
3982
4650
  const absolutePath = path8.isAbsolute(pkgIdentifier) ? pkgIdentifier : path8.join(rootDir, pkgIdentifier);
3983
4651
  const pkgJsonPath2 = path8.join(absolutePath, "package.json");
3984
- if (fs2.existsSync(pkgJsonPath2)) {
4652
+ if (fs4.existsSync(pkgJsonPath2)) {
3985
4653
  try {
3986
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath2, "utf-8"));
4654
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath2, "utf-8"));
3987
4655
  if (pkgJson.standardagent?.entryAgents) {
3988
4656
  return {
3989
4657
  packageId: pkgJson.name || path8.basename(absolutePath),
@@ -4000,9 +4668,9 @@ var UnpackingService = class {
4000
4668
  }
4001
4669
  const packedDir = path8.join(rootDir, "agents", "packed", pkgIdentifier);
4002
4670
  const pkgJsonPath = path8.join(packedDir, "package.json");
4003
- if (fs2.existsSync(pkgJsonPath)) {
4671
+ if (fs4.existsSync(pkgJsonPath)) {
4004
4672
  try {
4005
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4673
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
4006
4674
  if (pkgJson.standardagent?.entryAgents) {
4007
4675
  return {
4008
4676
  packageId: pkgJson.name || pkgIdentifier,
@@ -4043,18 +4711,18 @@ var UnpackingService = class {
4043
4711
  * Check if a file exists.
4044
4712
  */
4045
4713
  fileExists(filePath) {
4046
- if (fs2.existsSync(filePath)) {
4714
+ if (fs4.existsSync(filePath)) {
4047
4715
  return true;
4048
4716
  }
4049
4717
  const withoutExt = filePath.replace(/\.(ts|js)$/, "");
4050
- return fs2.existsSync(`${withoutExt}.ts`) || fs2.existsSync(`${withoutExt}.js`);
4718
+ return fs4.existsSync(`${withoutExt}.ts`) || fs4.existsSync(`${withoutExt}.js`);
4051
4719
  }
4052
4720
  /**
4053
4721
  * Recursively delete a directory.
4054
4722
  */
4055
4723
  deleteDirectory(dirPath) {
4056
- if (fs2.existsSync(dirPath)) {
4057
- fs2.rmSync(dirPath, { recursive: true, force: true });
4724
+ if (fs4.existsSync(dirPath)) {
4725
+ fs4.rmSync(dirPath, { recursive: true, force: true });
4058
4726
  }
4059
4727
  }
4060
4728
  /**
@@ -4131,7 +4799,7 @@ var NpmPublishService = class {
4131
4799
  };
4132
4800
  }
4133
4801
  const pkgJsonPath = path8.join(packageDir, "package.json");
4134
- if (!fs2.existsSync(pkgJsonPath)) {
4802
+ if (!fs4.existsSync(pkgJsonPath)) {
4135
4803
  return {
4136
4804
  success: false,
4137
4805
  output: "",
@@ -4141,7 +4809,7 @@ var NpmPublishService = class {
4141
4809
  let packageName;
4142
4810
  let version;
4143
4811
  try {
4144
- const pkgJson = JSON.parse(fs2.readFileSync(pkgJsonPath, "utf-8"));
4812
+ const pkgJson = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
4145
4813
  packageName = pkgJson.name;
4146
4814
  version = pkgJson.version;
4147
4815
  } catch (e) {
@@ -4157,7 +4825,7 @@ var NpmPublishService = class {
4157
4825
  registry=${registry}
4158
4826
  `;
4159
4827
  try {
4160
- fs2.writeFileSync(npmrcPath, npmrcContent, { mode: 384 });
4828
+ fs4.writeFileSync(npmrcPath, npmrcContent, { mode: 384 });
4161
4829
  const args = ["publish"];
4162
4830
  if (dryRun) {
4163
4831
  args.push("--dry-run");
@@ -4189,8 +4857,8 @@ registry=${registry}
4189
4857
  };
4190
4858
  } finally {
4191
4859
  try {
4192
- if (fs2.existsSync(npmrcPath)) {
4193
- fs2.unlinkSync(npmrcPath);
4860
+ if (fs4.existsSync(npmrcPath)) {
4861
+ fs4.unlinkSync(npmrcPath);
4194
4862
  }
4195
4863
  } catch {
4196
4864
  }
@@ -4257,11 +4925,11 @@ var VIRTUAL_BUILDER_ID = "virtual:@standardagents/builder";
4257
4925
  var RESOLVED_VIRTUAL_BUILDER_ID = "\0" + VIRTUAL_BUILDER_ID;
4258
4926
  function scanApiDirectory(dir, baseRoute = "") {
4259
4927
  const routes = [];
4260
- if (!fs2__default.existsSync(dir)) {
4928
+ if (!fs4__default.existsSync(dir)) {
4261
4929
  return routes;
4262
4930
  }
4263
4931
  try {
4264
- const entries = fs2__default.readdirSync(dir, { withFileTypes: true });
4932
+ const entries = fs4__default.readdirSync(dir, { withFileTypes: true });
4265
4933
  for (const entry of entries) {
4266
4934
  const fullPath = path8__default.join(dir, entry.name);
4267
4935
  if (entry.isDirectory()) {
@@ -4308,12 +4976,114 @@ function scanApiDirectory(dir, baseRoute = "") {
4308
4976
  return [];
4309
4977
  }
4310
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
+ }
4311
5081
  function isSnakeCase(str) {
4312
5082
  return /^[a-z][a-z0-9_]*[a-z0-9]$/.test(str) || /^[a-z]$/.test(str);
4313
5083
  }
4314
5084
  function validateToolFile(filePath, fileName) {
4315
5085
  try {
4316
- const content = fs2__default.readFileSync(filePath, "utf-8");
5086
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4317
5087
  const hasDefaultExport = /export\s+default\s+defineTool/.test(content);
4318
5088
  if (!hasDefaultExport) {
4319
5089
  return `Tool file '${fileName}.ts' must have a default export using defineTool()`;
@@ -4325,10 +5095,10 @@ function validateToolFile(filePath, fileName) {
4325
5095
  }
4326
5096
  async function scanToolsDirectory(dir) {
4327
5097
  const tools = [];
4328
- if (!fs2__default.existsSync(dir)) {
5098
+ if (!fs4__default.existsSync(dir)) {
4329
5099
  return tools;
4330
5100
  }
4331
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5101
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4332
5102
  for (const entry of entries) {
4333
5103
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4334
5104
  const fileName = entry.name.replace(".ts", "");
@@ -4360,10 +5130,10 @@ async function scanToolsDirectory(dir) {
4360
5130
  }
4361
5131
  async function scanHooksDirectory(dir) {
4362
5132
  const hooks = [];
4363
- if (!fs2__default.existsSync(dir)) {
5133
+ if (!fs4__default.existsSync(dir)) {
4364
5134
  return hooks;
4365
5135
  }
4366
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5136
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4367
5137
  for (const entry of entries) {
4368
5138
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4369
5139
  const fileName = entry.name.replace(".ts", "");
@@ -4373,7 +5143,7 @@ async function scanHooksDirectory(dir) {
4373
5143
  const filePath = path8__default.join(dir, entry.name);
4374
5144
  const importPath = "./" + path8__default.relative(process.cwd(), filePath).replace(/\\/g, "/");
4375
5145
  try {
4376
- const content = fs2__default.readFileSync(filePath, "utf-8");
5146
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4377
5147
  const idMatch = content.match(/id:\s*['"]([^'"]+)['"]/);
4378
5148
  const hookMatch = content.match(/hook:\s*['"]([^'"]+)['"]/);
4379
5149
  if (idMatch && hookMatch) {
@@ -4396,16 +5166,16 @@ async function scanHooksDirectory(dir) {
4396
5166
  }
4397
5167
  async function scanConfigDirectory(dir, definePattern) {
4398
5168
  const items = [];
4399
- if (!fs2__default.existsSync(dir)) {
5169
+ if (!fs4__default.existsSync(dir)) {
4400
5170
  return items;
4401
5171
  }
4402
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5172
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4403
5173
  for (const entry of entries) {
4404
5174
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4405
5175
  const filePath = path8__default.join(dir, entry.name);
4406
5176
  const importPath = "./" + path8__default.relative(process.cwd(), filePath).replace(/\\/g, "/");
4407
5177
  try {
4408
- const content = fs2__default.readFileSync(filePath, "utf-8");
5178
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4409
5179
  const hasDefaultExport = definePattern.test(content);
4410
5180
  if (!hasDefaultExport) {
4411
5181
  items.push({
@@ -4447,10 +5217,10 @@ async function scanAgentsDirectory(dir) {
4447
5217
  }
4448
5218
  async function scanEffectsDirectory(dir) {
4449
5219
  const effects = [];
4450
- if (!fs2__default.existsSync(dir)) {
5220
+ if (!fs4__default.existsSync(dir)) {
4451
5221
  return effects;
4452
5222
  }
4453
- const entries = await fs2__default.promises.readdir(dir, { withFileTypes: true });
5223
+ const entries = await fs4__default.promises.readdir(dir, { withFileTypes: true });
4454
5224
  for (const entry of entries) {
4455
5225
  if (entry.isFile() && entry.name.endsWith(".ts")) {
4456
5226
  const fileName = entry.name.replace(".ts", "");
@@ -4460,7 +5230,7 @@ async function scanEffectsDirectory(dir) {
4460
5230
  continue;
4461
5231
  }
4462
5232
  try {
4463
- const content = fs2__default.readFileSync(filePath, "utf-8");
5233
+ const content = fs4__default.readFileSync(filePath, "utf-8");
4464
5234
  if (!content.includes("defineEffect")) {
4465
5235
  continue;
4466
5236
  }
@@ -4522,7 +5292,7 @@ function agentbuilder(options = {}) {
4522
5292
  const rou3Path = path8__default.join(__dirname, "../dist/rou3.js");
4523
5293
  let rou3Code = "";
4524
5294
  try {
4525
- 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();
4526
5296
  } catch (err) {
4527
5297
  console.warn("[vite-plugin-agent] Could not read rou3.js for inlining:", err);
4528
5298
  }
@@ -4873,7 +5643,7 @@ function agentbuilder(options = {}) {
4873
5643
  );
4874
5644
  return {
4875
5645
  // Set publicDir to builder's client assets so Cloudflare plugin preserves assets config
4876
- publicDir: fs2__default.existsSync(builderClientDir) ? builderClientDir : void 0,
5646
+ publicDir: fs4__default.existsSync(builderClientDir) ? builderClientDir : void 0,
4877
5647
  build: {
4878
5648
  rollupOptions: {
4879
5649
  // The packing system dynamically imports rollup, typescript, and related
@@ -5041,6 +5811,7 @@ ${toolsCode}
5041
5811
  }
5042
5812
  if (id === RESOLVED_VIRTUAL_ROUTES_ID) {
5043
5813
  const threadRoutes = scanApiDirectory(threadApiDir);
5814
+ const toAbsolutePath = (inputPath) => path8__default.resolve(process.cwd(), inputPath).replace(/\\/g, "/");
5044
5815
  const threadRouteCode = threadRoutes.map(({ method, route, importPath }) => {
5045
5816
  const apiRoute = `/api/threads/:id${route}`;
5046
5817
  return ` addRoute(
@@ -5048,6 +5819,44 @@ ${toolsCode}
5048
5819
  "${method}",
5049
5820
  "${apiRoute}",
5050
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
5051
5860
  );`;
5052
5861
  }).join("\n");
5053
5862
  return `// Inline rou3 router code (no external imports) /* v${routesVersion} */
@@ -5089,6 +5898,11 @@ function isPublicRoute(routePath) {
5089
5898
  return true;
5090
5899
  }
5091
5900
 
5901
+ // Packed thread routes are also public
5902
+ if (routePath.startsWith('/api/packages/') && routePath.includes('/threads/')) {
5903
+ return true;
5904
+ }
5905
+
5092
5906
  // Provider icon routes are public (used by <img src>)
5093
5907
  if (routePath.startsWith('/api/providers/') && routePath.includes('/icon')) {
5094
5908
  return true;
@@ -5171,6 +5985,9 @@ export async function router(request, env) {
5171
5985
  // Register user thread API routes
5172
5986
  ${threadRouteCode}
5173
5987
 
5988
+ // Register packed thread API routes
5989
+ ${packedThreadRouteCode}
5990
+
5174
5991
  const routeMatch = findRoute(
5175
5992
  router,
5176
5993
  request.method.toUpperCase(),
@@ -5458,6 +6275,7 @@ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package
5458
6275
  const models = await scanModelsDirectory(modelsDir);
5459
6276
  const prompts = await scanPromptsDirectory(promptsDir);
5460
6277
  const agents = await scanAgentsDirectory(agentsDir);
6278
+ const effects = await scanEffectsDirectory(effectsDir);
5461
6279
  const toAbsolutePath = (relativePath) => {
5462
6280
  if (relativePath.startsWith("./")) {
5463
6281
  return path8__default.resolve(process.cwd(), relativePath).replace(/\\/g, "/");
@@ -5484,49 +6302,45 @@ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package
5484
6302
  const absPath = toAbsolutePath(importPath);
5485
6303
  return ` "${id2}": async () => (await import("${absPath}")).default,`;
5486
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");
5487
6309
  const packedDir = path8__default.resolve(process.cwd(), "agents/packed");
5488
6310
  const packedPackages = [];
5489
- if (fs2__default.existsSync(packedDir)) {
6311
+ if (fs4__default.existsSync(packedDir)) {
5490
6312
  console.log(`[vite-plugin-agent] Scanning packed directory: ${packedDir}`);
5491
- const pkgDirs = fs2__default.readdirSync(packedDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
5492
- console.log(`[vite-plugin-agent] Found package dirs: ${pkgDirs.join(", ")}`);
5493
- for (const pkgDirName of pkgDirs) {
5494
- 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) {
5495
6316
  const pkgJsonPath = path8__default.join(pkgPath, "package.json");
5496
- if (fs2__default.existsSync(pkgJsonPath)) {
6317
+ if (fs4__default.existsSync(pkgJsonPath)) {
5497
6318
  try {
5498
- const pkgJson = JSON.parse(fs2__default.readFileSync(pkgJsonPath, "utf-8"));
5499
- 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);
5500
6321
  if (!pkgJson.standardagent) {
5501
6322
  continue;
5502
6323
  }
5503
6324
  const mainEntry = pkgJson.main || "./dist/index.js";
5504
6325
  const outputDir2 = path8__default.dirname(mainEntry).replace(/^\.\//, "");
5505
- const scanPackedDir = async (subDir) => {
5506
- const fullPath = path8__default.join(pkgPath, outputDir2, subDir);
5507
- if (!fs2__default.existsSync(fullPath)) return [];
5508
- const files = fs2__default.readdirSync(fullPath).filter((f) => f.endsWith(".js") || f.endsWith(".ts")).map((f) => ({
5509
- name: f.replace(/\.(js|ts)$/, ""),
5510
- path: path8__default.join(fullPath, f).replace(/\\/g, "/")
5511
- }));
5512
- return files;
5513
- };
5514
6326
  const pkg = {
5515
6327
  packageId: pkgJson.name,
5516
6328
  version: pkgJson.version,
5517
6329
  entryAgents: pkgJson.standardagent.entryAgents || [],
5518
6330
  items: {
5519
- agents: await scanPackedDir("agents"),
5520
- prompts: await scanPackedDir("prompts"),
5521
- tools: await scanPackedDir("tools"),
5522
- models: await scanPackedDir("models"),
5523
- 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)
5524
6338
  }
5525
6339
  };
5526
6340
  console.log(`[vite-plugin-agent] Scanned package ${pkgJson.name}:`, pkg.items.agents);
5527
6341
  packedPackages.push(pkg);
5528
6342
  } catch (err) {
5529
- 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);
5530
6344
  }
5531
6345
  }
5532
6346
  }
@@ -5547,6 +6361,12 @@ ${allProviders.map((p) => ` "${p.name}": async () => (await import("${p.package
5547
6361
  return { ...mod.default, __package: ${signature} };
5548
6362
  },`
5549
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");
5550
6370
  return ` "${pkg.packageId}": {
5551
6371
  agents: {
5552
6372
  ${genLoaders(pkg.items.agents)}
@@ -5562,6 +6382,12 @@ ${genLoaders(pkg.items.models)}
5562
6382
  },
5563
6383
  hooks: {
5564
6384
  ${genLoaders(pkg.items.hooks)}
6385
+ },
6386
+ effects: {
6387
+ ${genEffectLoaders(pkg.items.effects)}
6388
+ },
6389
+ threadEndpoints: {
6390
+ ${genThreadEndpointLoaders(pkg.items.threadEndpoints)}
5565
6391
  },
5566
6392
  entryAgents: ${JSON.stringify(pkg.entryAgents)},
5567
6393
  signature: ${signature},
@@ -5587,6 +6413,10 @@ ${globalModelsCode}
5587
6413
  hooks: {
5588
6414
  ${globalHooksCode}
5589
6415
  },
6416
+ effects: {
6417
+ ${globalEffectsCode}
6418
+ },
6419
+ threadEndpoints: {},
5590
6420
  },
5591
6421
  packages: {
5592
6422
  ${packagesCode}
@@ -5865,11 +6695,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
5865
6695
  try {
5866
6696
  const rawBody = await parseRequestBody(req);
5867
6697
  const body = transformModelData(rawBody);
5868
- const validationError = validateModelData(body);
5869
- if (validationError) {
6698
+ const fieldErrors = validateModelData(body);
6699
+ if (fieldErrors) {
5870
6700
  res.statusCode = 400;
5871
6701
  res.setHeader("Content-Type", "application/json");
5872
- res.end(JSON.stringify({ error: validationError }));
6702
+ res.end(JSON.stringify({ error: "Validation failed", fieldErrors }));
5873
6703
  return;
5874
6704
  }
5875
6705
  if (modelExists(modelsDir, body.name)) {
@@ -5910,11 +6740,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
5910
6740
  const body = transformModelData(rawBody);
5911
6741
  const newName = body.name;
5912
6742
  const isNameChange = newName && newName !== urlModelName;
5913
- const validationError = validateModelData(body);
5914
- if (validationError) {
6743
+ const fieldErrors = validateModelData(body);
6744
+ if (fieldErrors) {
5915
6745
  res.statusCode = 400;
5916
6746
  res.setHeader("Content-Type", "application/json");
5917
- res.end(JSON.stringify({ error: validationError }));
6747
+ res.end(JSON.stringify({ error: "Validation failed", fieldErrors }));
5918
6748
  return;
5919
6749
  }
5920
6750
  let updatedPrompts = [];
@@ -5989,11 +6819,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
5989
6819
  try {
5990
6820
  const rawBody = await parseRequestBody(req);
5991
6821
  const body = transformPromptData(rawBody);
5992
- const validationError = validatePromptData(body);
5993
- if (validationError) {
6822
+ const fieldErrors = validatePromptData(body);
6823
+ if (fieldErrors) {
5994
6824
  res.statusCode = 400;
5995
6825
  res.setHeader("Content-Type", "application/json");
5996
- res.end(JSON.stringify({ error: validationError }));
6826
+ res.end(JSON.stringify({ error: "Validation failed", fieldErrors }));
5997
6827
  return;
5998
6828
  }
5999
6829
  if (promptExists(promptsDir, body.name)) {
@@ -6034,11 +6864,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6034
6864
  const body = transformPromptData(rawBody);
6035
6865
  const newName = body.name;
6036
6866
  const isNameChange = newName && newName !== urlPromptName;
6037
- const validationError = validatePromptData(body);
6038
- if (validationError) {
6867
+ const fieldErrors = validatePromptData(body);
6868
+ if (fieldErrors) {
6039
6869
  res.statusCode = 400;
6040
6870
  res.setHeader("Content-Type", "application/json");
6041
- res.end(JSON.stringify({ error: validationError }));
6871
+ res.end(JSON.stringify({ error: "Validation failed", fieldErrors }));
6042
6872
  return;
6043
6873
  }
6044
6874
  let updatedPrompts = [];
@@ -6114,11 +6944,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6114
6944
  try {
6115
6945
  const rawBody = await parseRequestBody(req);
6116
6946
  const body = transformAgentData(rawBody);
6117
- const validationError = validateAgentData(body);
6118
- if (validationError) {
6947
+ const fieldErrors = validateAgentData(body);
6948
+ if (fieldErrors) {
6119
6949
  res.statusCode = 400;
6120
6950
  res.setHeader("Content-Type", "application/json");
6121
- res.end(JSON.stringify({ error: validationError }));
6951
+ res.end(JSON.stringify({ error: "Validation failed", fieldErrors }));
6122
6952
  return;
6123
6953
  }
6124
6954
  if (agentExists(agentsDir, body.name)) {
@@ -6158,11 +6988,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6158
6988
  const rawBody = await parseRequestBody(req);
6159
6989
  const body = transformAgentData(rawBody);
6160
6990
  body.name = agentName;
6161
- const validationError = validateAgentData(body);
6162
- if (validationError) {
6991
+ const fieldErrors = validateAgentData(body);
6992
+ if (fieldErrors) {
6163
6993
  res.statusCode = 400;
6164
6994
  res.setHeader("Content-Type", "application/json");
6165
- res.end(JSON.stringify({ error: validationError }));
6995
+ res.end(JSON.stringify({ error: "Validation failed", fieldErrors }));
6166
6996
  return;
6167
6997
  }
6168
6998
  const result = await saveAgent(agentsDir, body, true);
@@ -6404,14 +7234,14 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6404
7234
  const rootDir = process.cwd();
6405
7235
  const packedDir = path8__default.join(rootDir, "agents", "packed");
6406
7236
  let packageDir = path8__default.join(packedDir, packageId);
6407
- if (!fs2__default.existsSync(packageDir)) {
6408
- if (!fs2__default.existsSync(packedDir)) {
7237
+ if (!fs4__default.existsSync(packageDir)) {
7238
+ if (!fs4__default.existsSync(packedDir)) {
6409
7239
  res.statusCode = 400;
6410
7240
  res.setHeader("Content-Type", "application/json");
6411
7241
  res.end(JSON.stringify({ error: "No packed packages found. Pack the agent first." }));
6412
7242
  return;
6413
7243
  }
6414
- 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);
6415
7245
  const matchingDir = dirs.find(
6416
7246
  (d) => d === packageId || d === `standardagent-${packageId}` || d === `standardagent-${packageId.replace(/_/g, "-")}`
6417
7247
  );
@@ -6429,8 +7259,8 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6429
7259
  let tokenSource = body.token ? "provided" : "environment";
6430
7260
  if (!token) {
6431
7261
  const devVarsPath = path8__default.join(rootDir, ".dev.vars");
6432
- if (fs2__default.existsSync(devVarsPath)) {
6433
- const devVars = fs2__default.readFileSync(devVarsPath, "utf-8");
7262
+ if (fs4__default.existsSync(devVarsPath)) {
7263
+ const devVars = fs4__default.readFileSync(devVarsPath, "utf-8");
6434
7264
  const match = devVars.match(/^NPM_TOKEN=(.+)$/m);
6435
7265
  if (match) {
6436
7266
  token = match[1].trim();
@@ -6582,11 +7412,11 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6582
7412
  filePath = path8__default.join(clientDir, "index.html");
6583
7413
  }
6584
7414
  try {
6585
- if (fs2__default.existsSync(filePath)) {
6586
- let content = fs2__default.readFileSync(filePath);
7415
+ if (fs4__default.existsSync(filePath)) {
7416
+ let content = fs4__default.readFileSync(filePath);
6587
7417
  const ext = path8__default.extname(filePath).toLowerCase();
6588
7418
  if (ext === ".html") {
6589
- const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { mountPoint: "${mountPoint}" };</script>`;
7419
+ const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { mountPoint: "${mountPoint}", devMode: true };</script>`;
6590
7420
  let htmlContent = content.toString();
6591
7421
  const assetPrefix = mountPoint === "/" ? "/" : `${mountPoint}/`;
6592
7422
  htmlContent = htmlContent.replace(/\/agents\//g, assetPrefix);
@@ -6629,21 +7459,21 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6629
7459
  currentDir,
6630
7460
  isInDist ? "./client" : "../dist/client"
6631
7461
  );
6632
- if (!fs2__default.existsSync(clientDir)) {
7462
+ if (!fs4__default.existsSync(clientDir)) {
6633
7463
  console.warn(`[agentbuilder] Client directory not found at ${clientDir}`);
6634
7464
  return;
6635
7465
  }
6636
- fs2__default.mkdirSync(mountDir, { recursive: true });
7466
+ fs4__default.mkdirSync(mountDir, { recursive: true });
6637
7467
  function copyRecursive(src, dest) {
6638
- const entries = fs2__default.readdirSync(src, { withFileTypes: true });
7468
+ const entries = fs4__default.readdirSync(src, { withFileTypes: true });
6639
7469
  for (const entry of entries) {
6640
7470
  const srcPath = path8__default.join(src, entry.name);
6641
7471
  const destPath = path8__default.join(dest, entry.name);
6642
7472
  if (entry.isDirectory()) {
6643
- fs2__default.mkdirSync(destPath, { recursive: true });
7473
+ fs4__default.mkdirSync(destPath, { recursive: true });
6644
7474
  copyRecursive(srcPath, destPath);
6645
7475
  } else {
6646
- let content = fs2__default.readFileSync(srcPath);
7476
+ let content = fs4__default.readFileSync(srcPath);
6647
7477
  if (entry.name === "index.html") {
6648
7478
  const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { mountPoint: "${mountPoint}" };</script>`;
6649
7479
  let htmlContent = content.toString();
@@ -6652,7 +7482,7 @@ export class DurableAgentBuilder extends _BaseDurableAgentBuilder {
6652
7482
  htmlContent = htmlContent.replace("</head>", `${configScript}</head>`);
6653
7483
  content = Buffer.from(htmlContent);
6654
7484
  }
6655
- fs2__default.writeFileSync(destPath, content);
7485
+ fs4__default.writeFileSync(destPath, content);
6656
7486
  }
6657
7487
  }
6658
7488
  }