@faapi/faapi 6.23.0 → 6.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3082,8 +3082,6 @@ var init_generateToolArtifacts = __esm({
3082
3082
 
3083
3083
  // src/agents/scanAgents.ts
3084
3084
  import fg3 from "fast-glob";
3085
- import path15 from "path";
3086
- import fs12 from "fs";
3087
3085
  function extractAgentNameFromPath(filePath) {
3088
3086
  const normalized = filePath.replace(/\\/g, "/");
3089
3087
  const match = normalized.match(/(?:^|\/)agents\/(.+)\/handler\.ts$/);
@@ -3094,11 +3092,6 @@ function extractAgentNameFromPath(filePath) {
3094
3092
  }
3095
3093
  return match[1].replace(/\//g, ".");
3096
3094
  }
3097
- function detectAgentExports(source) {
3098
- return {
3099
- hasRun: RUN_EXPORT_RE.test(source)
3100
- };
3101
- }
3102
3095
  async function scanAgents(rootDir, patterns) {
3103
3096
  const files = await fg3(patterns, {
3104
3097
  cwd: rootDir,
@@ -3113,9 +3106,6 @@ async function scanAgents(rootDir, patterns) {
3113
3106
  if (fileName !== "handler.ts" && fileName !== "handler.js") {
3114
3107
  continue;
3115
3108
  }
3116
- const absPath = path15.resolve(rootDir, normalizedFile);
3117
- const source = await fs12.promises.readFile(absPath, "utf8").catch(() => "");
3118
- const { hasRun } = detectAgentExports(source);
3119
3109
  const name = extractAgentNameFromPath(normalizedFile);
3120
3110
  const prevFile = seen.get(name);
3121
3111
  if (prevFile) {
@@ -3126,18 +3116,16 @@ async function scanAgents(rootDir, patterns) {
3126
3116
  seen.set(name, normalizedFile);
3127
3117
  agents.push({
3128
3118
  name,
3129
- filePath: normalizedFile,
3130
- hasRun
3119
+ filePath: normalizedFile
3131
3120
  });
3132
3121
  }
3133
3122
  return agents;
3134
3123
  }
3135
- var DEFAULT_AGENT_PATTERNS, RUN_EXPORT_RE;
3124
+ var DEFAULT_AGENT_PATTERNS;
3136
3125
  var init_scanAgents = __esm({
3137
3126
  "src/agents/scanAgents.ts"() {
3138
3127
  "use strict";
3139
3128
  DEFAULT_AGENT_PATTERNS = ["src/agents/**/handler.ts"];
3140
- RUN_EXPORT_RE = /export\s+(?:async\s+)?(?:function\s+|const\s+)run\b/;
3141
3129
  }
3142
3130
  });
3143
3131
 
@@ -3146,12 +3134,21 @@ import ts11 from "typescript";
3146
3134
  function extractAgentMetadata(program, filePath, pathMeta) {
3147
3135
  const sourceFile = program.getSourceFile(filePath);
3148
3136
  if (!sourceFile) return null;
3137
+ const runOwner = findRunExportOwner(sourceFile);
3138
+ if (runOwner) {
3139
+ throw SchemaExtractionError.at(
3140
+ runOwner,
3141
+ "run",
3142
+ "agent \u81EA\u5B9A\u4E49 run \u5DF2\u79FB\u9664\u2014\u2014agent \u7EDF\u4E00\u4E3A\u58F0\u660E\u5F0F\u6267\u884C\uFF08config + \u9ED8\u8BA4 reactLoop\uFF09\u3002\u7F16\u6392\u573A\u666F\u8BF7\u6CE8\u518C tool\uFF08src/tools/ \u4E0B\u5BFC\u51FA\u51FD\u6570\uFF0C\u6709 schema/trace/\u9274\u6743\u94A9\u5B50\uFF09\uFF0C\u591A agent \u534F\u4F5C\u7528 config.agents \u58F0\u660E sub-agent",
3143
+ sourceFile
3144
+ );
3145
+ }
3149
3146
  const configFound = findConfigExport(sourceFile);
3150
3147
  if (!configFound) {
3151
3148
  throw SchemaExtractionError.at(
3152
3149
  sourceFile,
3153
3150
  "config.systemPrompt",
3154
- "agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09",
3151
+ "agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E systemPrompt\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09\u6216 systemPromptFile\uFF08\u76F8\u5BF9 resources \u76EE\u5F55\u7684\u8DEF\u5F84\u5B57\u9762\u91CF\uFF09\u4E8C\u9009\u4E00",
3155
3152
  sourceFile
3156
3153
  );
3157
3154
  }
@@ -3167,16 +3164,13 @@ function extractAgentMetadata(program, filePath, pathMeta) {
3167
3164
  const jsDoc = getJSDocFromNode(configFound.jsDocOwner);
3168
3165
  const description = extractDescription(jsDoc);
3169
3166
  const agentNameOverride = extractJSDocTagValue(jsDoc, "agent");
3170
- const { systemPrompt, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(
3171
- objectLiteral,
3172
- sourceFile
3173
- );
3167
+ const { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(objectLiteral, sourceFile);
3174
3168
  return {
3175
3169
  name: agentNameOverride ?? pathMeta.name,
3176
3170
  description,
3177
3171
  filePath: pathMeta.filePath,
3178
- hasRun: pathMeta.hasRun,
3179
3172
  systemPrompt,
3173
+ systemPromptFile,
3180
3174
  tools,
3181
3175
  agents,
3182
3176
  model,
@@ -3184,6 +3178,25 @@ function extractAgentMetadata(program, filePath, pathMeta) {
3184
3178
  inputDescription
3185
3179
  };
3186
3180
  }
3181
+ function findRunExportOwner(sourceFile) {
3182
+ let result = null;
3183
+ ts11.forEachChild(sourceFile, (node) => {
3184
+ if (result) return;
3185
+ if (ts11.isFunctionDeclaration(node) && hasExportModifier(node) && node.name?.text === "run") {
3186
+ result = node;
3187
+ return;
3188
+ }
3189
+ if (ts11.isVariableStatement(node) && hasExportModifier(node)) {
3190
+ for (const decl of node.declarationList.declarations) {
3191
+ if (ts11.isIdentifier(decl.name) && decl.name.text === "run") {
3192
+ result = node;
3193
+ return;
3194
+ }
3195
+ }
3196
+ }
3197
+ });
3198
+ return result;
3199
+ }
3187
3200
  function findConfigExport(sourceFile) {
3188
3201
  let result = null;
3189
3202
  ts11.forEachChild(sourceFile, (node) => {
@@ -3226,6 +3239,7 @@ function getReturnObjectLiteral(fn) {
3226
3239
  }
3227
3240
  function extractConfigFields(objLit, sourceFile) {
3228
3241
  let systemPrompt;
3242
+ let systemPromptFile;
3229
3243
  let tools;
3230
3244
  let agents;
3231
3245
  let model;
@@ -3249,6 +3263,9 @@ function extractConfigFields(objLit, sourceFile) {
3249
3263
  case "systemPrompt":
3250
3264
  systemPrompt = requireStringValue(prop, "systemPrompt", sourceFile);
3251
3265
  break;
3266
+ case "systemPromptFile":
3267
+ systemPromptFile = requireStringValue(prop, "systemPromptFile", sourceFile);
3268
+ break;
3252
3269
  case "tools":
3253
3270
  tools = requireStringArrayValue(prop, "tools", sourceFile);
3254
3271
  break;
@@ -3268,20 +3285,28 @@ function extractConfigFields(objLit, sourceFile) {
3268
3285
  throw SchemaExtractionError.at(
3269
3286
  prop,
3270
3287
  `config.${propName}`,
3271
- "\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / tools / agents / model / maxTurns / inputDescription",
3288
+ "\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / systemPromptFile / tools / agents / model / maxTurns / inputDescription",
3272
3289
  sourceFile
3273
3290
  );
3274
3291
  }
3275
3292
  }
3276
- if (systemPrompt === void 0) {
3293
+ if (systemPrompt !== void 0 && systemPromptFile !== void 0) {
3277
3294
  throw SchemaExtractionError.at(
3278
3295
  objLit,
3279
3296
  "config.systemPrompt",
3280
- "agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09",
3297
+ "systemPrompt \u4E0E systemPromptFile \u4E92\u65A5\u2014\u2014\u5185\u8054\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E0E resources \u6587\u4EF6\u4E8C\u9009\u4E00",
3281
3298
  sourceFile
3282
3299
  );
3283
3300
  }
3284
- return { systemPrompt, tools, agents, model, maxTurns, inputDescription };
3301
+ if (systemPrompt === void 0 && systemPromptFile === void 0) {
3302
+ throw SchemaExtractionError.at(
3303
+ objLit,
3304
+ "config.systemPrompt",
3305
+ "agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E systemPrompt\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09\u6216 systemPromptFile\uFF08\u76F8\u5BF9 resources \u76EE\u5F55\u7684\u8DEF\u5F84\u5B57\u9762\u91CF\uFF09\u4E8C\u9009\u4E00",
3306
+ sourceFile
3307
+ );
3308
+ }
3309
+ return { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription };
3285
3310
  }
3286
3311
  function getPropertyName(name) {
3287
3312
  if (ts11.isIdentifier(name)) return name.text;
@@ -3364,13 +3389,13 @@ var init_extractAgentMetadata = __esm({
3364
3389
  });
3365
3390
 
3366
3391
  // src/cli/generateAgentArtifacts.ts
3367
- import path16 from "path";
3392
+ import path15 from "path";
3368
3393
  function serializeAgents(agents, dist = "dist") {
3369
3394
  return agents.map((a) => ({
3370
3395
  name: a.name,
3371
3396
  description: a.description,
3372
- hasRun: a.hasRun,
3373
3397
  systemPrompt: a.systemPrompt,
3398
+ systemPromptFile: a.systemPromptFile,
3374
3399
  tools: a.tools,
3375
3400
  agents: a.agents,
3376
3401
  model: a.model,
@@ -3390,8 +3415,8 @@ function hydrateAgents(manifest) {
3390
3415
  name: a.name,
3391
3416
  description: a.description ?? void 0,
3392
3417
  filePath: a.filePath,
3393
- hasRun: a.hasRun,
3394
3418
  systemPrompt: a.systemPrompt ?? void 0,
3419
+ systemPromptFile: a.systemPromptFile ?? void 0,
3395
3420
  tools: a.tools ?? void 0,
3396
3421
  agents: a.agents ?? void 0,
3397
3422
  model: a.model ?? void 0,
@@ -3423,14 +3448,13 @@ function validateAgentList(metadata) {
3423
3448
  }
3424
3449
  async function generateAgentArtifacts(agents, rootDir, dist) {
3425
3450
  const metadata = [];
3426
- const programByFile = createPrograms(agents.map((m) => path16.resolve(rootDir, m.filePath)));
3451
+ const programByFile = createPrograms(agents.map((m) => path15.resolve(rootDir, m.filePath)));
3427
3452
  for (const manifest of agents) {
3428
- const absPath = path16.resolve(rootDir, manifest.filePath);
3453
+ const absPath = path15.resolve(rootDir, manifest.filePath);
3429
3454
  const program = programByFile.get(absPath);
3430
3455
  const result = extractAgentMetadata(program, absPath, {
3431
3456
  name: manifest.name,
3432
- filePath: manifest.filePath,
3433
- hasRun: manifest.hasRun
3457
+ filePath: manifest.filePath
3434
3458
  });
3435
3459
  if (!result) {
3436
3460
  throw new Error(
@@ -3441,7 +3465,7 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
3441
3465
  }
3442
3466
  validateAgentList(metadata);
3443
3467
  const serialized = serializeAgents(metadata, dist);
3444
- const agentsPath = path16.resolve(rootDir, dist, AGENTS_FILE);
3468
+ const agentsPath = path15.resolve(rootDir, dist, AGENTS_FILE);
3445
3469
  await writeAgentsModule(serialized, agentsPath);
3446
3470
  return metadata;
3447
3471
  }
@@ -3459,8 +3483,8 @@ var init_generateAgentArtifacts = __esm({
3459
3483
 
3460
3484
  // src/task/scanTasks.ts
3461
3485
  import fg4 from "fast-glob";
3462
- import path17 from "path";
3463
- import fs13 from "fs";
3486
+ import path16 from "path";
3487
+ import fs12 from "fs";
3464
3488
  function parseNumericLiteral(raw) {
3465
3489
  return Number(raw.replace(/_/g, ""));
3466
3490
  }
@@ -3482,12 +3506,12 @@ async function scanTasks(rootDir, patterns) {
3482
3506
  const seen = /* @__PURE__ */ new Map();
3483
3507
  for (const file of files) {
3484
3508
  const normalizedFile = file.replace(/\\/g, "/");
3485
- const fileName = path17.posix.basename(normalizedFile);
3509
+ const fileName = path16.posix.basename(normalizedFile);
3486
3510
  if (fileName !== TASK_FILENAME) {
3487
3511
  continue;
3488
3512
  }
3489
- const absPath = path17.resolve(rootDir, normalizedFile);
3490
- const source = await fs13.promises.readFile(absPath, "utf8").catch(() => "");
3513
+ const absPath = path16.resolve(rootDir, normalizedFile);
3514
+ const source = await fs12.promises.readFile(absPath, "utf8").catch(() => "");
3491
3515
  const name = filePathToTaskName(normalizedFile);
3492
3516
  const prevFile = seen.get(name);
3493
3517
  if (prevFile) {
@@ -3512,6 +3536,11 @@ async function scanTasks(rootDir, patterns) {
3512
3536
  `[faapi] Task "${name}" timeoutMs ${value} is below the minimum ${MIN_ISOLATED_TIMEOUT_MS}ms (1 minute). Declaring a timeout means this is a long-running task that needs real cancellation \u2014 tasks finishing within a minute do not need one: remove timeoutMs to run in-process (implement your own deadline with Promise.race if needed), or raise it.`
3513
3537
  );
3514
3538
  }
3539
+ if (value > MAX_ISOLATED_TIMEOUT_MS) {
3540
+ throw new Error(
3541
+ `[faapi] Task "${name}" timeoutMs ${value} exceeds the maximum ${MAX_ISOLATED_TIMEOUT_MS}ms (23 hours). The pg-boss driver budgets expire_in from timeoutMs (execution budget preventing mid-run re-delivery), and pg-boss 10 asserts expire_in strictly below 24h \u2014 larger timeouts would fail at enqueue time. Split the work into a resumable pipeline (persist progress, enqueue the next stage), or use the bullmq driver (Redis has no such cap).`
3542
+ );
3543
+ }
3515
3544
  manifest.timeoutMs = value;
3516
3545
  }
3517
3546
  if (graceMs !== void 0) manifest.graceMs = parseNumericLiteral(graceMs);
@@ -3519,7 +3548,7 @@ async function scanTasks(rootDir, patterns) {
3519
3548
  }
3520
3549
  return tasks.sort((a, b) => a.name.localeCompare(b.name));
3521
3550
  }
3522
- var TASK_PATTERNS, TASK_FILENAME, CRON_RE, NUM_LITERAL, CONCURRENCY_RE, RETRIES_RE, TIMEOUT_MS_RE, GRACE_MS_RE, MIN_ISOLATED_TIMEOUT_MS;
3551
+ var TASK_PATTERNS, TASK_FILENAME, CRON_RE, NUM_LITERAL, CONCURRENCY_RE, RETRIES_RE, TIMEOUT_MS_RE, GRACE_MS_RE, MIN_ISOLATED_TIMEOUT_MS, MAX_ISOLATED_TIMEOUT_MS;
3523
3552
  var init_scanTasks = __esm({
3524
3553
  "src/task/scanTasks.ts"() {
3525
3554
  "use strict";
@@ -3532,11 +3561,12 @@ var init_scanTasks = __esm({
3532
3561
  TIMEOUT_MS_RE = new RegExp(`(?:^|\\n)\\s*timeoutMs:\\s*${NUM_LITERAL}`);
3533
3562
  GRACE_MS_RE = new RegExp(`(?:^|\\n)\\s*graceMs:\\s*${NUM_LITERAL}`);
3534
3563
  MIN_ISOLATED_TIMEOUT_MS = 6e4;
3564
+ MAX_ISOLATED_TIMEOUT_MS = 23 * 60 * 6e4;
3535
3565
  }
3536
3566
  });
3537
3567
 
3538
3568
  // src/cli/generateTaskArtifacts.ts
3539
- import path18 from "path";
3569
+ import path17 from "path";
3540
3570
  function serializeTasks(tasks, dist = "dist") {
3541
3571
  return tasks.map((t) => ({
3542
3572
  name: t.name,
@@ -3569,7 +3599,7 @@ function collectTaskSchemaSources(tasks, rootDir) {
3569
3599
  const tasksByFile = /* @__PURE__ */ new Map();
3570
3600
  for (const task of tasks) {
3571
3601
  if (!task.inputTypeName) continue;
3572
- const absPath = path18.resolve(rootDir, task.filePath);
3602
+ const absPath = path17.resolve(rootDir, task.filePath);
3573
3603
  let list = tasksByFile.get(absPath);
3574
3604
  if (!list) {
3575
3605
  list = [];
@@ -3626,9 +3656,9 @@ function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
3626
3656
  async function generateTaskArtifacts(manifests, rootDir, dist) {
3627
3657
  const metadata = [];
3628
3658
  if (manifests.length > 0) {
3629
- const programByFile = createPrograms(manifests.map((m) => path18.resolve(rootDir, m.filePath)));
3659
+ const programByFile = createPrograms(manifests.map((m) => path17.resolve(rootDir, m.filePath)));
3630
3660
  for (const manifest of manifests) {
3631
- const absPath = path18.resolve(rootDir, manifest.filePath);
3661
+ const absPath = path17.resolve(rootDir, manifest.filePath);
3632
3662
  const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
3633
3663
  name: manifest.name,
3634
3664
  filePath: manifest.filePath
@@ -3639,7 +3669,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
3639
3669
  }
3640
3670
  }
3641
3671
  const serialized = serializeTasks(manifests, dist);
3642
- const tasksPath = path18.resolve(rootDir, dist, TASKS_FILE);
3672
+ const tasksPath = path17.resolve(rootDir, dist, TASKS_FILE);
3643
3673
  await writeTasksModule(serialized, tasksPath);
3644
3674
  if (metadata.length === 0) {
3645
3675
  return hydrateTasks(serialized);
@@ -3672,8 +3702,8 @@ var init_generateTaskArtifacts = __esm({
3672
3702
  });
3673
3703
 
3674
3704
  // src/cli/compileSourceFiles.ts
3675
- import path19 from "path";
3676
- import fs14 from "fs";
3705
+ import path18 from "path";
3706
+ import fs13 from "fs";
3677
3707
  import fg5 from "fast-glob";
3678
3708
  async function compileSourceFiles(options) {
3679
3709
  const { rootDir, dist, files, logLevel = "silent", production, atomicWrite } = options;
@@ -3686,11 +3716,11 @@ async function compileSourceFiles(options) {
3686
3716
  if (entryPoints.length === 0) {
3687
3717
  return { compiledFiles: [] };
3688
3718
  }
3689
- const absDist = path19.resolve(rootDir, dist);
3690
- await fs14.promises.mkdir(absDist, { recursive: true });
3719
+ const absDist = path18.resolve(rootDir, dist);
3720
+ await fs13.promises.mkdir(absDist, { recursive: true });
3691
3721
  const plugins = buildAliasPlugins(rootDir);
3692
3722
  const esbuild = await import("esbuild");
3693
- const outbase = path19.resolve(rootDir, APP_DIR);
3723
+ const outbase = path18.resolve(rootDir, APP_DIR);
3694
3724
  const result = await esbuild.build({
3695
3725
  entryPoints,
3696
3726
  outdir: absDist,
@@ -3710,10 +3740,10 @@ async function compileSourceFiles(options) {
3710
3740
  if (atomicWrite && result.outputFiles) {
3711
3741
  await Promise.all(
3712
3742
  result.outputFiles.map(async (file) => {
3713
- await fs14.promises.mkdir(path19.dirname(file.path), { recursive: true });
3743
+ await fs13.promises.mkdir(path18.dirname(file.path), { recursive: true });
3714
3744
  const tmp = `${file.path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
3715
- await fs14.promises.writeFile(tmp, file.contents);
3716
- await fs14.promises.rename(tmp, file.path);
3745
+ await fs13.promises.writeFile(tmp, file.contents);
3746
+ await fs13.promises.rename(tmp, file.path);
3717
3747
  })
3718
3748
  );
3719
3749
  }
@@ -3741,12 +3771,12 @@ var init_compileDevRoutes = __esm({
3741
3771
  });
3742
3772
 
3743
3773
  // src/cli/compileOnDemand.ts
3744
- import path20 from "path";
3745
- import fs15 from "fs";
3774
+ import path19 from "path";
3775
+ import fs14 from "fs";
3746
3776
  function isProductFresh(sourceAbsPath, productAbsPath) {
3747
3777
  try {
3748
- const srcStat = fs15.statSync(sourceAbsPath);
3749
- const prodStat = fs15.statSync(productAbsPath);
3778
+ const srcStat = fs14.statSync(sourceAbsPath);
3779
+ const prodStat = fs14.statSync(productAbsPath);
3750
3780
  return prodStat.mtimeMs >= srcStat.mtimeMs;
3751
3781
  } catch {
3752
3782
  return false;
@@ -3776,7 +3806,7 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
3776
3806
  if (state.compiledFiles.has(sourceAbsPath)) {
3777
3807
  return false;
3778
3808
  }
3779
- if (!fs15.existsSync(sourceAbsPath)) {
3809
+ if (!fs14.existsSync(sourceAbsPath)) {
3780
3810
  return false;
3781
3811
  }
3782
3812
  const productPath = prodSourcePathToProductPath(sourceAbsPath, rootDir, dist);
@@ -3826,11 +3856,11 @@ async function ensureMiddlewaresCompiled(middlewarePaths, rootDir) {
3826
3856
  }
3827
3857
  }
3828
3858
  function prodSourcePathToProductPath(sourceAbsPath, rootDir, dist) {
3829
- const rel = path20.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3859
+ const rel = path19.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3830
3860
  if (!rel.startsWith("src/")) return null;
3831
3861
  const relWithoutSrc = rel.slice(4);
3832
3862
  const jsRel = relWithoutSrc.replace(/\.ts$/, ".js");
3833
- return path20.resolve(rootDir, dist, jsRel);
3863
+ return path19.resolve(rootDir, dist, jsRel);
3834
3864
  }
3835
3865
  function clearGeneratedSchemas() {
3836
3866
  state.generatedSchemas.clear();
@@ -3845,9 +3875,9 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
3845
3875
  if (state.generatedSchemas.has(schemaPath)) {
3846
3876
  return false;
3847
3877
  }
3848
- const prodAbsPath = path20.resolve(rootDir, routeFilePath);
3878
+ const prodAbsPath = path19.resolve(rootDir, routeFilePath);
3849
3879
  const sourceAbsPath = prodPathToSourcePath(prodAbsPath, rootDir, dist);
3850
- if (!fs15.existsSync(sourceAbsPath)) {
3880
+ if (!fs14.existsSync(sourceAbsPath)) {
3851
3881
  return false;
3852
3882
  }
3853
3883
  if (isProductFresh(sourceAbsPath, schemaPath)) {
@@ -3859,7 +3889,7 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
3859
3889
  if (fileRoutes.length === 0 && fileWsRoutes.length === 0) {
3860
3890
  return false;
3861
3891
  }
3862
- const sourceRelPath = path20.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3892
+ const sourceRelPath = path19.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
3863
3893
  const sourceRoutes = fileRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
3864
3894
  const sourceWsRoutes = fileWsRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
3865
3895
  const generatePromise = (async () => {
@@ -3881,7 +3911,7 @@ async function deleteSchemaFiles(routes, rootDir, dist) {
3881
3911
  if (deleted.has(schemaPath)) continue;
3882
3912
  deleted.add(schemaPath);
3883
3913
  try {
3884
- await fs15.promises.unlink(schemaPath);
3914
+ await fs14.promises.unlink(schemaPath);
3885
3915
  } catch {
3886
3916
  }
3887
3917
  }
@@ -3889,19 +3919,19 @@ async function deleteSchemaFiles(routes, rootDir, dist) {
3889
3919
  function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
3890
3920
  const cached = sourcePathCache.get(prodAbsPath);
3891
3921
  if (cached) return cached;
3892
- const rel = path20.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
3922
+ const rel = path19.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
3893
3923
  let relWithoutDist = rel;
3894
3924
  if (relWithoutDist.startsWith(`${dist}/`)) {
3895
3925
  relWithoutDist = relWithoutDist.slice(dist.length + 1);
3896
3926
  }
3897
3927
  const srcRel = `src/${relWithoutDist}`;
3898
3928
  const tsRel = srcRel.replace(/\.js$/, ".ts");
3899
- const tsAbs = path20.resolve(rootDir, tsRel);
3929
+ const tsAbs = path19.resolve(rootDir, tsRel);
3900
3930
  let result;
3901
- if (fs15.existsSync(tsAbs)) {
3931
+ if (fs14.existsSync(tsAbs)) {
3902
3932
  result = tsAbs;
3903
3933
  } else {
3904
- result = path20.resolve(rootDir, srcRel);
3934
+ result = path19.resolve(rootDir, srcRel);
3905
3935
  }
3906
3936
  sourcePathCache.set(prodAbsPath, result);
3907
3937
  return result;
@@ -3932,15 +3962,15 @@ var init_compileOnDemand = __esm({
3932
3962
  });
3933
3963
 
3934
3964
  // src/config/loadConfig.ts
3935
- import path21 from "path";
3936
- import fs16 from "fs";
3965
+ import path20 from "path";
3966
+ import fs15 from "fs";
3937
3967
  async function loadConfig(rootDir, dist) {
3938
- const configProductPath = path21.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
3939
- if (fs16.existsSync(configProductPath)) {
3968
+ const configProductPath = path20.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
3969
+ if (fs15.existsSync(configProductPath)) {
3940
3970
  const module = await importWithCacheBust(configProductPath);
3941
3971
  return module.default ?? {};
3942
3972
  }
3943
- const hasSourceConfig = fs16.existsSync(path21.join(rootDir, "faapi.config.ts")) || fs16.existsSync(path21.join(rootDir, "faapi.config.js"));
3973
+ const hasSourceConfig = fs15.existsSync(path20.join(rootDir, "faapi.config.ts")) || fs15.existsSync(path20.join(rootDir, "faapi.config.js"));
3944
3974
  if (hasSourceConfig) {
3945
3975
  throw new Error(
3946
3976
  `[faapi] ${dist}/${CONFIG_PRODUCT_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
@@ -3958,8 +3988,8 @@ var init_loadConfig = __esm({
3958
3988
  });
3959
3989
 
3960
3990
  // src/cli/loadEnv.ts
3961
- import fs17 from "fs";
3962
- import path22 from "path";
3991
+ import fs16 from "fs";
3992
+ import path21 from "path";
3963
3993
  function resolveEnv() {
3964
3994
  return process.env.NODE_ENV || "development";
3965
3995
  }
@@ -4026,9 +4056,9 @@ function loadEnv(rootDir) {
4026
4056
  const files = getEnvFiles(env);
4027
4057
  const merged = {};
4028
4058
  for (const file of files) {
4029
- const filePath = path22.join(rootDir, file);
4030
- if (!fs17.existsSync(filePath)) continue;
4031
- const content = fs17.readFileSync(filePath, "utf-8");
4059
+ const filePath = path21.join(rootDir, file);
4060
+ if (!fs16.existsSync(filePath)) continue;
4061
+ const content = fs16.readFileSync(filePath, "utf-8");
4032
4062
  const parsed = parseEnvFile(content, merged);
4033
4063
  Object.assign(merged, parsed);
4034
4064
  }
@@ -5819,41 +5849,41 @@ var init_rebuildScheduler = __esm({
5819
5849
  });
5820
5850
 
5821
5851
  // src/cli/copyResources.ts
5822
- import path23 from "path";
5823
- import fs18 from "fs";
5852
+ import path22 from "path";
5853
+ import fs17 from "fs";
5824
5854
  function isResourceSourcePath(rootDir, absPath) {
5825
- return isInsideDir(absPath, path23.resolve(rootDir, RESOURCES_DIR));
5855
+ return isInsideDir(absPath, path22.resolve(rootDir, RESOURCES_DIR));
5826
5856
  }
5827
5857
  function resolveResourcesDir(rootDir, dist) {
5828
- return path23.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
5858
+ return path22.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
5829
5859
  }
5830
5860
  async function copyResources(rootDir, dist) {
5831
- const sourceDir = path23.resolve(rootDir, RESOURCES_DIR);
5832
- if (!fs18.existsSync(sourceDir)) return false;
5861
+ const sourceDir = path22.resolve(rootDir, RESOURCES_DIR);
5862
+ if (!fs17.existsSync(sourceDir)) return false;
5833
5863
  const outDir = resolveResourcesDir(rootDir, dist);
5834
- await fs18.promises.rm(outDir, { recursive: true, force: true });
5835
- await fs18.promises.cp(sourceDir, outDir, { recursive: true });
5864
+ await fs17.promises.rm(outDir, { recursive: true, force: true });
5865
+ await fs17.promises.cp(sourceDir, outDir, { recursive: true });
5836
5866
  return true;
5837
5867
  }
5838
5868
  async function copyResourceFile(rootDir, dist, absSourceFile) {
5839
- const sourceDir = path23.resolve(rootDir, RESOURCES_DIR);
5869
+ const sourceDir = path22.resolve(rootDir, RESOURCES_DIR);
5840
5870
  if (!isInsideDir(absSourceFile, sourceDir)) {
5841
5871
  throw new Error(`[faapi] copyResourceFile: ${absSourceFile} is not under ${RESOURCES_DIR}`);
5842
5872
  }
5843
- if (!fs18.existsSync(absSourceFile)) return;
5844
- const rel = path23.relative(sourceDir, absSourceFile);
5845
- const dest = path23.join(resolveResourcesDir(rootDir, dist), rel);
5846
- await fs18.promises.mkdir(path23.dirname(dest), { recursive: true });
5847
- await fs18.promises.cp(absSourceFile, dest);
5873
+ if (!fs17.existsSync(absSourceFile)) return;
5874
+ const rel = path22.relative(sourceDir, absSourceFile);
5875
+ const dest = path22.join(resolveResourcesDir(rootDir, dist), rel);
5876
+ await fs17.promises.mkdir(path22.dirname(dest), { recursive: true });
5877
+ await fs17.promises.cp(absSourceFile, dest);
5848
5878
  }
5849
5879
  async function removeResourceFile(rootDir, dist, absSourceFile) {
5850
- const sourceDir = path23.resolve(rootDir, RESOURCES_DIR);
5880
+ const sourceDir = path22.resolve(rootDir, RESOURCES_DIR);
5851
5881
  if (!isInsideDir(absSourceFile, sourceDir)) {
5852
5882
  throw new Error(`[faapi] removeResourceFile: ${absSourceFile} is not under ${RESOURCES_DIR}`);
5853
5883
  }
5854
- const rel = path23.relative(sourceDir, absSourceFile);
5855
- const dest = path23.join(resolveResourcesDir(rootDir, dist), rel);
5856
- await fs18.promises.rm(dest, { force: true });
5884
+ const rel = path22.relative(sourceDir, absSourceFile);
5885
+ const dest = path22.join(resolveResourcesDir(rootDir, dist), rel);
5886
+ await fs17.promises.rm(dest, { force: true });
5857
5887
  }
5858
5888
  var RESOURCES_DIR, RESOURCES_OUTPUT_DIR;
5859
5889
  var init_copyResources = __esm({
@@ -5866,7 +5896,7 @@ var init_copyResources = __esm({
5866
5896
  });
5867
5897
 
5868
5898
  // src/cli/watcher.ts
5869
- import path24 from "path";
5899
+ import path23 from "path";
5870
5900
  import { existsSync as existsSync2 } from "fs";
5871
5901
  function startWatcher(options) {
5872
5902
  const { rootDir, app, devDist } = options;
@@ -5901,9 +5931,9 @@ function startWatcher(options) {
5901
5931
  }
5902
5932
  });
5903
5933
  const CONFIG_FILES = ["faapi.config.ts", "faapi.config.js"];
5904
- const configAbsPaths = new Set(CONFIG_FILES.map((f) => path24.resolve(rootDir, f)));
5934
+ const configAbsPaths = new Set(CONFIG_FILES.map((f) => path23.resolve(rootDir, f)));
5905
5935
  const watchPaths = ["src", "tsconfig.json", ...CONFIG_FILES];
5906
- const scheduleOnly = /* @__PURE__ */ new Set([...configAbsPaths, path24.resolve(rootDir, "tsconfig.json")]);
5936
+ const scheduleOnly = /* @__PURE__ */ new Set([...configAbsPaths, path23.resolve(rootDir, "tsconfig.json")]);
5907
5937
  const watcher = esm_default.watch(watchPaths, {
5908
5938
  cwd: rootDir,
5909
5939
  ignoreInitial: true,
@@ -5914,14 +5944,14 @@ function startWatcher(options) {
5914
5944
  }
5915
5945
  if (!stats) return false;
5916
5946
  if (stats.isDirectory()) return false;
5917
- if (isResourceSourcePath(rootDir, path24.resolve(rootDir, filePath))) return false;
5947
+ if (isResourceSourcePath(rootDir, path23.resolve(rootDir, filePath))) return false;
5918
5948
  return !filePath.endsWith(".ts") && !filePath.endsWith(".js");
5919
5949
  }
5920
5950
  });
5921
5951
  watcher.on("add", (file) => handleFileEvent(file));
5922
5952
  watcher.on("change", (file) => handleFileEvent(file));
5923
5953
  function handleFileEvent(file) {
5924
- const abs = path24.resolve(rootDir, file);
5954
+ const abs = path23.resolve(rootDir, file);
5925
5955
  if (isResourceSourcePath(rootDir, abs)) {
5926
5956
  void copyResourceFile(rootDir, devDist, abs).catch((err) => {
5927
5957
  console.error(
@@ -5941,7 +5971,7 @@ function startWatcher(options) {
5941
5971
  scheduler.addFiles([abs]);
5942
5972
  }
5943
5973
  watcher.on("unlink", (file) => {
5944
- const abs = path24.resolve(rootDir, file);
5974
+ const abs = path23.resolve(rootDir, file);
5945
5975
  if (isResourceSourcePath(rootDir, abs)) {
5946
5976
  void removeResourceFile(rootDir, devDist, abs).catch((err) => {
5947
5977
  console.error(
@@ -6754,17 +6784,17 @@ var init_formatEntry = __esm({
6754
6784
  });
6755
6785
 
6756
6786
  // src/logger/fileSink.ts
6757
- import fs19 from "fs";
6758
- import path25 from "path";
6787
+ import fs18 from "fs";
6788
+ import path24 from "path";
6759
6789
  function createFileLogSink(options) {
6760
- fs19.mkdirSync(options.dir, { recursive: true });
6790
+ fs18.mkdirSync(options.dir, { recursive: true });
6761
6791
  const streams = /* @__PURE__ */ new Map();
6762
6792
  const getStream = (name) => {
6763
6793
  if (streams.has(name)) return streams.get(name);
6764
6794
  return void 0;
6765
6795
  };
6766
6796
  const openStream = (name) => {
6767
- const stream = fs19.createWriteStream(path25.join(options.dir, `${name}.log`), { flags: "a" });
6797
+ const stream = fs18.createWriteStream(path24.join(options.dir, `${name}.log`), { flags: "a" });
6768
6798
  stream.on("error", () => {
6769
6799
  });
6770
6800
  streams.set(name, stream);
@@ -7002,6 +7032,24 @@ var init_queryToObject = __esm({
7002
7032
  }
7003
7033
  });
7004
7034
 
7035
+ // src/utils/readResource.ts
7036
+ import path25 from "path";
7037
+ import fs19 from "fs/promises";
7038
+ function setActiveResourcesDir(dir) {
7039
+ if (dir === null) {
7040
+ delete globalThis[ACTIVE_RESOURCES_DIR_KEY];
7041
+ } else {
7042
+ globalThis[ACTIVE_RESOURCES_DIR_KEY] = dir;
7043
+ }
7044
+ }
7045
+ var ACTIVE_RESOURCES_DIR_KEY;
7046
+ var init_readResource = __esm({
7047
+ "src/utils/readResource.ts"() {
7048
+ "use strict";
7049
+ ACTIVE_RESOURCES_DIR_KEY = /* @__PURE__ */ Symbol.for("faapi.resources.dir");
7050
+ }
7051
+ });
7052
+
7005
7053
  // src/runtime/createContext.ts
7006
7054
  function resolveRequestId(request) {
7007
7055
  const header = request.headers.get("x-request-id");
@@ -9234,8 +9282,15 @@ var init_startServer = __esm({
9234
9282
  });
9235
9283
 
9236
9284
  // src/task/taskWorker.ts
9285
+ import { existsSync as existsSync3 } from "fs";
9237
9286
  import { Worker } from "worker_threads";
9238
- import { pathToFileURL as pathToFileURL2 } from "url";
9287
+ import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
9288
+ function resolveWorkerEntryUrl() {
9289
+ if (workerEntryUrl) return workerEntryUrl;
9290
+ const js = new URL("./workerEntry.js", import.meta.url);
9291
+ workerEntryUrl = existsSync3(fileURLToPath(js)) ? js : new URL("./workerEntry.ts", import.meta.url);
9292
+ return workerEntryUrl;
9293
+ }
9239
9294
  function safeConfig(config) {
9240
9295
  if (config === void 0 || config === null) return config;
9241
9296
  try {
@@ -9249,55 +9304,6 @@ function safeConfig(config) {
9249
9304
  return void 0;
9250
9305
  }
9251
9306
  }
9252
- function buildWrapperSource(moduleUrl) {
9253
- return `
9254
- import { parentPort } from 'node:worker_threads';
9255
- import * as mod from '${moduleUrl}';
9256
-
9257
- ${BUILD_VIEW_SOURCE}
9258
-
9259
- ${SERIALIZE_ERROR_SOURCE}
9260
-
9261
- ${BUILD_LOGGER_SOURCE}
9262
-
9263
- const run = mod.run;
9264
- if (typeof run !== 'function') {
9265
- parentPort.postMessage({
9266
- type: 'error',
9267
- error: { name: 'Error', message: 'Task module has no run export', stack: undefined, props: {} },
9268
- });
9269
- } else {
9270
- let controller = null;
9271
- parentPort.on('message', async (msg) => {
9272
- if (msg?.type === 'abort') {
9273
- controller?.abort(new Error(msg.reason));
9274
- return;
9275
- }
9276
- if (msg?.type !== 'run') return;
9277
- controller = new AbortController();
9278
- const { payload, taskCtx } = msg;
9279
- try {
9280
- const registries = buildRegistriesView(msg.registries);
9281
- const progress = (value) => parentPort.postMessage({ type: 'progress', value });
9282
- const taskLog = msg.log ? createTaskLogger(msg.log.level, msg.log.scope, msg.log.fields) : undefined;
9283
- const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress, log: taskLog });
9284
- parentPort.postMessage({ type: 'done', result });
9285
- } catch (err) {
9286
- const serialized = serializeError(err);
9287
- try {
9288
- parentPort.postMessage({ type: 'error', error: serialized });
9289
- } catch (_) {
9290
- // props \u542B\u4E0D\u53EF\u514B\u9686\u503C\uFF08\u51FD\u6570\u7B49\uFF09\u65F6\u4E22\u5F03 props\uFF0C\u4FDD\u5E95 name/message/stack
9291
- parentPort.postMessage({
9292
- type: 'error',
9293
- error: { name: serialized.name, message: serialized.message, stack: serialized.stack, props: {} },
9294
- });
9295
- }
9296
- }
9297
- });
9298
- }
9299
- `;
9300
- }
9301
9307
  function reviveError(payload) {
9302
9308
  const err = new Error(payload?.message ?? "task worker error");
9303
9309
  if (payload?.name !== void 0) err.name = payload.name;
@@ -9318,13 +9324,12 @@ async function runTaskInWorker(options) {
9318
9324
  );
9319
9325
  }
9320
9326
  const moduleUrl = pathToFileURL2(taskModulePath).href;
9321
- const wrapperUrl = new URL(
9322
- `data:text/javascript,${encodeURIComponent(buildWrapperSource(moduleUrl))}`
9323
- );
9324
9327
  return new Promise((resolve3, reject) => {
9325
9328
  let worker;
9326
9329
  try {
9327
- worker = new Worker(wrapperUrl);
9330
+ worker = new Worker(resolveWorkerEntryUrl(), {
9331
+ workerData: { moduleUrl, resourcesDir: taskCtx.resourcesDir }
9332
+ });
9328
9333
  } catch (err) {
9329
9334
  reject(err);
9330
9335
  return;
@@ -9412,7 +9417,11 @@ async function runTaskInWorker(options) {
9412
9417
  worker.postMessage({
9413
9418
  type: "run",
9414
9419
  payload,
9415
- taskCtx: { config: safeConfig(taskCtx.config), job: taskCtx.job },
9420
+ taskCtx: {
9421
+ config: safeConfig(taskCtx.config),
9422
+ resourcesDir: taskCtx.resourcesDir,
9423
+ job: taskCtx.job
9424
+ },
9416
9425
  registries: options.registries,
9417
9426
  log: options.log
9418
9427
  });
@@ -9425,7 +9434,7 @@ async function runTaskInWorker(options) {
9425
9434
  }
9426
9435
  });
9427
9436
  }
9428
- var KILL_GRACE_MS, TaskCancelledError, BUILD_VIEW_SOURCE, SERIALIZE_ERROR_SOURCE, BUILD_LOGGER_SOURCE;
9437
+ var workerEntryUrl, KILL_GRACE_MS, TaskCancelledError;
9429
9438
  var init_taskWorker = __esm({
9430
9439
  "src/task/taskWorker.ts"() {
9431
9440
  "use strict";
@@ -9436,104 +9445,6 @@ var init_taskWorker = __esm({
9436
9445
  this.name = "TaskCancelledError";
9437
9446
  }
9438
9447
  };
9439
- BUILD_VIEW_SOURCE = `
9440
- function buildRegistriesView(snapshot) {
9441
- var agents = new Map(((snapshot && snapshot.agents) || []).map(function (a) { return [a.name, a]; }));
9442
- var tools = new Map(((snapshot && snapshot.tools) || []).map(function (t) { return [t.name, t]; }));
9443
- var skills = new Map(((snapshot && snapshot.skills) || []).map(function (s) { return [s.name, s]; }));
9444
- return {
9445
- agent: {
9446
- getAgent: function (name) { return agents.get(name); },
9447
- getAgentEntry: function (name) { return agents.get(name); },
9448
- listAgents: function () { return Array.from(agents.values()); },
9449
- asTool: function (name) {
9450
- var agent = agents.get(name);
9451
- if (!agent) return undefined;
9452
- return {
9453
- kind: 'agent',
9454
- name: 'agent.' + agent.name,
9455
- agentName: agent.name,
9456
- description: agent.description,
9457
- metadata: agent,
9458
- };
9459
- },
9460
- resolveAgentTools: function (name) {
9461
- var agent = agents.get(name);
9462
- var result = new Map();
9463
- if (agent && agent.tools) {
9464
- agent.tools.forEach(function (toolName) {
9465
- var resolved = tools.get(toolName);
9466
- if (resolved) result.set(resolved.name, resolved);
9467
- });
9468
- }
9469
- return Array.from(result.values());
9470
- },
9471
- resolveSubAgents: function (name) {
9472
- var agent = agents.get(name);
9473
- var result = [];
9474
- if (agent && agent.agents) {
9475
- agent.agents.forEach(function (subName) {
9476
- var sub = agents.get(subName);
9477
- if (sub) result.push(sub);
9478
- });
9479
- }
9480
- return result;
9481
- },
9482
- },
9483
- tool: {
9484
- get: function (name) { return tools.get(name); },
9485
- list: function () { return Array.from(tools.values()); },
9486
- },
9487
- skill: {
9488
- get: function (name) { return skills.get(name); },
9489
- list: function () { return Array.from(skills.values()); },
9490
- },
9491
- };
9492
- }
9493
- `;
9494
- SERIALIZE_ERROR_SOURCE = `
9495
- function serializeError(err) {
9496
- if (err instanceof Error) {
9497
- var props = {};
9498
- var keys = Object.keys(err);
9499
- for (var i = 0; i < keys.length; i++) {
9500
- props[keys[i]] = err[keys[i]];
9501
- }
9502
- return { name: err.name, message: err.message, stack: err.stack, props: props };
9503
- }
9504
- return { name: 'Error', message: String(err), stack: undefined, props: {} };
9505
- }
9506
- `;
9507
- BUILD_LOGGER_SOURCE = `
9508
- var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
9509
- function createTaskLogger(level, scope, fields) {
9510
- function make(suffix) {
9511
- function write(lvl, message, callFields) {
9512
- if (level !== undefined && LOG_RANK[lvl] < LOG_RANK[level]) return;
9513
- var entry = { level: lvl, message: message, time: new Date().toISOString() };
9514
- var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
9515
- if (fullScope !== undefined) entry.scope = fullScope;
9516
- if (fields !== undefined || callFields !== undefined) {
9517
- entry.fields = Object.assign({}, fields, callFields);
9518
- }
9519
- try {
9520
- parentPort.postMessage({ type: 'log', entry: entry });
9521
- } catch (_) {
9522
- entry.fields = { warning: 'log fields not cloneable across worker boundary, dropped' };
9523
- parentPort.postMessage({ type: 'log', entry: entry });
9524
- }
9525
- }
9526
- return {
9527
- debug: function (m, f) { write('debug', m, f); },
9528
- info: function (m, f) { write('info', m, f); },
9529
- warn: function (m, f) { write('warn', m, f); },
9530
- error: function (m, f) { write('error', m, f); },
9531
- child: function (cs) { return make(suffix === undefined ? cs : suffix + ':' + cs); },
9532
- };
9533
- }
9534
- return make(undefined);
9535
- }
9536
- `;
9537
9448
  }
9538
9449
  });
9539
9450
 
@@ -9636,6 +9547,7 @@ function createTaskQueue(deps) {
9636
9547
  payload: job.payload,
9637
9548
  taskCtx: {
9638
9549
  config: deps.config,
9550
+ resourcesDir: deps.resourcesDir,
9639
9551
  job: { id: job.id, name: job.name, attempt: job.attempt }
9640
9552
  },
9641
9553
  registries: snapshotRegistries(),
@@ -9666,6 +9578,7 @@ function createTaskQueue(deps) {
9666
9578
  const taskCtx = {
9667
9579
  signal: job.signal,
9668
9580
  config: deps.config,
9581
+ resourcesDir: deps.resourcesDir,
9669
9582
  job: { id: job.id, name: job.name, attempt: job.attempt },
9670
9583
  registries: registriesView,
9671
9584
  log: createLogger(`task:${job.name}`, {
@@ -10299,8 +10212,7 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
10299
10212
  if (agents.length > 0) {
10300
10213
  console.log(`- Loaded ${agents.length} agent(s):`);
10301
10214
  for (const agent of agents) {
10302
- const exports = agent.hasRun ? "run" : "-";
10303
- console.log(` ${agent.name} [${exports}] ${agent.filePath}`);
10215
+ console.log(` ${agent.name} ${agent.filePath}`);
10304
10216
  }
10305
10217
  }
10306
10218
  if (taskMetas.length > 0) {
@@ -10312,9 +10224,15 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
10312
10224
  }
10313
10225
  }
10314
10226
  async function createAppBase(options) {
10227
+ if (getCurrentApp()) {
10228
+ throw new Error(
10229
+ "[faapi] createApp: an app is already alive in this process \u2014 faapi supports a single app per process. Close it first (`await app.close()`) or run the second app in a separate process."
10230
+ );
10231
+ }
10315
10232
  const rootDir = options?.rootDir ?? process.cwd();
10316
10233
  const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
10317
10234
  const resourcesDir = resolveResourcesDir(rootDir, dist);
10235
+ setActiveResourcesDir(resourcesDir);
10318
10236
  const routesPath = path31.resolve(rootDir, dist, ROUTES_FILE);
10319
10237
  if (!fs23.existsSync(routesPath)) {
10320
10238
  throw new Error(
@@ -10337,6 +10255,7 @@ async function createAppBase(options) {
10337
10255
  registry: registries.task,
10338
10256
  rootDir,
10339
10257
  config,
10258
+ resourcesDir,
10340
10259
  registries: createTaskRegistriesView(registries),
10341
10260
  driver: taskDriver,
10342
10261
  onFailed: config?.task?.onFailed
@@ -10378,6 +10297,7 @@ async function createAppBase(options) {
10378
10297
  config?.plugins,
10379
10298
  {
10380
10299
  rootDir,
10300
+ resourcesDir,
10381
10301
  registries,
10382
10302
  routes: sorted,
10383
10303
  getRoutes: () => sorted,
@@ -10479,6 +10399,7 @@ async function createAppBase(options) {
10479
10399
  registries.task.clear();
10480
10400
  registries.agentHandle.clear();
10481
10401
  registries.taskHandle.clear();
10402
+ setActiveResourcesDir(null);
10482
10403
  if (!server.listening) {
10483
10404
  app.server = null;
10484
10405
  if (getCurrentApp() === app) setCurrentApp(null);
@@ -10553,6 +10474,7 @@ var init_createAppCore = __esm({
10553
10474
  init_appSingleton();
10554
10475
  init_injectMock();
10555
10476
  init_copyResources();
10477
+ init_readResource();
10556
10478
  init_manifestLoader();
10557
10479
  DEFAULT_DIST = "dist";
10558
10480
  DEFAULT_PORT = 3e3;