@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/index.js CHANGED
@@ -1662,7 +1662,7 @@ var init_atomicWrite = __esm({
1662
1662
 
1663
1663
  // src/cli/generateZodArtifacts.ts
1664
1664
  import path11 from "path";
1665
- import { existsSync } from "fs";
1665
+ import { existsSync as existsSync2 } from "fs";
1666
1666
  async function generateZodArtifacts(sources, options) {
1667
1667
  const { generateFileSource, resolversByFile, rootDir, dist } = options;
1668
1668
  if (sources.length === 0) return;
@@ -1696,7 +1696,7 @@ async function generateZodArtifacts(sources, options) {
1696
1696
  const allSourceCode = fileEntries.map((e) => e.source).join("\n");
1697
1697
  if (usesCoerceHelpers(allSourceCode)) {
1698
1698
  const helpersPath = path11.resolve(rootDir, dist, HELPERS_FILENAME);
1699
- if (!existsSync(helpersPath)) {
1699
+ if (!existsSync2(helpersPath)) {
1700
1700
  await atomicWriteFile(helpersPath, generateHelpersFileSource());
1701
1701
  }
1702
1702
  }
@@ -2079,8 +2079,16 @@ var PayloadTooLargeError = class extends FaapiError {
2079
2079
  };
2080
2080
 
2081
2081
  // src/task/taskWorker.ts
2082
+ import { existsSync } from "fs";
2082
2083
  import { Worker } from "worker_threads";
2083
- import { pathToFileURL } from "url";
2084
+ import { fileURLToPath, pathToFileURL } from "url";
2085
+ var workerEntryUrl;
2086
+ function resolveWorkerEntryUrl() {
2087
+ if (workerEntryUrl) return workerEntryUrl;
2088
+ const js = new URL("./workerEntry.js", import.meta.url);
2089
+ workerEntryUrl = existsSync(fileURLToPath(js)) ? js : new URL("./workerEntry.ts", import.meta.url);
2090
+ return workerEntryUrl;
2091
+ }
2084
2092
  var KILL_GRACE_MS = 5e3;
2085
2093
  var TaskCancelledError = class extends Error {
2086
2094
  constructor(message) {
@@ -2101,153 +2109,6 @@ function safeConfig(config) {
2101
2109
  return void 0;
2102
2110
  }
2103
2111
  }
2104
- var BUILD_VIEW_SOURCE = `
2105
- function buildRegistriesView(snapshot) {
2106
- var agents = new Map(((snapshot && snapshot.agents) || []).map(function (a) { return [a.name, a]; }));
2107
- var tools = new Map(((snapshot && snapshot.tools) || []).map(function (t) { return [t.name, t]; }));
2108
- var skills = new Map(((snapshot && snapshot.skills) || []).map(function (s) { return [s.name, s]; }));
2109
- return {
2110
- agent: {
2111
- getAgent: function (name) { return agents.get(name); },
2112
- getAgentEntry: function (name) { return agents.get(name); },
2113
- listAgents: function () { return Array.from(agents.values()); },
2114
- asTool: function (name) {
2115
- var agent = agents.get(name);
2116
- if (!agent) return undefined;
2117
- return {
2118
- kind: 'agent',
2119
- name: 'agent.' + agent.name,
2120
- agentName: agent.name,
2121
- description: agent.description,
2122
- metadata: agent,
2123
- };
2124
- },
2125
- resolveAgentTools: function (name) {
2126
- var agent = agents.get(name);
2127
- var result = new Map();
2128
- if (agent && agent.tools) {
2129
- agent.tools.forEach(function (toolName) {
2130
- var resolved = tools.get(toolName);
2131
- if (resolved) result.set(resolved.name, resolved);
2132
- });
2133
- }
2134
- return Array.from(result.values());
2135
- },
2136
- resolveSubAgents: function (name) {
2137
- var agent = agents.get(name);
2138
- var result = [];
2139
- if (agent && agent.agents) {
2140
- agent.agents.forEach(function (subName) {
2141
- var sub = agents.get(subName);
2142
- if (sub) result.push(sub);
2143
- });
2144
- }
2145
- return result;
2146
- },
2147
- },
2148
- tool: {
2149
- get: function (name) { return tools.get(name); },
2150
- list: function () { return Array.from(tools.values()); },
2151
- },
2152
- skill: {
2153
- get: function (name) { return skills.get(name); },
2154
- list: function () { return Array.from(skills.values()); },
2155
- },
2156
- };
2157
- }
2158
- `;
2159
- var SERIALIZE_ERROR_SOURCE = `
2160
- function serializeError(err) {
2161
- if (err instanceof Error) {
2162
- var props = {};
2163
- var keys = Object.keys(err);
2164
- for (var i = 0; i < keys.length; i++) {
2165
- props[keys[i]] = err[keys[i]];
2166
- }
2167
- return { name: err.name, message: err.message, stack: err.stack, props: props };
2168
- }
2169
- return { name: 'Error', message: String(err), stack: undefined, props: {} };
2170
- }
2171
- `;
2172
- var BUILD_LOGGER_SOURCE = `
2173
- var LOG_RANK = { debug: 0, info: 1, warn: 2, error: 3 };
2174
- function createTaskLogger(level, scope, fields) {
2175
- function make(suffix) {
2176
- function write(lvl, message, callFields) {
2177
- if (level !== undefined && LOG_RANK[lvl] < LOG_RANK[level]) return;
2178
- var entry = { level: lvl, message: message, time: new Date().toISOString() };
2179
- var fullScope = suffix === undefined ? scope : scope === undefined ? suffix : scope + ':' + suffix;
2180
- if (fullScope !== undefined) entry.scope = fullScope;
2181
- if (fields !== undefined || callFields !== undefined) {
2182
- entry.fields = Object.assign({}, fields, callFields);
2183
- }
2184
- try {
2185
- parentPort.postMessage({ type: 'log', entry: entry });
2186
- } catch (_) {
2187
- entry.fields = { warning: 'log fields not cloneable across worker boundary, dropped' };
2188
- parentPort.postMessage({ type: 'log', entry: entry });
2189
- }
2190
- }
2191
- return {
2192
- debug: function (m, f) { write('debug', m, f); },
2193
- info: function (m, f) { write('info', m, f); },
2194
- warn: function (m, f) { write('warn', m, f); },
2195
- error: function (m, f) { write('error', m, f); },
2196
- child: function (cs) { return make(suffix === undefined ? cs : suffix + ':' + cs); },
2197
- };
2198
- }
2199
- return make(undefined);
2200
- }
2201
- `;
2202
- function buildWrapperSource(moduleUrl) {
2203
- return `
2204
- import { parentPort } from 'node:worker_threads';
2205
- import * as mod from '${moduleUrl}';
2206
-
2207
- ${BUILD_VIEW_SOURCE}
2208
-
2209
- ${SERIALIZE_ERROR_SOURCE}
2210
-
2211
- ${BUILD_LOGGER_SOURCE}
2212
-
2213
- const run = mod.run;
2214
- if (typeof run !== 'function') {
2215
- parentPort.postMessage({
2216
- type: 'error',
2217
- error: { name: 'Error', message: 'Task module has no run export', stack: undefined, props: {} },
2218
- });
2219
- } else {
2220
- let controller = null;
2221
- parentPort.on('message', async (msg) => {
2222
- if (msg?.type === 'abort') {
2223
- controller?.abort(new Error(msg.reason));
2224
- return;
2225
- }
2226
- if (msg?.type !== 'run') return;
2227
- controller = new AbortController();
2228
- const { payload, taskCtx } = msg;
2229
- try {
2230
- const registries = buildRegistriesView(msg.registries);
2231
- const progress = (value) => parentPort.postMessage({ type: 'progress', value });
2232
- const taskLog = msg.log ? createTaskLogger(msg.log.level, msg.log.scope, msg.log.fields) : undefined;
2233
- const result = await run(payload, { ...taskCtx, signal: controller.signal, registries, progress, log: taskLog });
2234
- parentPort.postMessage({ type: 'done', result });
2235
- } catch (err) {
2236
- const serialized = serializeError(err);
2237
- try {
2238
- parentPort.postMessage({ type: 'error', error: serialized });
2239
- } catch (_) {
2240
- // props \u542B\u4E0D\u53EF\u514B\u9686\u503C\uFF08\u51FD\u6570\u7B49\uFF09\u65F6\u4E22\u5F03 props\uFF0C\u4FDD\u5E95 name/message/stack
2241
- parentPort.postMessage({
2242
- type: 'error',
2243
- error: { name: serialized.name, message: serialized.message, stack: serialized.stack, props: {} },
2244
- });
2245
- }
2246
- }
2247
- });
2248
- }
2249
- `;
2250
- }
2251
2112
  function reviveError(payload) {
2252
2113
  const err = new Error(payload?.message ?? "task worker error");
2253
2114
  if (payload?.name !== void 0) err.name = payload.name;
@@ -2268,13 +2129,12 @@ async function runTaskInWorker(options) {
2268
2129
  );
2269
2130
  }
2270
2131
  const moduleUrl = pathToFileURL(taskModulePath).href;
2271
- const wrapperUrl = new URL(
2272
- `data:text/javascript,${encodeURIComponent(buildWrapperSource(moduleUrl))}`
2273
- );
2274
2132
  return new Promise((resolve, reject) => {
2275
2133
  let worker;
2276
2134
  try {
2277
- worker = new Worker(wrapperUrl);
2135
+ worker = new Worker(resolveWorkerEntryUrl(), {
2136
+ workerData: { moduleUrl, resourcesDir: taskCtx.resourcesDir }
2137
+ });
2278
2138
  } catch (err) {
2279
2139
  reject(err);
2280
2140
  return;
@@ -2362,7 +2222,11 @@ async function runTaskInWorker(options) {
2362
2222
  worker.postMessage({
2363
2223
  type: "run",
2364
2224
  payload,
2365
- taskCtx: { config: safeConfig(taskCtx.config), job: taskCtx.job },
2225
+ taskCtx: {
2226
+ config: safeConfig(taskCtx.config),
2227
+ resourcesDir: taskCtx.resourcesDir,
2228
+ job: taskCtx.job
2229
+ },
2366
2230
  registries: options.registries,
2367
2231
  log: options.log
2368
2232
  });
@@ -2712,6 +2576,7 @@ function createTaskQueue(deps) {
2712
2576
  payload: job.payload,
2713
2577
  taskCtx: {
2714
2578
  config: deps.config,
2579
+ resourcesDir: deps.resourcesDir,
2715
2580
  job: { id: job.id, name: job.name, attempt: job.attempt }
2716
2581
  },
2717
2582
  registries: snapshotRegistries(),
@@ -2742,6 +2607,7 @@ function createTaskQueue(deps) {
2742
2607
  const taskCtx = {
2743
2608
  signal: job.signal,
2744
2609
  config: deps.config,
2610
+ resourcesDir: deps.resourcesDir,
2745
2611
  job: { id: job.id, name: job.name, attempt: job.attempt },
2746
2612
  registries: registriesView,
2747
2613
  log: createLogger(`task:${job.name}`, {
@@ -2991,6 +2857,7 @@ function parseNumericLiteral(raw) {
2991
2857
  return Number(raw.replace(/_/g, ""));
2992
2858
  }
2993
2859
  var MIN_ISOLATED_TIMEOUT_MS = 6e4;
2860
+ var MAX_ISOLATED_TIMEOUT_MS = 23 * 60 * 6e4;
2994
2861
  function filePathToTaskName(filePath) {
2995
2862
  const normalized = filePath.replace(/\\/g, "/");
2996
2863
  const match = normalized.match(/(?:^|\/)tasks\/(.+)\/task\.ts$/);
@@ -3039,6 +2906,11 @@ async function scanTasks(rootDir, patterns) {
3039
2906
  `[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.`
3040
2907
  );
3041
2908
  }
2909
+ if (value > MAX_ISOLATED_TIMEOUT_MS) {
2910
+ throw new Error(
2911
+ `[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).`
2912
+ );
2913
+ }
3042
2914
  manifest.timeoutMs = value;
3043
2915
  }
3044
2916
  if (graceMs !== void 0) manifest.graceMs = parseNumericLiteral(graceMs);
@@ -3086,7 +2958,7 @@ function listSkills() {
3086
2958
  return defaultRegistries.skill.list();
3087
2959
  }
3088
2960
 
3089
- // src/loader/loadAgentModule.ts
2961
+ // src/loader/loadToolModule.ts
3090
2962
  import fs12 from "fs";
3091
2963
 
3092
2964
  // src/loader/resolveExports.ts
@@ -3737,52 +3609,13 @@ function getDevDist() {
3737
3609
  return state.distDir;
3738
3610
  }
3739
3611
 
3740
- // src/loader/loadAgentModule.ts
3741
- async function loadAgentModule(filePath, hasRun, rootDir) {
3742
- if (isDevOnDemandEnabled() && rootDir) {
3743
- const dist = getDevDist();
3744
- if (dist) {
3745
- const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
3746
- if (sourcePath && fs12.existsSync(sourcePath)) {
3747
- try {
3748
- await ensureCompiled(sourcePath, rootDir, dist);
3749
- } catch (compileErr) {
3750
- const reason = compileErr instanceof Error ? compileErr.message : String(compileErr);
3751
- throw new Error(`Failed to compile agent module "${sourcePath}": ${reason}`, {
3752
- cause: compileErr
3753
- });
3754
- }
3755
- }
3756
- }
3757
- }
3758
- let module;
3759
- try {
3760
- module = await importWithCacheBust(filePath, isDevOnDemandEnabled());
3761
- } catch (err) {
3762
- const reason = err instanceof Error ? err.message : String(err);
3763
- throw new Error(`Failed to load agent module "${filePath}": ${reason}`, { cause: err });
3764
- }
3765
- let run;
3766
- if (hasRun) {
3767
- const runExport = resolveExport(module, "run");
3768
- if (typeof runExport !== "function") {
3769
- throw new Error(
3770
- `Agent module "${filePath}" does not export a valid "run" function (hasRun=true). Expected a function, got ${runExport === void 0 ? "undefined" : typeof runExport}.`
3771
- );
3772
- }
3773
- run = runExport;
3774
- }
3775
- return { run };
3776
- }
3777
-
3778
3612
  // src/loader/loadToolModule.ts
3779
- import fs13 from "fs";
3780
3613
  async function loadToolModule(filePath, functionName, rootDir) {
3781
3614
  if (isDevOnDemandEnabled() && rootDir) {
3782
3615
  const dist = getDevDist();
3783
3616
  if (dist) {
3784
3617
  const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
3785
- if (sourcePath && fs13.existsSync(sourcePath)) {
3618
+ if (sourcePath && fs12.existsSync(sourcePath)) {
3786
3619
  try {
3787
3620
  await ensureCompiled(sourcePath, rootDir, dist);
3788
3621
  } catch (compileErr) {
@@ -3811,7 +3644,7 @@ async function loadToolModule(filePath, functionName, rootDir) {
3811
3644
  }
3812
3645
 
3813
3646
  // src/loader/loadToolSchema.ts
3814
- import { existsSync as existsSync2 } from "fs";
3647
+ import { existsSync as existsSync3 } from "fs";
3815
3648
 
3816
3649
  // src/cli/generateToolArtifacts.ts
3817
3650
  init_generateZodArtifacts();
@@ -4045,7 +3878,7 @@ async function loadToolSchema(tool, rootDir) {
4045
3878
  if (!tool.inputTypeName) return void 0;
4046
3879
  const schemaName = `${tool.inputTypeName}Schema`;
4047
3880
  const zodPath = getToolSchemaPath(tool, rootDir);
4048
- if (!existsSync2(zodPath)) return void 0;
3881
+ if (!existsSync3(zodPath)) return void 0;
4049
3882
  try {
4050
3883
  const mod = await importWithCacheBust(zodPath, isDevOnDemandEnabled());
4051
3884
  const schema = mod[`${tool.inputTypeName}Schema`];
@@ -4254,15 +4087,15 @@ function helmet(options = {}) {
4254
4087
 
4255
4088
  // src/config/loadConfig.ts
4256
4089
  import path16 from "path";
4257
- import fs14 from "fs";
4090
+ import fs13 from "fs";
4258
4091
  var CONFIG_PRODUCT_FILE = "faapi-config.js";
4259
4092
  async function loadConfig(rootDir, dist) {
4260
4093
  const configProductPath = path16.resolve(rootDir, dist, CONFIG_PRODUCT_FILE);
4261
- if (fs14.existsSync(configProductPath)) {
4094
+ if (fs13.existsSync(configProductPath)) {
4262
4095
  const module = await importWithCacheBust(configProductPath);
4263
4096
  return module.default ?? {};
4264
4097
  }
4265
- const hasSourceConfig = fs14.existsSync(path16.join(rootDir, "faapi.config.ts")) || fs14.existsSync(path16.join(rootDir, "faapi.config.js"));
4098
+ const hasSourceConfig = fs13.existsSync(path16.join(rootDir, "faapi.config.ts")) || fs13.existsSync(path16.join(rootDir, "faapi.config.js"));
4266
4099
  if (hasSourceConfig) {
4267
4100
  throw new Error(
4268
4101
  `[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`
@@ -4272,7 +4105,7 @@ async function loadConfig(rootDir, dist) {
4272
4105
  }
4273
4106
 
4274
4107
  // src/cli/loadEnv.ts
4275
- import fs15 from "fs";
4108
+ import fs14 from "fs";
4276
4109
  import path17 from "path";
4277
4110
  function resolveEnv() {
4278
4111
  return process.env.NODE_ENV || "development";
@@ -4341,8 +4174,8 @@ function loadEnv(rootDir) {
4341
4174
  const merged = {};
4342
4175
  for (const file of files) {
4343
4176
  const filePath = path17.join(rootDir, file);
4344
- if (!fs15.existsSync(filePath)) continue;
4345
- const content = fs15.readFileSync(filePath, "utf-8");
4177
+ if (!fs14.existsSync(filePath)) continue;
4178
+ const content = fs14.readFileSync(filePath, "utf-8");
4346
4179
  const parsed = parseEnvFile(content, merged);
4347
4180
  Object.assign(merged, parsed);
4348
4181
  }
@@ -4353,9 +4186,53 @@ function loadEnv(rootDir) {
4353
4186
  }
4354
4187
  }
4355
4188
 
4189
+ // src/utils/readResource.ts
4190
+ import path18 from "path";
4191
+ import fs15 from "fs/promises";
4192
+ var ACTIVE_RESOURCES_DIR_KEY = /* @__PURE__ */ Symbol.for("faapi.resources.dir");
4193
+ function getActiveResourcesDir() {
4194
+ return globalThis[ACTIVE_RESOURCES_DIR_KEY] ?? null;
4195
+ }
4196
+ function setActiveResourcesDir(dir) {
4197
+ if (dir === null) {
4198
+ delete globalThis[ACTIVE_RESOURCES_DIR_KEY];
4199
+ } else {
4200
+ globalThis[ACTIVE_RESOURCES_DIR_KEY] = dir;
4201
+ }
4202
+ }
4203
+ function resolveResourceTarget(resourcesDir, relativePath) {
4204
+ if (typeof relativePath !== "string" || relativePath === "") {
4205
+ throw new Error("[faapi] readResource: relativePath must be a non-empty string");
4206
+ }
4207
+ const root = toRealPath(path18.resolve(resourcesDir));
4208
+ const resolved = path18.resolve(root, relativePath);
4209
+ if (!isInsideDir(resolved, root)) {
4210
+ throw new Error(
4211
+ `[faapi] readResource: "${relativePath}" escapes the resources directory (absolute paths and ".." are not allowed)`
4212
+ );
4213
+ }
4214
+ const realTarget = toRealPath(resolved);
4215
+ if (!isInsideDir(realTarget, root)) {
4216
+ throw new Error(
4217
+ `[faapi] readResource: "${relativePath}" resolves outside the resources directory via a symlink`
4218
+ );
4219
+ }
4220
+ return realTarget;
4221
+ }
4222
+ async function readResource(relativePath, encoding) {
4223
+ const resourcesDir = getActiveResourcesDir();
4224
+ if (!resourcesDir) {
4225
+ throw new Error(
4226
+ "[faapi] readResource: no active app in this process \u2014 resources are bound at app startup (createAppBase); testing direct-call can pass `resourcesDir` to createTestContext to bind"
4227
+ );
4228
+ }
4229
+ const target = resolveResourceTarget(resourcesDir, relativePath);
4230
+ return encoding === void 0 ? fs15.readFile(target) : fs15.readFile(target, encoding);
4231
+ }
4232
+
4356
4233
  // src/cli/createAppCore.ts
4357
4234
  import fs22 from "fs";
4358
- import path27 from "path";
4235
+ import path28 from "path";
4359
4236
 
4360
4237
  // src/router/sortRoutes.ts
4361
4238
  function sortRoutes(routes) {
@@ -4419,7 +4296,7 @@ import {
4419
4296
  import { createSecureServer as createHttp2SecureServer } from "http2";
4420
4297
  import { readFileSync } from "fs";
4421
4298
  import { Readable as Readable2 } from "stream";
4422
- import path20 from "path";
4299
+ import path21 from "path";
4423
4300
 
4424
4301
  // src/router/matchRoute.ts
4425
4302
  var httpIndexCache = /* @__PURE__ */ new WeakMap();
@@ -5901,14 +5778,14 @@ function etag(options = {}) {
5901
5778
  // src/server/handleWsUpgrade.ts
5902
5779
  import fs17 from "fs";
5903
5780
  import { WebSocketServer, WebSocket } from "ws";
5904
- import path19 from "path";
5781
+ import path20 from "path";
5905
5782
 
5906
5783
  // src/cli/copyResources.ts
5907
- import path18 from "path";
5784
+ import path19 from "path";
5908
5785
  import fs16 from "fs";
5909
5786
  var RESOURCES_OUTPUT_DIR = "resources";
5910
5787
  function resolveResourcesDir(rootDir, dist) {
5911
- return path18.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
5788
+ return path19.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
5912
5789
  }
5913
5790
 
5914
5791
  // src/server/serverUtils.ts
@@ -6230,7 +6107,7 @@ function attachWebSocket(options) {
6230
6107
  }
6231
6108
  let handlers;
6232
6109
  try {
6233
- const absoluteFilePath = path19.resolve(rootDir, route.filePath);
6110
+ const absoluteFilePath = path20.resolve(rootDir, route.filePath);
6234
6111
  handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
6235
6112
  } catch (err) {
6236
6113
  const reason = err instanceof Error ? err.message : String(err);
@@ -6493,7 +6370,7 @@ function getRoutePaths(route, rootDir, dist) {
6493
6370
  let cached = routePathCache.get(route);
6494
6371
  if (!cached) {
6495
6372
  cached = {
6496
- absFilePath: path20.resolve(rootDir, route.filePath),
6373
+ absFilePath: path21.resolve(rootDir, route.filePath),
6497
6374
  schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
6498
6375
  };
6499
6376
  routePathCache.set(route, cached);
@@ -6714,7 +6591,7 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
6714
6591
 
6715
6592
  // src/cli/generateRoutes.ts
6716
6593
  import fs18 from "fs";
6717
- import path21 from "path";
6594
+ import path22 from "path";
6718
6595
  async function hydrateRoutes(manifest) {
6719
6596
  const hydrateRoute = (serialized) => ({
6720
6597
  method: serialized.method,
@@ -6758,18 +6635,18 @@ function createIdleTaskDriver() {
6758
6635
  }
6759
6636
 
6760
6637
  // src/cli/loadPlugins.ts
6761
- import path23 from "path";
6638
+ import path24 from "path";
6762
6639
  import fs20 from "fs";
6763
6640
  import { pathToFileURL as pathToFileURL3 } from "url";
6764
6641
 
6765
6642
  // src/cli/compileConfig.ts
6766
- import path22 from "path";
6643
+ import path23 from "path";
6767
6644
  import fs19 from "fs";
6768
6645
  async function compileProjectModules(entryPoints, rootDir, dist) {
6769
6646
  const { insideFiles, outsideFiles } = await collectRelativeImports(entryPoints, rootDir);
6770
6647
  const esbuild = await import("esbuild");
6771
6648
  const aliasPlugins = buildAliasPlugins(rootDir);
6772
- const absDist = path22.resolve(rootDir, dist);
6649
+ const absDist = path23.resolve(rootDir, dist);
6773
6650
  await esbuild.build({
6774
6651
  entryPoints: [...entryPoints, ...outsideFiles],
6775
6652
  outdir: absDist,
@@ -6783,7 +6660,7 @@ async function compileProjectModules(entryPoints, rootDir, dist) {
6783
6660
  logLevel: "silent"
6784
6661
  });
6785
6662
  if (insideFiles.length > 0) {
6786
- const appOutbase = path22.resolve(rootDir, "src");
6663
+ const appOutbase = path23.resolve(rootDir, "src");
6787
6664
  await esbuild.build({
6788
6665
  entryPoints: insideFiles,
6789
6666
  outdir: absDist,
@@ -6864,7 +6741,7 @@ async function loadPlugins(declarations, ctx, rootDir, dist) {
6864
6741
  var TS_EXTS = /\.(ts|tsx|mts|cts)$/;
6865
6742
  var JS_EXTS = /\.(js|mjs|cjs|jsx)$/;
6866
6743
  function resolveLocalPluginSource(specifier, baseDir) {
6867
- const base = path23.isAbsolute(specifier) ? specifier : path23.resolve(baseDir, specifier);
6744
+ const base = path24.isAbsolute(specifier) ? specifier : path24.resolve(baseDir, specifier);
6868
6745
  if ((TS_EXTS.test(base) || JS_EXTS.test(base)) && fs20.existsSync(base)) return base;
6869
6746
  for (const ext of [".ts", ".js"]) {
6870
6747
  if (fs20.existsSync(base + ext)) return base + ext;
@@ -6875,16 +6752,16 @@ function resolveLocalPluginSource(specifier, baseDir) {
6875
6752
  return null;
6876
6753
  }
6877
6754
  function mirrorProductPath(sourcePath, baseDir, distDir) {
6878
- let rel = path23.relative(baseDir, sourcePath).replace(/\\/g, "/");
6755
+ let rel = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
6879
6756
  if (rel.startsWith("src/")) rel = rel.slice(4);
6880
- return path23.resolve(distDir, rel.replace(TS_EXTS, ".js"));
6757
+ return path24.resolve(distDir, rel.replace(TS_EXTS, ".js"));
6881
6758
  }
6882
6759
  async function importPluginModule(specifier, baseDir, dist) {
6883
6760
  const isRelative = specifier.startsWith("./") || specifier.startsWith("../");
6884
- if (!isRelative && !path23.isAbsolute(specifier)) {
6761
+ if (!isRelative && !path24.isAbsolute(specifier)) {
6885
6762
  return import(specifier);
6886
6763
  }
6887
- const distDir = dist ? path23.resolve(baseDir, dist) : null;
6764
+ const distDir = dist ? path24.resolve(baseDir, dist) : null;
6888
6765
  const sourcePath = resolveLocalPluginSource(specifier, baseDir);
6889
6766
  const productPath = sourcePath && distDir ? mirrorProductPath(sourcePath, baseDir, distDir) : null;
6890
6767
  if (productPath !== null && fs20.existsSync(productPath) && (sourcePath === null || isProductFresh(sourcePath, productPath))) {
@@ -6896,7 +6773,7 @@ async function importPluginModule(specifier, baseDir, dist) {
6896
6773
  `Local plugin "${specifier}" has no up-to-date build artifact (dist is stale or missing). Run "faapi build" first, or use "faapi dev" for on-demand compilation.`
6897
6774
  );
6898
6775
  }
6899
- const relFromRoot = path23.relative(baseDir, sourcePath).replace(/\\/g, "/");
6776
+ const relFromRoot = path24.relative(baseDir, sourcePath).replace(/\\/g, "/");
6900
6777
  if (relFromRoot.startsWith("src/")) {
6901
6778
  await ensureCompiled(sourcePath, baseDir, dist);
6902
6779
  } else {
@@ -6914,7 +6791,7 @@ async function importPluginModule(specifier, baseDir, dist) {
6914
6791
  `${specifier}/index.ts`,
6915
6792
  `${specifier}.js`,
6916
6793
  `${specifier}/index.js`
6917
- ].map((c) => path23.isAbsolute(c) ? c : path23.join(baseDir, c));
6794
+ ].map((c) => path24.isAbsolute(c) ? c : path24.join(baseDir, c));
6918
6795
  throw new Error(
6919
6796
  `Cannot find local plugin "${specifier}" (resolved from ${baseDir}). Expected one of:
6920
6797
  ${candidates.join("\n ")}
@@ -6940,10 +6817,10 @@ function resolveDeclaration(decl) {
6940
6817
 
6941
6818
  // src/cli/manifestLoader.ts
6942
6819
  import fs21 from "fs";
6943
- import path26 from "path";
6820
+ import path27 from "path";
6944
6821
 
6945
6822
  // src/cli/generateAgentArtifacts.ts
6946
- import path24 from "path";
6823
+ import path25 from "path";
6947
6824
 
6948
6825
  // src/ast/extractAgentMetadata.ts
6949
6826
  import ts11 from "typescript";
@@ -6951,12 +6828,21 @@ init_resolveTypeNode();
6951
6828
  function extractAgentMetadata(program, filePath, pathMeta) {
6952
6829
  const sourceFile = program.getSourceFile(filePath);
6953
6830
  if (!sourceFile) return null;
6831
+ const runOwner = findRunExportOwner(sourceFile);
6832
+ if (runOwner) {
6833
+ throw SchemaExtractionError.at(
6834
+ runOwner,
6835
+ "run",
6836
+ "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",
6837
+ sourceFile
6838
+ );
6839
+ }
6954
6840
  const configFound = findConfigExport(sourceFile);
6955
6841
  if (!configFound) {
6956
6842
  throw SchemaExtractionError.at(
6957
6843
  sourceFile,
6958
6844
  "config.systemPrompt",
6959
- "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",
6845
+ "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",
6960
6846
  sourceFile
6961
6847
  );
6962
6848
  }
@@ -6972,16 +6858,13 @@ function extractAgentMetadata(program, filePath, pathMeta) {
6972
6858
  const jsDoc = getJSDocFromNode(configFound.jsDocOwner);
6973
6859
  const description = extractDescription(jsDoc);
6974
6860
  const agentNameOverride = extractJSDocTagValue(jsDoc, "agent");
6975
- const { systemPrompt, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(
6976
- objectLiteral,
6977
- sourceFile
6978
- );
6861
+ const { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription } = extractConfigFields(objectLiteral, sourceFile);
6979
6862
  return {
6980
6863
  name: agentNameOverride ?? pathMeta.name,
6981
6864
  description,
6982
6865
  filePath: pathMeta.filePath,
6983
- hasRun: pathMeta.hasRun,
6984
6866
  systemPrompt,
6867
+ systemPromptFile,
6985
6868
  tools,
6986
6869
  agents,
6987
6870
  model,
@@ -6989,6 +6872,25 @@ function extractAgentMetadata(program, filePath, pathMeta) {
6989
6872
  inputDescription
6990
6873
  };
6991
6874
  }
6875
+ function findRunExportOwner(sourceFile) {
6876
+ let result = null;
6877
+ ts11.forEachChild(sourceFile, (node) => {
6878
+ if (result) return;
6879
+ if (ts11.isFunctionDeclaration(node) && hasExportModifier(node) && node.name?.text === "run") {
6880
+ result = node;
6881
+ return;
6882
+ }
6883
+ if (ts11.isVariableStatement(node) && hasExportModifier(node)) {
6884
+ for (const decl of node.declarationList.declarations) {
6885
+ if (ts11.isIdentifier(decl.name) && decl.name.text === "run") {
6886
+ result = node;
6887
+ return;
6888
+ }
6889
+ }
6890
+ }
6891
+ });
6892
+ return result;
6893
+ }
6992
6894
  function findConfigExport(sourceFile) {
6993
6895
  let result = null;
6994
6896
  ts11.forEachChild(sourceFile, (node) => {
@@ -7031,6 +6933,7 @@ function getReturnObjectLiteral(fn) {
7031
6933
  }
7032
6934
  function extractConfigFields(objLit, sourceFile) {
7033
6935
  let systemPrompt;
6936
+ let systemPromptFile;
7034
6937
  let tools;
7035
6938
  let agents;
7036
6939
  let model;
@@ -7054,6 +6957,9 @@ function extractConfigFields(objLit, sourceFile) {
7054
6957
  case "systemPrompt":
7055
6958
  systemPrompt = requireStringValue(prop, "systemPrompt", sourceFile);
7056
6959
  break;
6960
+ case "systemPromptFile":
6961
+ systemPromptFile = requireStringValue(prop, "systemPromptFile", sourceFile);
6962
+ break;
7057
6963
  case "tools":
7058
6964
  tools = requireStringArrayValue(prop, "tools", sourceFile);
7059
6965
  break;
@@ -7073,20 +6979,28 @@ function extractConfigFields(objLit, sourceFile) {
7073
6979
  throw SchemaExtractionError.at(
7074
6980
  prop,
7075
6981
  `config.${propName}`,
7076
- "\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / tools / agents / model / maxTurns / inputDescription",
6982
+ "\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / systemPromptFile / tools / agents / model / maxTurns / inputDescription",
7077
6983
  sourceFile
7078
6984
  );
7079
6985
  }
7080
6986
  }
7081
- if (systemPrompt === void 0) {
6987
+ if (systemPrompt !== void 0 && systemPromptFile !== void 0) {
7082
6988
  throw SchemaExtractionError.at(
7083
6989
  objLit,
7084
6990
  "config.systemPrompt",
7085
- "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",
6991
+ "systemPrompt \u4E0E systemPromptFile \u4E92\u65A5\u2014\u2014\u5185\u8054\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E0E resources \u6587\u4EF6\u4E8C\u9009\u4E00",
7086
6992
  sourceFile
7087
6993
  );
7088
6994
  }
7089
- return { systemPrompt, tools, agents, model, maxTurns, inputDescription };
6995
+ if (systemPrompt === void 0 && systemPromptFile === void 0) {
6996
+ throw SchemaExtractionError.at(
6997
+ objLit,
6998
+ "config.systemPrompt",
6999
+ "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",
7000
+ sourceFile
7001
+ );
7002
+ }
7003
+ return { systemPrompt, systemPromptFile, tools, agents, model, maxTurns, inputDescription };
7090
7004
  }
7091
7005
  function getPropertyName(name) {
7092
7006
  if (ts11.isIdentifier(name)) return name.text;
@@ -7169,8 +7083,8 @@ function serializeAgents(agents, dist = "dist") {
7169
7083
  return agents.map((a) => ({
7170
7084
  name: a.name,
7171
7085
  description: a.description,
7172
- hasRun: a.hasRun,
7173
7086
  systemPrompt: a.systemPrompt,
7087
+ systemPromptFile: a.systemPromptFile,
7174
7088
  tools: a.tools,
7175
7089
  agents: a.agents,
7176
7090
  model: a.model,
@@ -7190,8 +7104,8 @@ function hydrateAgents(manifest) {
7190
7104
  name: a.name,
7191
7105
  description: a.description ?? void 0,
7192
7106
  filePath: a.filePath,
7193
- hasRun: a.hasRun,
7194
7107
  systemPrompt: a.systemPrompt ?? void 0,
7108
+ systemPromptFile: a.systemPromptFile ?? void 0,
7195
7109
  tools: a.tools ?? void 0,
7196
7110
  agents: a.agents ?? void 0,
7197
7111
  model: a.model ?? void 0,
@@ -7223,14 +7137,13 @@ function validateAgentList(metadata) {
7223
7137
  }
7224
7138
  async function generateAgentArtifacts(agents, rootDir, dist) {
7225
7139
  const metadata = [];
7226
- const programByFile = createPrograms(agents.map((m) => path24.resolve(rootDir, m.filePath)));
7140
+ const programByFile = createPrograms(agents.map((m) => path25.resolve(rootDir, m.filePath)));
7227
7141
  for (const manifest of agents) {
7228
- const absPath = path24.resolve(rootDir, manifest.filePath);
7142
+ const absPath = path25.resolve(rootDir, manifest.filePath);
7229
7143
  const program = programByFile.get(absPath);
7230
7144
  const result = extractAgentMetadata(program, absPath, {
7231
7145
  name: manifest.name,
7232
- filePath: manifest.filePath,
7233
- hasRun: manifest.hasRun
7146
+ filePath: manifest.filePath
7234
7147
  });
7235
7148
  if (!result) {
7236
7149
  throw new Error(
@@ -7241,14 +7154,14 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
7241
7154
  }
7242
7155
  validateAgentList(metadata);
7243
7156
  const serialized = serializeAgents(metadata, dist);
7244
- const agentsPath = path24.resolve(rootDir, dist, AGENTS_FILE);
7157
+ const agentsPath = path25.resolve(rootDir, dist, AGENTS_FILE);
7245
7158
  await writeAgentsModule(serialized, agentsPath);
7246
7159
  return metadata;
7247
7160
  }
7248
7161
 
7249
7162
  // src/cli/generateTaskArtifacts.ts
7250
7163
  init_generateZodArtifacts();
7251
- import path25 from "path";
7164
+ import path26 from "path";
7252
7165
  init_createProgram();
7253
7166
  init_atomicWrite();
7254
7167
  init_extractHandlerTypes();
@@ -7286,7 +7199,7 @@ function collectTaskSchemaSources(tasks, rootDir) {
7286
7199
  const tasksByFile = /* @__PURE__ */ new Map();
7287
7200
  for (const task of tasks) {
7288
7201
  if (!task.inputTypeName) continue;
7289
- const absPath = path25.resolve(rootDir, task.filePath);
7202
+ const absPath = path26.resolve(rootDir, task.filePath);
7290
7203
  let list = tasksByFile.get(absPath);
7291
7204
  if (!list) {
7292
7205
  list = [];
@@ -7343,9 +7256,9 @@ function generateTaskSchemaFileSource(sources, resolveType, helpersImportPath) {
7343
7256
  async function generateTaskArtifacts(manifests, rootDir, dist) {
7344
7257
  const metadata = [];
7345
7258
  if (manifests.length > 0) {
7346
- const programByFile = createPrograms(manifests.map((m) => path25.resolve(rootDir, m.filePath)));
7259
+ const programByFile = createPrograms(manifests.map((m) => path26.resolve(rootDir, m.filePath)));
7347
7260
  for (const manifest of manifests) {
7348
- const absPath = path25.resolve(rootDir, manifest.filePath);
7261
+ const absPath = path26.resolve(rootDir, manifest.filePath);
7349
7262
  const result = extractToolMetadata(programByFile.get(absPath), absPath, "run", {
7350
7263
  name: manifest.name,
7351
7264
  filePath: manifest.filePath
@@ -7356,7 +7269,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
7356
7269
  }
7357
7270
  }
7358
7271
  const serialized = serializeTasks(manifests, dist);
7359
- const tasksPath = path25.resolve(rootDir, dist, TASKS_FILE);
7272
+ const tasksPath = path26.resolve(rootDir, dist, TASKS_FILE);
7360
7273
  await writeTasksModule(serialized, tasksPath);
7361
7274
  if (metadata.length === 0) {
7362
7275
  return hydrateTasks(serialized);
@@ -7378,7 +7291,7 @@ async function generateTaskArtifacts(manifests, rootDir, dist) {
7378
7291
  var TOOLS_FILE2 = "faapi-tools.js";
7379
7292
  var AGENTS_FILE2 = "faapi-agents.js";
7380
7293
  async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries) {
7381
- const toolsPath = path26.resolve(rootDir, dist, TOOLS_FILE2);
7294
+ const toolsPath = path27.resolve(rootDir, dist, TOOLS_FILE2);
7382
7295
  if (!fs21.existsSync(toolsPath)) {
7383
7296
  return [];
7384
7297
  }
@@ -7388,7 +7301,7 @@ async function loadAndHydrateTools(rootDir, dist, registries = defaultRegistries
7388
7301
  return hydrated;
7389
7302
  }
7390
7303
  async function loadAndHydrateAgents(rootDir, dist, registries = defaultRegistries) {
7391
- const agentsPath = path26.resolve(rootDir, dist, AGENTS_FILE2);
7304
+ const agentsPath = path27.resolve(rootDir, dist, AGENTS_FILE2);
7392
7305
  if (!fs21.existsSync(agentsPath)) {
7393
7306
  return [];
7394
7307
  }
@@ -7404,7 +7317,7 @@ function getTaskDriverOptions(config) {
7404
7317
  return void 0;
7405
7318
  }
7406
7319
  async function loadAndHydrateTasks(rootDir, dist, registries = defaultRegistries) {
7407
- const tasksPath = path26.resolve(rootDir, dist, TASKS_FILE);
7320
+ const tasksPath = path27.resolve(rootDir, dist, TASKS_FILE);
7408
7321
  if (!fs21.existsSync(tasksPath)) {
7409
7322
  return [];
7410
7323
  }
@@ -7582,8 +7495,7 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
7582
7495
  if (agents.length > 0) {
7583
7496
  console.log(`- Loaded ${agents.length} agent(s):`);
7584
7497
  for (const agent of agents) {
7585
- const exports = agent.hasRun ? "run" : "-";
7586
- console.log(` ${agent.name} [${exports}] ${agent.filePath}`);
7498
+ console.log(` ${agent.name} ${agent.filePath}`);
7587
7499
  }
7588
7500
  }
7589
7501
  if (taskMetas.length > 0) {
@@ -7595,10 +7507,16 @@ function logStartupSummary(routes, wsRoutes, tools, agents, taskMetas, p) {
7595
7507
  }
7596
7508
  }
7597
7509
  async function createAppBase(options) {
7510
+ if (getCurrentApp()) {
7511
+ throw new Error(
7512
+ "[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."
7513
+ );
7514
+ }
7598
7515
  const rootDir = options?.rootDir ?? process.cwd();
7599
7516
  const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
7600
7517
  const resourcesDir = resolveResourcesDir(rootDir, dist);
7601
- const routesPath = path27.resolve(rootDir, dist, ROUTES_FILE);
7518
+ setActiveResourcesDir(resourcesDir);
7519
+ const routesPath = path28.resolve(rootDir, dist, ROUTES_FILE);
7602
7520
  if (!fs22.existsSync(routesPath)) {
7603
7521
  throw new Error(
7604
7522
  `[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
@@ -7620,6 +7538,7 @@ async function createAppBase(options) {
7620
7538
  registry: registries.task,
7621
7539
  rootDir,
7622
7540
  config,
7541
+ resourcesDir,
7623
7542
  registries: createTaskRegistriesView(registries),
7624
7543
  driver: taskDriver,
7625
7544
  onFailed: config?.task?.onFailed
@@ -7661,6 +7580,7 @@ async function createAppBase(options) {
7661
7580
  config?.plugins,
7662
7581
  {
7663
7582
  rootDir,
7583
+ resourcesDir,
7664
7584
  registries,
7665
7585
  routes: sorted,
7666
7586
  getRoutes: () => sorted,
@@ -7762,6 +7682,7 @@ async function createAppBase(options) {
7762
7682
  registries.task.clear();
7763
7683
  registries.agentHandle.clear();
7764
7684
  registries.taskHandle.clear();
7685
+ setActiveResourcesDir(null);
7765
7686
  if (!server.listening) {
7766
7687
  app.server = null;
7767
7688
  if (getCurrentApp() === app) setCurrentApp(null);
@@ -7819,7 +7740,7 @@ import path31 from "path";
7819
7740
 
7820
7741
  // src/router/scanRoutes.ts
7821
7742
  import fg3 from "fast-glob";
7822
- import path28 from "path";
7743
+ import path29 from "path";
7823
7744
  import fs23 from "fs";
7824
7745
 
7825
7746
  // src/router/constants.ts
@@ -7890,26 +7811,26 @@ function extractExportsFromSource(source) {
7890
7811
  return names;
7891
7812
  }
7892
7813
  function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
7893
- const routeDir = path28.dirname(routeFilePath);
7894
- const resolvedRoot = path28.resolve(rootDir);
7814
+ const routeDir = path29.dirname(routeFilePath);
7815
+ const resolvedRoot = path29.resolve(rootDir);
7895
7816
  const paths = [];
7896
- let currentDir = path28.resolve(rootDir, routeDir);
7817
+ let currentDir = path29.resolve(rootDir, routeDir);
7897
7818
  while (true) {
7898
7819
  if (dist) {
7899
- const mwTsPath = path28.join(currentDir, "middlewares.ts");
7900
- const mwJsPath = path28.join(currentDir, "middlewares.js");
7901
- const absTsPath = path28.resolve(rootDir, mwTsPath);
7902
- const absJsPath = path28.resolve(rootDir, mwJsPath);
7820
+ const mwTsPath = path29.join(currentDir, "middlewares.ts");
7821
+ const mwJsPath = path29.join(currentDir, "middlewares.js");
7822
+ const absTsPath = path29.resolve(rootDir, mwTsPath);
7823
+ const absJsPath = path29.resolve(rootDir, mwJsPath);
7903
7824
  const absMwPath = fs23.existsSync(absTsPath) ? absTsPath : fs23.existsSync(absJsPath) ? absJsPath : null;
7904
7825
  if (absMwPath) {
7905
- const relMwPath = path28.relative(rootDir, absMwPath);
7906
- const prodAbsPath = path28.resolve(rootDir, toProdFilePath(relMwPath, dist));
7826
+ const relMwPath = path29.relative(rootDir, absMwPath);
7827
+ const prodAbsPath = path29.resolve(rootDir, toProdFilePath(relMwPath, dist));
7907
7828
  paths.push(prodAbsPath);
7908
7829
  }
7909
7830
  } else {
7910
7831
  for (const ext of [".ts", ".js"]) {
7911
- const mwPath = path28.join(currentDir, `middlewares${ext}`);
7912
- const absMwPath = path28.resolve(rootDir, mwPath);
7832
+ const mwPath = path29.join(currentDir, `middlewares${ext}`);
7833
+ const absMwPath = path29.resolve(rootDir, mwPath);
7913
7834
  if (fs23.existsSync(absMwPath)) {
7914
7835
  paths.push(absMwPath);
7915
7836
  break;
@@ -7917,7 +7838,7 @@ function collectMiddlewarePaths(routeFilePath, rootDir, dist) {
7917
7838
  }
7918
7839
  }
7919
7840
  if (currentDir === resolvedRoot) break;
7920
- const parentDir = path28.dirname(currentDir);
7841
+ const parentDir = path29.dirname(currentDir);
7921
7842
  if (parentDir === currentDir) break;
7922
7843
  currentDir = parentDir;
7923
7844
  }
@@ -7936,7 +7857,7 @@ async function scanRoutes(rootDir, patterns, dist) {
7936
7857
  const normalizedFile = file.replace(/\\/g, "/");
7937
7858
  const fileName = normalizedFile.split("/").pop();
7938
7859
  if (fileName === "handler.ts" || fileName === "handler.js") {
7939
- const absPath = path28.resolve(rootDir, normalizedFile);
7860
+ const absPath = path29.resolve(rootDir, normalizedFile);
7940
7861
  const urlPath = filePathToUrlPath(normalizedFile);
7941
7862
  const paramNames = extractParamNames(urlPath);
7942
7863
  const isDynamic = paramNames.length > 0;
@@ -7985,7 +7906,7 @@ async function scanRoutes(rootDir, patterns, dist) {
7985
7906
 
7986
7907
  // src/tools/scanTools.ts
7987
7908
  import fg4 from "fast-glob";
7988
- import path29 from "path";
7909
+ import path30 from "path";
7989
7910
  import fs24 from "fs";
7990
7911
  var TOOL_PATTERNS = ["src/tools/**/*.ts"];
7991
7912
  var TOOL_EXPORT_RE = new RegExp(
@@ -8036,7 +7957,7 @@ async function scanTools(rootDir, patterns) {
8036
7957
  if (fileName !== "handler.ts" && fileName !== "handler.js") {
8037
7958
  continue;
8038
7959
  }
8039
- const absPath = path29.resolve(rootDir, normalizedFile);
7960
+ const absPath = path30.resolve(rootDir, normalizedFile);
8040
7961
  const source = await fs24.promises.readFile(absPath, "utf8").catch(() => "");
8041
7962
  const exportNames = extractToolExportsFromSource(source);
8042
7963
  const namespace = filePathToToolNamespace(normalizedFile);
@@ -8061,10 +7982,7 @@ async function scanTools(rootDir, patterns) {
8061
7982
 
8062
7983
  // src/agents/scanAgents.ts
8063
7984
  import fg5 from "fast-glob";
8064
- import path30 from "path";
8065
- import fs25 from "fs";
8066
7985
  var DEFAULT_AGENT_PATTERNS = ["src/agents/**/handler.ts"];
8067
- var RUN_EXPORT_RE = /export\s+(?:async\s+)?(?:function\s+|const\s+)run\b/;
8068
7986
  function extractAgentNameFromPath(filePath) {
8069
7987
  const normalized = filePath.replace(/\\/g, "/");
8070
7988
  const match = normalized.match(/(?:^|\/)agents\/(.+)\/handler\.ts$/);
@@ -8075,11 +7993,6 @@ function extractAgentNameFromPath(filePath) {
8075
7993
  }
8076
7994
  return match[1].replace(/\//g, ".");
8077
7995
  }
8078
- function detectAgentExports(source) {
8079
- return {
8080
- hasRun: RUN_EXPORT_RE.test(source)
8081
- };
8082
- }
8083
7996
  async function scanAgents(rootDir, patterns) {
8084
7997
  const files = await fg5(patterns, {
8085
7998
  cwd: rootDir,
@@ -8094,9 +8007,6 @@ async function scanAgents(rootDir, patterns) {
8094
8007
  if (fileName !== "handler.ts" && fileName !== "handler.js") {
8095
8008
  continue;
8096
8009
  }
8097
- const absPath = path30.resolve(rootDir, normalizedFile);
8098
- const source = await fs25.promises.readFile(absPath, "utf8").catch(() => "");
8099
- const { hasRun } = detectAgentExports(source);
8100
8010
  const name = extractAgentNameFromPath(normalizedFile);
8101
8011
  const prevFile = seen.get(name);
8102
8012
  if (prevFile) {
@@ -8107,8 +8017,7 @@ async function scanAgents(rootDir, patterns) {
8107
8017
  seen.set(name, normalizedFile);
8108
8018
  agents.push({
8109
8019
  name,
8110
- filePath: normalizedFile,
8111
- hasRun
8020
+ filePath: normalizedFile
8112
8021
  });
8113
8022
  }
8114
8023
  return agents;
@@ -8232,13 +8141,13 @@ export {
8232
8141
  hydrateSkillRegistry,
8233
8142
  invalidateProgramCache,
8234
8143
  listSkills,
8235
- loadAgentModule,
8236
8144
  loadConfig,
8237
8145
  loadEnv,
8238
8146
  loadTaskDriver,
8239
8147
  loadToolModule,
8240
8148
  loadToolSchema,
8241
8149
  logger,
8150
+ readResource,
8242
8151
  registerAgentHandleFactory,
8243
8152
  removeSkill,
8244
8153
  resolveAgentTools,