perstack 0.0.87 → 0.0.88

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/bin/cli.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { createApiClient } from '../chunk-XIREKYBD.js';
3
- import { lazySchema, zodSchema, createJsonErrorResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, loadOptionalSetting, loadSetting, withoutTrailingSlash, InvalidArgumentError, collectToolDefinitionsForExpert, normalizeHeaders, withUserAgentSuffix, getRuntimeEnvironmentUserAgent, combineHeaders, generateId, getSkillManagersFromLockfile, getSkillManagers, parseProviderOptions, resolve, postJsonToApi, createJsonResponseHandler, createToolNameMapping, createEventSourceResponseHandler, APICallError, loadApiKey, InvalidResponseDataError, isParsableJson, asSchema, UnsupportedFunctionalityError, convertToBase64, extractResponseHeaders, EmptyResponseBodyError, validateTypes, isNonNullable, closeSkillManagers, generateText, streamText, getSkillManagerByToolName, getToolSet, dedent, safeParseJSON, safeValidateTypes, NoSuchModelError, TooManyEmbeddingValuesForCallError, postFormDataToApi, convertToFormData, convertBase64ToUint8Array, downloadBlob, mediaTypeToExtension, createBinaryResponseHandler, convertUint8ArrayToBase64, InvalidPromptError, AISDKError, delay, getFromApi } from '../chunk-DNXNGNCU.js';
4
- import { external_exports, parseWithFriendlyError, startCommandInputSchema, defaultMaxRetries, defaultTimeout, createId, runCommandInputSchema, validateEventFilter, createFilteredEventListener, checkpointSchema, lockfileSchema, runParamsSchema, jobSchema, defaultPerstackApiBaseUrl, createRuntimeEvent, runSettingSchema, perstackConfigSchema, expertSchema, knownModels, stopRunByExceededMaxSteps, continueToNextStep, stopRunByError, retry, createStreamingEvent, completeRun, finishToolCall, resolveToolResults, stopRunByInteractiveTool, skipDelegates, stopRunByDelegate, attemptCompletion, finishMcpTools, callTools, proceedToInteractiveTools, startGeneration, startRun, resumeFromStop, BASE_SKILL_PREFIX, createBaseToolActivity, createGeneralToolActivity } from '../chunk-VW27FULX.js';
2
+ import { createApiClient } from '../chunk-HNOP6GUQ.js';
3
+ import { lazySchema, zodSchema, createJsonErrorResponseHandler, createProviderToolFactory, createProviderToolFactoryWithOutputSchema, loadOptionalSetting, loadSetting, withoutTrailingSlash, InvalidArgumentError, collectToolDefinitionsForExpert, normalizeHeaders, withUserAgentSuffix, getRuntimeEnvironmentUserAgent, combineHeaders, generateId, getSkillManagersFromLockfile, getSkillManagers, parseProviderOptions, resolve, postJsonToApi, createJsonResponseHandler, createToolNameMapping, createEventSourceResponseHandler, APICallError, loadApiKey, InvalidResponseDataError, isParsableJson, asSchema, UnsupportedFunctionalityError, convertToBase64, extractResponseHeaders, EmptyResponseBodyError, validateTypes, isNonNullable, closeSkillManagers, generateText, streamText, getSkillManagerByToolName, getToolSet, dedent, safeParseJSON, safeValidateTypes, NoSuchModelError, TooManyEmbeddingValuesForCallError, postFormDataToApi, convertToFormData, convertBase64ToUint8Array, downloadBlob, mediaTypeToExtension, createBinaryResponseHandler, convertUint8ArrayToBase64, InvalidPromptError, AISDKError, delay, getFromApi } from '../chunk-MCZYLWXM.js';
4
+ import { external_exports, parseWithFriendlyError, startCommandInputSchema, defaultMaxRetries, defaultTimeout, createId, runCommandInputSchema, validateEventFilter, createFilteredEventListener, lockfileSchema, checkpointSchema, runParamsSchema, jobSchema, perstackConfigSchema, defaultPerstackApiBaseUrl, createRuntimeEvent, runSettingSchema, expertSchema, knownModels, stopRunByExceededMaxSteps, continueToNextStep, stopRunByError, retry, createStreamingEvent, completeRun, finishToolCall, resolveToolResults, stopRunByInteractiveTool, skipDelegates, stopRunByDelegate, attemptCompletion, finishMcpTools, callTools, proceedToInteractiveTools, startGeneration, startRun, resumeFromStop, BASE_SKILL_PREFIX, createBaseToolActivity, createGeneralToolActivity } from '../chunk-FVVK5V2C.js';
5
5
  import '../chunk-XX73NEQ4.js';
6
6
  import { __commonJS, __require, __toESM } from '../chunk-E5EEIGMK.js';
7
7
  import { writeFile, readFile, mkdir } from 'fs/promises';
8
- import path2 from 'path';
9
- import { existsSync, readFileSync, mkdirSync, writeFileSync, readdirSync, statSync } from 'fs';
8
+ import path from 'path';
9
+ import { readFileSync, existsSync, mkdirSync, writeFileSync, readdirSync, statSync } from 'fs';
10
10
  import { Buffer as Buffer$1 } from 'buffer';
11
11
  import dotenv from 'dotenv';
12
12
  import { render, useApp, useInput, Box, Text } from 'ink';
@@ -34152,243 +34152,6 @@ ${captureLines}` : capture.stack;
34152
34152
  }
34153
34153
  });
34154
34154
 
34155
- // ../../packages/installer/src/expert-resolver.ts
34156
- function toRuntimeExpert(key, expert) {
34157
- const skills = Object.fromEntries(
34158
- Object.entries(expert.skills ?? {}).map(([name, skill]) => {
34159
- switch (skill.type) {
34160
- case "mcpStdioSkill":
34161
- return [
34162
- name,
34163
- {
34164
- type: skill.type,
34165
- name,
34166
- description: skill.description,
34167
- rule: skill.rule,
34168
- pick: skill.pick ?? [],
34169
- omit: skill.omit ?? [],
34170
- command: skill.command,
34171
- packageName: skill.packageName,
34172
- requiredEnv: skill.requiredEnv ?? [],
34173
- lazyInit: false
34174
- }
34175
- ];
34176
- case "mcpSseSkill":
34177
- return [
34178
- name,
34179
- {
34180
- type: skill.type,
34181
- name,
34182
- description: skill.description,
34183
- rule: skill.rule,
34184
- pick: skill.pick ?? [],
34185
- omit: skill.omit ?? [],
34186
- endpoint: skill.endpoint,
34187
- lazyInit: false
34188
- }
34189
- ];
34190
- case "interactiveSkill":
34191
- return [
34192
- name,
34193
- {
34194
- type: skill.type,
34195
- name,
34196
- description: skill.description,
34197
- rule: skill.rule,
34198
- tools: Object.fromEntries(
34199
- Object.entries(skill.tools).map(([toolName, tool]) => [
34200
- toolName,
34201
- {
34202
- name: toolName,
34203
- description: tool.description,
34204
- inputSchema: JSON.parse(tool.inputJsonSchema)
34205
- }
34206
- ])
34207
- )
34208
- }
34209
- ];
34210
- default: {
34211
- throw new Error(`Unknown skill type: ${skill.type}`);
34212
- }
34213
- }
34214
- })
34215
- );
34216
- return {
34217
- key,
34218
- name: expert.name,
34219
- version: expert.version,
34220
- minRuntimeVersion: expert.minRuntimeVersion ?? "v1.0",
34221
- description: expert.description ?? "",
34222
- instruction: expert.instruction,
34223
- skills,
34224
- delegates: expert.delegates ?? [],
34225
- tags: expert.tags ?? []
34226
- };
34227
- }
34228
- function configExpertToExpert(key, configExpert) {
34229
- return expertSchema.parse({
34230
- key,
34231
- name: key,
34232
- version: configExpert.version ?? "1.0.0",
34233
- description: configExpert.description,
34234
- instruction: configExpert.instruction,
34235
- skills: configExpert.skills,
34236
- delegates: configExpert.delegates,
34237
- tags: configExpert.tags,
34238
- providerTools: configExpert.providerTools,
34239
- providerSkills: configExpert.providerSkills,
34240
- providerToolOptions: configExpert.providerToolOptions
34241
- });
34242
- }
34243
- async function resolveAllExperts(config, env) {
34244
- const experts = {};
34245
- for (const [key, configExpert] of Object.entries(config.experts ?? {})) {
34246
- experts[key] = configExpertToExpert(key, configExpert);
34247
- }
34248
- const toResolve = /* @__PURE__ */ new Set();
34249
- for (const expert of Object.values(experts)) {
34250
- for (const delegateKey of expert.delegates) {
34251
- if (!experts[delegateKey]) {
34252
- toResolve.add(delegateKey);
34253
- }
34254
- }
34255
- }
34256
- if (toResolve.size === 0) {
34257
- return experts;
34258
- }
34259
- const apiKey = env.PERSTACK_API_KEY;
34260
- if (!apiKey) {
34261
- throw new Error("PERSTACK_API_KEY is required to resolve remote delegates");
34262
- }
34263
- const client = createApiClient({
34264
- baseUrl: config.perstackApiBaseUrl ?? defaultPerstackApiBaseUrl,
34265
- apiKey
34266
- });
34267
- while (toResolve.size > 0) {
34268
- const delegateKey = toResolve.values().next().value;
34269
- if (!delegateKey) break;
34270
- toResolve.delete(delegateKey);
34271
- if (experts[delegateKey]) continue;
34272
- const result = await client.experts.get(delegateKey);
34273
- if (!result.ok) {
34274
- throw new Error(`Failed to resolve delegate "${delegateKey}": ${result.error.message}`);
34275
- }
34276
- const publishedExpert = result.data.data.definition.experts[delegateKey];
34277
- if (!publishedExpert) {
34278
- throw new Error(`Expert "${delegateKey}" not found in API response`);
34279
- }
34280
- experts[delegateKey] = toRuntimeExpert(delegateKey, publishedExpert);
34281
- for (const nestedDelegate of publishedExpert.delegates ?? []) {
34282
- if (!experts[nestedDelegate]) {
34283
- toResolve.add(nestedDelegate);
34284
- }
34285
- }
34286
- }
34287
- return experts;
34288
- }
34289
-
34290
- // ../runtime/package.json
34291
- var package_default = {
34292
- version: "0.0.95"};
34293
-
34294
- // ../runtime/src/helpers/usage.ts
34295
- function createEmptyUsage() {
34296
- return {
34297
- inputTokens: 0,
34298
- outputTokens: 0,
34299
- reasoningTokens: 0,
34300
- totalTokens: 0,
34301
- cachedInputTokens: 0
34302
- };
34303
- }
34304
- function usageFromGenerateTextResult(result) {
34305
- return {
34306
- inputTokens: result.usage.inputTokens || 0,
34307
- outputTokens: result.usage.outputTokens || 0,
34308
- reasoningTokens: result.usage.reasoningTokens || 0,
34309
- totalTokens: result.usage.totalTokens || 0,
34310
- cachedInputTokens: result.usage.cachedInputTokens || 0
34311
- };
34312
- }
34313
- function sumUsage(a, b) {
34314
- return {
34315
- inputTokens: a.inputTokens + b.inputTokens,
34316
- outputTokens: a.outputTokens + b.outputTokens,
34317
- reasoningTokens: a.reasoningTokens + b.reasoningTokens,
34318
- totalTokens: a.totalTokens + b.totalTokens,
34319
- cachedInputTokens: a.cachedInputTokens + b.cachedInputTokens
34320
- };
34321
- }
34322
-
34323
- // ../runtime/src/helpers/checkpoint.ts
34324
- function createInitialCheckpoint(checkpointId, params) {
34325
- return {
34326
- id: checkpointId,
34327
- jobId: params.jobId,
34328
- runId: params.runId,
34329
- expert: {
34330
- key: params.expertKey,
34331
- name: params.expert.name,
34332
- version: params.expert.version
34333
- },
34334
- stepNumber: 1,
34335
- status: "init",
34336
- messages: [],
34337
- usage: createEmptyUsage(),
34338
- contextWindow: params.contextWindow,
34339
- contextWindowUsage: params.contextWindow ? 0 : void 0
34340
- };
34341
- }
34342
- function createNextStepCheckpoint(checkpointId, checkpoint, runId) {
34343
- return {
34344
- ...checkpoint,
34345
- id: checkpointId,
34346
- runId,
34347
- stepNumber: checkpoint.stepNumber + 1
34348
- };
34349
- }
34350
- function buildDelegationReturnState(currentSetting, resultCheckpoint, parentCheckpoint) {
34351
- const { messages, delegatedBy } = resultCheckpoint;
34352
- if (!delegatedBy) {
34353
- throw new Error("delegatedBy is required for buildDelegationReturnState");
34354
- }
34355
- const delegateResultMessage = messages[messages.length - 1];
34356
- if (!delegateResultMessage || delegateResultMessage.type !== "expertMessage") {
34357
- throw new Error("Delegation error: delegation result message is incorrect");
34358
- }
34359
- const delegateText = delegateResultMessage.contents.find((content) => content.type === "textPart");
34360
- if (!delegateText) {
34361
- console.warn(
34362
- `Delegation result from ${resultCheckpoint.expert.key} has no text content. Parent expert ${delegatedBy.expert.key} will receive empty string.`
34363
- );
34364
- }
34365
- const { expert, toolCallId, toolName } = delegatedBy;
34366
- const newRunId = createId();
34367
- return {
34368
- setting: {
34369
- ...currentSetting,
34370
- runId: newRunId,
34371
- expertKey: expert.key,
34372
- input: {
34373
- interactiveToolCallResult: {
34374
- toolCallId,
34375
- toolName,
34376
- skillName: `delegate/${resultCheckpoint.expert.key}`,
34377
- text: delegateText?.text ?? ""
34378
- }
34379
- }
34380
- },
34381
- checkpoint: {
34382
- ...parentCheckpoint,
34383
- runId: newRunId,
34384
- stepNumber: resultCheckpoint.stepNumber,
34385
- usage: resultCheckpoint.usage,
34386
- pendingToolCalls: parentCheckpoint.pendingToolCalls,
34387
- partialToolResults: parentCheckpoint.partialToolResults
34388
- }
34389
- };
34390
- }
34391
-
34392
34155
  // ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
34393
34156
  function getLineColFromPtr(string, ptr) {
34394
34157
  let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
@@ -35218,7 +34981,92 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
35218
34981
  // ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/index.js
35219
34982
  var dist_default = { parse, stringify, TomlDate, TomlError };
35220
34983
 
35221
- // ../runtime/src/helpers/lockfile.ts
34984
+ // ../../packages/perstack-toml/src/utils.ts
34985
+ function isRemoteUrl(configPath) {
34986
+ const lower = configPath.toLowerCase();
34987
+ return lower.startsWith("https://") || lower.startsWith("http://");
34988
+ }
34989
+
34990
+ // ../../packages/perstack-toml/src/config.ts
34991
+ var ALLOWED_CONFIG_HOSTS = ["raw.githubusercontent.com"];
34992
+ async function getPerstackConfig(configPath) {
34993
+ const configString = await findPerstackConfigString(configPath);
34994
+ if (configString === null) {
34995
+ throw new Error("perstack.toml not found. Create one or specify --config path.");
34996
+ }
34997
+ return parsePerstackConfig(configString);
34998
+ }
34999
+ function parsePerstackConfig(config) {
35000
+ const toml = dist_default.parse(config ?? "");
35001
+ return parseWithFriendlyError(perstackConfigSchema, toml, "perstack.toml");
35002
+ }
35003
+ async function fetchRemoteConfig(url) {
35004
+ let parsed;
35005
+ try {
35006
+ parsed = new URL(url);
35007
+ } catch {
35008
+ throw new Error(`Invalid remote config URL: ${url}`);
35009
+ }
35010
+ if (parsed.protocol !== "https:") {
35011
+ throw new Error("Remote config requires HTTPS");
35012
+ }
35013
+ if (!ALLOWED_CONFIG_HOSTS.includes(parsed.hostname)) {
35014
+ throw new Error(`Remote config only allowed from: ${ALLOWED_CONFIG_HOSTS.join(", ")}`);
35015
+ }
35016
+ try {
35017
+ const response = await fetch(url, { redirect: "error" });
35018
+ if (!response.ok) {
35019
+ throw new Error(`${response.status} ${response.statusText}`);
35020
+ }
35021
+ return await response.text();
35022
+ } catch (error) {
35023
+ const message = error instanceof Error ? error.message : String(error);
35024
+ throw new Error(`Failed to fetch remote config: ${message}`);
35025
+ }
35026
+ }
35027
+ async function findPerstackConfigString(configPath) {
35028
+ if (configPath) {
35029
+ if (isRemoteUrl(configPath)) {
35030
+ return await fetchRemoteConfig(configPath);
35031
+ }
35032
+ try {
35033
+ const tomlString = await readFile(path.resolve(process.cwd(), configPath), "utf-8");
35034
+ return tomlString;
35035
+ } catch {
35036
+ throw new Error(`Given config path "${configPath}" is not found`);
35037
+ }
35038
+ }
35039
+ return await findPerstackConfigStringRecursively(path.resolve(process.cwd()));
35040
+ }
35041
+ async function findPerstackConfigStringRecursively(cwd) {
35042
+ try {
35043
+ const tomlString = await readFile(path.resolve(cwd, "perstack.toml"), "utf-8");
35044
+ return tomlString;
35045
+ } catch {
35046
+ if (cwd === path.parse(cwd).root) {
35047
+ return null;
35048
+ }
35049
+ return await findPerstackConfigStringRecursively(path.dirname(cwd));
35050
+ }
35051
+ }
35052
+ async function findConfigPath(configPath) {
35053
+ if (configPath) {
35054
+ return path.resolve(process.cwd(), configPath);
35055
+ }
35056
+ return await findConfigPathRecursively(process.cwd());
35057
+ }
35058
+ async function findConfigPathRecursively(cwd) {
35059
+ const configPath = path.resolve(cwd, "perstack.toml");
35060
+ try {
35061
+ await readFile(configPath);
35062
+ return configPath;
35063
+ } catch {
35064
+ if (cwd === path.parse(cwd).root) {
35065
+ throw new Error("perstack.toml not found. Create one or specify --config path.");
35066
+ }
35067
+ return await findConfigPathRecursively(path.dirname(cwd));
35068
+ }
35069
+ }
35222
35070
  function loadLockfile(lockfilePath) {
35223
35071
  try {
35224
35072
  const content = readFileSync(lockfilePath, "utf-8");
@@ -35229,20 +35077,269 @@ function loadLockfile(lockfilePath) {
35229
35077
  }
35230
35078
  }
35231
35079
  function findLockfile(configPath) {
35080
+ if (configPath) {
35081
+ if (isRemoteUrl(configPath)) {
35082
+ return null;
35083
+ }
35084
+ const configDir = path.dirname(path.resolve(process.cwd(), configPath));
35085
+ return path.join(configDir, "perstack.lock");
35086
+ }
35232
35087
  return findLockfileRecursively(process.cwd());
35233
35088
  }
35234
35089
  function findLockfileRecursively(cwd) {
35235
- const lockfilePath = path2.resolve(cwd, "perstack.lock");
35090
+ const lockfilePath = path.resolve(cwd, "perstack.lock");
35236
35091
  try {
35237
35092
  readFileSync(lockfilePath);
35238
35093
  return lockfilePath;
35239
35094
  } catch {
35240
- if (cwd === path2.parse(cwd).root) {
35095
+ if (cwd === path.parse(cwd).root) {
35241
35096
  return null;
35242
35097
  }
35243
- return findLockfileRecursively(path2.dirname(cwd));
35098
+ return findLockfileRecursively(path.dirname(cwd));
35099
+ }
35100
+ }
35101
+ function generateLockfileToml(lockfile) {
35102
+ return dist_default.stringify(lockfile);
35103
+ }
35104
+
35105
+ // ../../packages/installer/src/expert-resolver.ts
35106
+ function toRuntimeExpert(key, expert) {
35107
+ const skills = Object.fromEntries(
35108
+ Object.entries(expert.skills ?? {}).map(([name, skill]) => {
35109
+ switch (skill.type) {
35110
+ case "mcpStdioSkill":
35111
+ return [
35112
+ name,
35113
+ {
35114
+ type: skill.type,
35115
+ name,
35116
+ description: skill.description,
35117
+ rule: skill.rule,
35118
+ pick: skill.pick ?? [],
35119
+ omit: skill.omit ?? [],
35120
+ command: skill.command,
35121
+ packageName: skill.packageName,
35122
+ requiredEnv: skill.requiredEnv ?? [],
35123
+ lazyInit: false
35124
+ }
35125
+ ];
35126
+ case "mcpSseSkill":
35127
+ return [
35128
+ name,
35129
+ {
35130
+ type: skill.type,
35131
+ name,
35132
+ description: skill.description,
35133
+ rule: skill.rule,
35134
+ pick: skill.pick ?? [],
35135
+ omit: skill.omit ?? [],
35136
+ endpoint: skill.endpoint,
35137
+ lazyInit: false
35138
+ }
35139
+ ];
35140
+ case "interactiveSkill":
35141
+ return [
35142
+ name,
35143
+ {
35144
+ type: skill.type,
35145
+ name,
35146
+ description: skill.description,
35147
+ rule: skill.rule,
35148
+ tools: Object.fromEntries(
35149
+ Object.entries(skill.tools).map(([toolName, tool]) => [
35150
+ toolName,
35151
+ {
35152
+ name: toolName,
35153
+ description: tool.description,
35154
+ inputSchema: JSON.parse(tool.inputJsonSchema)
35155
+ }
35156
+ ])
35157
+ )
35158
+ }
35159
+ ];
35160
+ default: {
35161
+ throw new Error(`Unknown skill type: ${skill.type}`);
35162
+ }
35163
+ }
35164
+ })
35165
+ );
35166
+ return {
35167
+ key,
35168
+ name: expert.name,
35169
+ version: expert.version,
35170
+ minRuntimeVersion: expert.minRuntimeVersion ?? "v1.0",
35171
+ description: expert.description ?? "",
35172
+ instruction: expert.instruction,
35173
+ skills,
35174
+ delegates: expert.delegates ?? [],
35175
+ tags: expert.tags ?? []
35176
+ };
35177
+ }
35178
+ function configExpertToExpert(key, configExpert) {
35179
+ return expertSchema.parse({
35180
+ key,
35181
+ name: key,
35182
+ version: configExpert.version ?? "1.0.0",
35183
+ description: configExpert.description,
35184
+ instruction: configExpert.instruction,
35185
+ skills: configExpert.skills,
35186
+ delegates: configExpert.delegates,
35187
+ tags: configExpert.tags,
35188
+ providerTools: configExpert.providerTools,
35189
+ providerSkills: configExpert.providerSkills,
35190
+ providerToolOptions: configExpert.providerToolOptions
35191
+ });
35192
+ }
35193
+ async function resolveAllExperts(config, env) {
35194
+ const experts = {};
35195
+ for (const [key, configExpert] of Object.entries(config.experts ?? {})) {
35196
+ experts[key] = configExpertToExpert(key, configExpert);
35197
+ }
35198
+ const toResolve = /* @__PURE__ */ new Set();
35199
+ for (const expert of Object.values(experts)) {
35200
+ for (const delegateKey of expert.delegates) {
35201
+ if (!experts[delegateKey]) {
35202
+ toResolve.add(delegateKey);
35203
+ }
35204
+ }
35205
+ }
35206
+ if (toResolve.size === 0) {
35207
+ return experts;
35208
+ }
35209
+ const apiKey = env.PERSTACK_API_KEY;
35210
+ if (!apiKey) {
35211
+ throw new Error("PERSTACK_API_KEY is required to resolve remote delegates");
35212
+ }
35213
+ const client = createApiClient({
35214
+ baseUrl: config.perstackApiBaseUrl ?? defaultPerstackApiBaseUrl,
35215
+ apiKey
35216
+ });
35217
+ while (toResolve.size > 0) {
35218
+ const delegateKey = toResolve.values().next().value;
35219
+ if (!delegateKey) break;
35220
+ toResolve.delete(delegateKey);
35221
+ if (experts[delegateKey]) continue;
35222
+ const result = await client.experts.get(delegateKey);
35223
+ if (!result.ok) {
35224
+ throw new Error(`Failed to resolve delegate "${delegateKey}": ${result.error.message}`);
35225
+ }
35226
+ const publishedExpert = result.data.data.definition.experts[delegateKey];
35227
+ if (!publishedExpert) {
35228
+ throw new Error(`Expert "${delegateKey}" not found in API response`);
35229
+ }
35230
+ experts[delegateKey] = toRuntimeExpert(delegateKey, publishedExpert);
35231
+ for (const nestedDelegate of publishedExpert.delegates ?? []) {
35232
+ if (!experts[nestedDelegate]) {
35233
+ toResolve.add(nestedDelegate);
35234
+ }
35235
+ }
35236
+ }
35237
+ return experts;
35238
+ }
35239
+
35240
+ // ../../packages/runtime/package.json
35241
+ var package_default = {
35242
+ version: "0.0.96"};
35243
+
35244
+ // ../../packages/runtime/src/helpers/usage.ts
35245
+ function createEmptyUsage() {
35246
+ return {
35247
+ inputTokens: 0,
35248
+ outputTokens: 0,
35249
+ reasoningTokens: 0,
35250
+ totalTokens: 0,
35251
+ cachedInputTokens: 0
35252
+ };
35253
+ }
35254
+ function usageFromGenerateTextResult(result) {
35255
+ return {
35256
+ inputTokens: result.usage.inputTokens || 0,
35257
+ outputTokens: result.usage.outputTokens || 0,
35258
+ reasoningTokens: result.usage.reasoningTokens || 0,
35259
+ totalTokens: result.usage.totalTokens || 0,
35260
+ cachedInputTokens: result.usage.cachedInputTokens || 0
35261
+ };
35262
+ }
35263
+ function sumUsage(a, b) {
35264
+ return {
35265
+ inputTokens: a.inputTokens + b.inputTokens,
35266
+ outputTokens: a.outputTokens + b.outputTokens,
35267
+ reasoningTokens: a.reasoningTokens + b.reasoningTokens,
35268
+ totalTokens: a.totalTokens + b.totalTokens,
35269
+ cachedInputTokens: a.cachedInputTokens + b.cachedInputTokens
35270
+ };
35271
+ }
35272
+
35273
+ // ../../packages/runtime/src/helpers/checkpoint.ts
35274
+ function createInitialCheckpoint(checkpointId, params) {
35275
+ return {
35276
+ id: checkpointId,
35277
+ jobId: params.jobId,
35278
+ runId: params.runId,
35279
+ expert: {
35280
+ key: params.expertKey,
35281
+ name: params.expert.name,
35282
+ version: params.expert.version
35283
+ },
35284
+ stepNumber: 1,
35285
+ status: "init",
35286
+ messages: [],
35287
+ usage: createEmptyUsage(),
35288
+ contextWindow: params.contextWindow,
35289
+ contextWindowUsage: params.contextWindow ? 0 : void 0
35290
+ };
35291
+ }
35292
+ function createNextStepCheckpoint(checkpointId, checkpoint, runId) {
35293
+ return {
35294
+ ...checkpoint,
35295
+ id: checkpointId,
35296
+ runId,
35297
+ stepNumber: checkpoint.stepNumber + 1
35298
+ };
35299
+ }
35300
+ function buildDelegationReturnState(currentSetting, resultCheckpoint, parentCheckpoint) {
35301
+ const { messages, delegatedBy } = resultCheckpoint;
35302
+ if (!delegatedBy) {
35303
+ throw new Error("delegatedBy is required for buildDelegationReturnState");
35304
+ }
35305
+ const delegateResultMessage = messages[messages.length - 1];
35306
+ if (!delegateResultMessage || delegateResultMessage.type !== "expertMessage") {
35307
+ throw new Error("Delegation error: delegation result message is incorrect");
35308
+ }
35309
+ const delegateText = delegateResultMessage.contents.find((content) => content.type === "textPart");
35310
+ if (!delegateText) {
35311
+ console.warn(
35312
+ `Delegation result from ${resultCheckpoint.expert.key} has no text content. Parent expert ${delegatedBy.expert.key} will receive empty string.`
35313
+ );
35244
35314
  }
35315
+ const { expert, toolCallId, toolName } = delegatedBy;
35316
+ const newRunId = createId();
35317
+ return {
35318
+ setting: {
35319
+ ...currentSetting,
35320
+ runId: newRunId,
35321
+ expertKey: expert.key,
35322
+ input: {
35323
+ interactiveToolCallResult: {
35324
+ toolCallId,
35325
+ toolName,
35326
+ skillName: `delegate/${resultCheckpoint.expert.key}`,
35327
+ text: delegateText?.text ?? ""
35328
+ }
35329
+ }
35330
+ },
35331
+ checkpoint: {
35332
+ ...parentCheckpoint,
35333
+ runId: newRunId,
35334
+ stepNumber: resultCheckpoint.stepNumber,
35335
+ usage: resultCheckpoint.usage,
35336
+ pendingToolCalls: parentCheckpoint.pendingToolCalls,
35337
+ partialToolResults: parentCheckpoint.partialToolResults
35338
+ }
35339
+ };
35245
35340
  }
35341
+
35342
+ // ../../packages/runtime/src/helpers/lockfile.ts
35246
35343
  function getLockfileExpertToolDefinitions(lockfileExpert) {
35247
35344
  const result = {};
35248
35345
  for (const toolDef of lockfileExpert.toolDefinitions) {
@@ -62882,7 +62979,7 @@ function createOllama(options = {}) {
62882
62979
  }
62883
62980
  createOllama();
62884
62981
 
62885
- // ../runtime/src/helpers/model.ts
62982
+ // ../../packages/runtime/src/helpers/model.ts
62886
62983
  __toESM(require_undici(), 1);
62887
62984
  function getContextWindow(providerName, modelId) {
62888
62985
  const modelConfig = knownModels.find((model) => model.provider === providerName)?.models.find((model) => model.name === modelId);
@@ -62892,7 +62989,7 @@ function calculateContextWindowUsage(usage, contextWindow) {
62892
62989
  return (usage.inputTokens + usage.cachedInputTokens + usage.outputTokens) / contextWindow;
62893
62990
  }
62894
62991
 
62895
- // ../runtime/src/helpers/runtime-version.ts
62992
+ // ../../packages/runtime/src/helpers/runtime-version.ts
62896
62993
  function parseRuntimeVersion(version) {
62897
62994
  if (!version) return null;
62898
62995
  const match = version.match(/^v?(\d+)\.(\d+)$/);
@@ -62931,9 +63028,9 @@ function validateRuntimeVersion(experts) {
62931
63028
  }
62932
63029
  }
62933
63030
 
62934
- // ../runtime/src/helpers/setup-experts.ts
63031
+ // ../../packages/runtime/src/helpers/setup-experts.ts
62935
63032
  async function setupExperts(setting, resolveExpertToRun) {
62936
- const resolveFn = resolveExpertToRun ?? (await import('../resolve-expert-BZ72FFV7.js')).resolveExpertToRun;
63033
+ const resolveFn = resolveExpertToRun ?? (await import('../resolve-expert-X775EKPT.js')).resolveExpertToRun;
62937
63034
  const { expertKey } = setting;
62938
63035
  const experts = { ...setting.experts };
62939
63036
  const clientOptions = {
@@ -62958,7 +63055,7 @@ async function setupExperts(setting, resolveExpertToRun) {
62958
63055
  return { expertToRun, experts };
62959
63056
  }
62960
63057
 
62961
- // ../runtime/src/helpers/thinking.ts
63058
+ // ../../packages/runtime/src/helpers/thinking.ts
62962
63059
  function extractThinkingParts(reasoning) {
62963
63060
  if (!reasoning) return [];
62964
63061
  return reasoning.map((r) => ({
@@ -62973,7 +63070,7 @@ function extractThinkingText(reasoning) {
62973
63070
  return reasoning.filter((r) => r.text).map((r) => r.text).join("\n");
62974
63071
  }
62975
63072
 
62976
- // ../runtime/src/orchestration/delegation-strategy.ts
63073
+ // ../../packages/runtime/src/orchestration/delegation-strategy.ts
62977
63074
  var SingleDelegationStrategy = class {
62978
63075
  async execute(delegations, setting, context, parentExpert, _runFn, _parentOptions) {
62979
63076
  if (delegations.length !== 1) {
@@ -63185,7 +63282,7 @@ function extractDelegationContext(checkpoint) {
63185
63282
  };
63186
63283
  }
63187
63284
 
63188
- // ../runtime/src/events/event-emitter.ts
63285
+ // ../../packages/runtime/src/events/event-emitter.ts
63189
63286
  var RunEventEmitter = class {
63190
63287
  listeners = [];
63191
63288
  subscribe(listener) {
@@ -63210,7 +63307,7 @@ var RunEventEmitter = class {
63210
63307
  }
63211
63308
  };
63212
63309
 
63213
- // ../runtime/src/helpers/provider-adapter-factory.ts
63310
+ // ../../packages/runtime/src/helpers/provider-adapter-factory.ts
63214
63311
  var PROVIDER_PACKAGE_NAMES = {
63215
63312
  anthropic: "anthropic-provider",
63216
63313
  openai: "openai-provider",
@@ -64314,7 +64411,7 @@ var VertexProviderAdapter = class extends BaseProviderAdapter {
64314
64411
  }
64315
64412
  };
64316
64413
 
64317
- // ../runtime/src/helpers/register-providers.ts
64414
+ // ../../packages/runtime/src/helpers/register-providers.ts
64318
64415
  registerProviderAdapter(
64319
64416
  "anthropic",
64320
64417
  async () => AnthropicProviderAdapter
@@ -64348,7 +64445,7 @@ registerProviderAdapter(
64348
64445
  async () => DeepseekProviderAdapter
64349
64446
  );
64350
64447
 
64351
- // ../runtime/src/llm/executor.ts
64448
+ // ../../packages/runtime/src/llm/executor.ts
64352
64449
  var shouldEnableReasoning = (budget) => budget !== void 0 && budget !== "none" && budget !== 0;
64353
64450
  var PROVIDERS_WITHOUT_REASONING_HISTORY = [
64354
64451
  "openai",
@@ -67738,7 +67835,7 @@ var McpToolExecutor = class {
67738
67835
  }
67739
67836
  };
67740
67837
 
67741
- // ../runtime/src/tool-execution/executor-factory.ts
67838
+ // ../../packages/runtime/src/tool-execution/executor-factory.ts
67742
67839
  var ToolExecutorFactory = class {
67743
67840
  executors;
67744
67841
  constructor() {
@@ -67772,7 +67869,7 @@ var ToolExecutorFactory = class {
67772
67869
  };
67773
67870
  var toolExecutorFactory = new ToolExecutorFactory();
67774
67871
 
67775
- // ../runtime/src/tool-execution/tool-classifier.ts
67872
+ // ../../packages/runtime/src/tool-execution/tool-classifier.ts
67776
67873
  async function getToolTypeByName(toolName, skillManagers) {
67777
67874
  const skillManager = await getSkillManagerByToolName(skillManagers, toolName);
67778
67875
  return skillManager.type;
@@ -67795,7 +67892,7 @@ async function classifyToolCalls(toolCalls, skillManagers) {
67795
67892
  return classified;
67796
67893
  }
67797
67894
 
67798
- // ../runtime/src/state-machine/states/calling-delegates.ts
67895
+ // ../../packages/runtime/src/state-machine/states/calling-delegates.ts
67799
67896
  async function callingDelegatesLogic({
67800
67897
  setting,
67801
67898
  checkpoint,
@@ -67855,7 +67952,7 @@ async function callingDelegatesLogic({
67855
67952
  });
67856
67953
  }
67857
67954
 
67858
- // ../runtime/src/state-machine/states/calling-interactive-tools.ts
67955
+ // ../../packages/runtime/src/state-machine/states/calling-interactive-tools.ts
67859
67956
  async function callingInteractiveToolsLogic({
67860
67957
  setting,
67861
67958
  checkpoint,
@@ -67885,7 +67982,7 @@ async function callingInteractiveToolsLogic({
67885
67982
  });
67886
67983
  }
67887
67984
 
67888
- // ../runtime/src/messages/message.ts
67985
+ // ../../packages/runtime/src/messages/message.ts
67889
67986
  function createUserMessage(contents) {
67890
67987
  return {
67891
67988
  type: "userMessage",
@@ -68097,7 +68194,7 @@ function toolResultPartToCoreToolResultPart(part) {
68097
68194
  };
68098
68195
  }
68099
68196
 
68100
- // ../runtime/src/state-machine/states/calling-mcp-tools.ts
68197
+ // ../../packages/runtime/src/state-machine/states/calling-mcp-tools.ts
68101
68198
  function hasRemainingTodos(toolResult) {
68102
68199
  const firstPart = toolResult.result[0];
68103
68200
  if (!firstPart || firstPart.type !== "textPart") {
@@ -68203,7 +68300,7 @@ async function callingMcpToolsLogic({
68203
68300
  return resolveToolResults(setting, checkpoint, { toolResults });
68204
68301
  }
68205
68302
 
68206
- // ../runtime/src/state-machine/states/finishing-step.ts
68303
+ // ../../packages/runtime/src/state-machine/states/finishing-step.ts
68207
68304
  async function finishingStepLogic({
68208
68305
  setting,
68209
68306
  checkpoint,
@@ -68240,7 +68337,7 @@ async function finishingStepLogic({
68240
68337
  });
68241
68338
  }
68242
68339
 
68243
- // ../runtime/src/state-machine/states/generating-run-result.ts
68340
+ // ../../packages/runtime/src/state-machine/states/generating-run-result.ts
68244
68341
  async function generatingRunResultLogic({
68245
68342
  setting,
68246
68343
  checkpoint,
@@ -68370,7 +68467,7 @@ async function generatingRunResultLogic({
68370
68467
  });
68371
68468
  }
68372
68469
 
68373
- // ../runtime/src/state-machine/states/generating-tool-call.ts
68470
+ // ../../packages/runtime/src/state-machine/states/generating-tool-call.ts
68374
68471
  async function classifyToolCalls2(toolCalls, skillManagers) {
68375
68472
  return Promise.all(
68376
68473
  toolCalls.map(async (tc) => {
@@ -68624,7 +68721,7 @@ async function generatingToolCallLogic({
68624
68721
  throw new Error(`Unexpected finish reason: ${finishReason}`);
68625
68722
  }
68626
68723
 
68627
- // ../runtime/src/messages/instruction-message.ts
68724
+ // ../../packages/runtime/src/messages/instruction-message.ts
68628
68725
  function getMetaInstruction(startedAt) {
68629
68726
  return dedent`
68630
68727
  IMPORTANT:
@@ -68723,7 +68820,7 @@ function getDelegateRules(expert, experts) {
68723
68820
  }, "");
68724
68821
  }
68725
68822
 
68726
- // ../runtime/src/state-machine/states/init.ts
68823
+ // ../../packages/runtime/src/state-machine/states/init.ts
68727
68824
  async function initLogic({
68728
68825
  setting,
68729
68826
  checkpoint
@@ -68778,7 +68875,7 @@ async function initLogic({
68778
68875
  }
68779
68876
  }
68780
68877
 
68781
- // ../runtime/src/state-machine/states/preparing-for-step.ts
68878
+ // ../../packages/runtime/src/state-machine/states/preparing-for-step.ts
68782
68879
  async function preparingForStepLogic({
68783
68880
  setting,
68784
68881
  checkpoint
@@ -68788,7 +68885,7 @@ async function preparingForStepLogic({
68788
68885
  });
68789
68886
  }
68790
68887
 
68791
- // ../runtime/src/state-machine/states/resolving-tool-result.ts
68888
+ // ../../packages/runtime/src/state-machine/states/resolving-tool-result.ts
68792
68889
  async function resolvingToolResultLogic({
68793
68890
  setting,
68794
68891
  checkpoint,
@@ -68814,7 +68911,7 @@ async function resolvingToolResultLogic({
68814
68911
  });
68815
68912
  }
68816
68913
 
68817
- // ../runtime/src/state-machine/states/resuming-from-stop.ts
68914
+ // ../../packages/runtime/src/state-machine/states/resuming-from-stop.ts
68818
68915
  async function resumingFromStopLogic({
68819
68916
  setting,
68820
68917
  checkpoint
@@ -68833,7 +68930,7 @@ async function resumingFromStopLogic({
68833
68930
  });
68834
68931
  }
68835
68932
 
68836
- // ../runtime/src/state-machine/machine.ts
68933
+ // ../../packages/runtime/src/state-machine/machine.ts
68837
68934
  var runtimeStateMachine = setup({
68838
68935
  }).createMachine({
68839
68936
  /** @xstate-layout N4IgpgJg5mDOIC5QCUCuA7AdASXQSwBcBiWAgQwCcC10BtABgF1FQAHAe1kL3fRZAAeiAKz0AzJgDsAJgAsksZNlixs+gDZZAGhABPRIszCAjGIAcY4crPHhJyQF8HOmpgAKFMK0p50UAGLsFADKBF4k5FQA4mDoYBRkBDx0TPwcXEm8-EIIZmaymPRK8saSopL00tI6+gjq9JjSltLG9HnqZkqdTi4YmDFxCUl+ACrs7AA2AMJkExNEngQUugzMSCDp3FnrOcam0pgAnHbS9GeSZsIq6jWIh2KHUsYd9MbSwl2S6j0grgPxiV8UDGkxmcyIAGNZhMQRNVmlOFs+DtEPt1Jg3odpGVbFcrLcENIzOjbGYipIZMpnmYfn9YgDhsDxtNoZDobgwgkIUkAG5gWHw9abTLI0C7ImSTDqYTY2S45TCCwE54HUr1WRXSqHcRVWl9f5DIGwsHzKFzAAiYAmYCgiTAgrYiJF2VRYnoj1ehwskkOZTEz2EBMMJnMFnezxUF2+zl+fRNRuZCzgkz5sOQcFQEwIDo2TuSLoQpWJUvowl9Flk0sqBLlZik2Mkpjyan90d6WHjo0TnlgKf5AAt2KgoP3s6khXntmLUT6JL6PkoFJX1MZtHoRKIpdrK3sqorpG3Yx3oQnJknexM+W4IAAzfx4a054X5lGFn2PMTYlSyWQH32WAl1DKKV1Q6L1V1EWQ9WPOZT3mHs+2wABbMgYHvR9x0dDIX2nN8zEeOVjGORsmgsMQCTJYRMGJORwP9MwDxpGNXE7Jkz0SMIkNYAgpnYLjrRFJ9J1FQQZzJTBPxUfDDjlN1OgJIkSUVUtDlXCpsUPVx0wvHk4O0zNiBvXw8FgftjWhITsKnUTCU-SU92JMlfSaGtjDrGQKSbfJxGeaDMG0lMjUHYdRyIIz8FM8y5kspECyabFGneRz3RkN011qOwGnUbcVzeJKDz8gLLyBa87wfMAwuMyLmRNGLnVfeL7KSl5nPI9c6mA9RQPwmwNVLQrk2KvxkNQsB0Iq8KTLMmqLMw3MrJEnJGsSxUWtSgkfSU-JDmIqNKj8g1AT8Gh9KzSE+NYASwBoOqcJs+K61sDo5SKBifwU4tSRUtTKi+KDmLjE9hvQTkyG5PBU0TUh2FYGgACFdA5AFwchyZbus3YyklYRst/DUlDEaU2tqFUMS+NyPmlPZDiAvzWMta1bTCCIYfh3QGZtO10cWmcLiOQnG3qHHiSDbGvM-Ex1EjYk/PvCL+yBUJwghXhhlQfl2AAOTAAQCCV1hubiqxjCMRUZXMGSvVUZV6A1LcuorDp8I0WWqoVvx9ZZ2GMARgBRAQITASBIAAWTIAR9dgQ2Gs0Ki8nyK4bCuDVRZNzRwxse4GK6pwY3QdgIDgfgaARBaCxUBosU0cw5TLUiCQAWlkR4nPdbVCeyld/vbHB8AIUvYtfRQ6yr6xa6xcwCTLaiadj1dKxk1phD8jwvB8PxAhCMJWAH+rcKAyuyVaa5Wi+KeW9njV59xpeDvpQ0u1BaFd7u3Y2keDpO7LW2FDLc+Z6AnsPEO4ZYAxghMOCL8MaojsJKYi8cHZ5C9EGNoRg1CdH3GcZeYD/KDV0o-CYp1+4TjLg1cQkp-SfjDE9Ew1R2o-hNnsUs1MfR-UuANHSQUhwjmIVhQeuFTg-ilF8GUblTgKDoRlBQhQJEaiJMnfCHDAp+FKuNKBPNCSlgaOIeQttWxS0DO1bKdY9HvH9D+FotMcFFXwVAEaaFyrqLirbBo1M7KvFUDJCiRJGgalUM3LEMk5R30GEdKAJ0MxZicWQlQEklAyillWVoZgUF1isG0MoDEsF0yBnYkGyNeQa0mNE3CtgiIYnEEBToFwvS+mVPkU20l8JWG1OIHJsE/AcyZmAEpNlbBqEwLo7yVRbY3HatPfCXUOgfCsGSTQmk+hyymorbevSloykeFYCkrxfqrmJiIaRRQ7JbP8Q8PyoQYasEgGsxA2JWiNB/jjdQTRqb1IkP6OwRF8KMSAbnBwQA */
@@ -69197,7 +69294,7 @@ var StateMachineLogics = {
69197
69294
  FinishingStep: finishingStepLogic
69198
69295
  };
69199
69296
 
69200
- // ../runtime/src/state-machine/actor-factory.ts
69297
+ // ../../packages/runtime/src/state-machine/actor-factory.ts
69201
69298
  var DefaultActorFactory = class {
69202
69299
  create(input) {
69203
69300
  return createActor(runtimeStateMachine, input);
@@ -69205,7 +69302,7 @@ var DefaultActorFactory = class {
69205
69302
  };
69206
69303
  var defaultActorFactory = new DefaultActorFactory();
69207
69304
 
69208
- // ../runtime/src/state-machine/coordinator.ts
69305
+ // ../../packages/runtime/src/state-machine/coordinator.ts
69209
69306
  var StateMachineCoordinator = class {
69210
69307
  constructor(params, deps = {}) {
69211
69308
  this.params = params;
@@ -69306,13 +69403,13 @@ var StateMachineCoordinator = class {
69306
69403
  }
69307
69404
  };
69308
69405
 
69309
- // ../runtime/src/state-machine/executor.ts
69406
+ // ../../packages/runtime/src/state-machine/executor.ts
69310
69407
  async function executeStateMachine(params) {
69311
69408
  const coordinator = new StateMachineCoordinator(params);
69312
69409
  return coordinator.execute();
69313
69410
  }
69314
69411
 
69315
- // ../runtime/src/orchestration/single-run-executor.ts
69412
+ // ../../packages/runtime/src/orchestration/single-run-executor.ts
69316
69413
  var SingleRunExecutor = class {
69317
69414
  constructor(options = {}) {
69318
69415
  this.options = options;
@@ -69388,7 +69485,7 @@ var SingleRunExecutor = class {
69388
69485
  }
69389
69486
  };
69390
69487
 
69391
- // ../runtime/src/run.ts
69488
+ // ../../packages/runtime/src/run.ts
69392
69489
  var defaultCreateJob = (jobId, expertKey, maxSteps, runtimeVersion2 = getCurrentRuntimeVersion()) => ({
69393
69490
  id: jobId,
69394
69491
  coordinatorExpertKey: expertKey,
@@ -69492,7 +69589,7 @@ async function run(runInput, options) {
69492
69589
  }
69493
69590
  }
69494
69591
 
69495
- // ../runtime/src/index.ts
69592
+ // ../../packages/runtime/src/index.ts
69496
69593
  var runtimeVersion = package_default.version;
69497
69594
  function getEnv(envPath) {
69498
69595
  const env = Object.fromEntries(
@@ -69501,89 +69598,6 @@ function getEnv(envPath) {
69501
69598
  dotenv.config({ path: envPath, processEnv: env, quiet: true });
69502
69599
  return env;
69503
69600
  }
69504
- var ALLOWED_CONFIG_HOSTS = ["raw.githubusercontent.com"];
69505
- async function getPerstackConfig(configPath) {
69506
- const configString = await findPerstackConfigString(configPath);
69507
- if (configString === null) {
69508
- throw new Error("perstack.toml not found. Create one or specify --config path.");
69509
- }
69510
- return await parsePerstackConfig(configString);
69511
- }
69512
- function isRemoteUrl2(configPath) {
69513
- const lower = configPath.toLowerCase();
69514
- return lower.startsWith("https://") || lower.startsWith("http://");
69515
- }
69516
- async function fetchRemoteConfig(url) {
69517
- let parsed;
69518
- try {
69519
- parsed = new URL(url);
69520
- } catch {
69521
- throw new Error(`Invalid remote config URL: ${url}`);
69522
- }
69523
- if (parsed.protocol !== "https:") {
69524
- throw new Error("Remote config requires HTTPS");
69525
- }
69526
- if (!ALLOWED_CONFIG_HOSTS.includes(parsed.hostname)) {
69527
- throw new Error(`Remote config only allowed from: ${ALLOWED_CONFIG_HOSTS.join(", ")}`);
69528
- }
69529
- try {
69530
- const response = await fetch(url, { redirect: "error" });
69531
- if (!response.ok) {
69532
- throw new Error(`${response.status} ${response.statusText}`);
69533
- }
69534
- return await response.text();
69535
- } catch (error) {
69536
- const message = error instanceof Error ? error.message : String(error);
69537
- throw new Error(`Failed to fetch remote config: ${message}`);
69538
- }
69539
- }
69540
- async function findPerstackConfigString(configPath) {
69541
- if (configPath) {
69542
- if (isRemoteUrl2(configPath)) {
69543
- return await fetchRemoteConfig(configPath);
69544
- }
69545
- try {
69546
- const tomlString = await readFile(path2.resolve(process.cwd(), configPath), "utf-8");
69547
- return tomlString;
69548
- } catch {
69549
- throw new Error(`Given config path "${configPath}" is not found`);
69550
- }
69551
- }
69552
- return await findPerstackConfigStringRecursively(path2.resolve(process.cwd()));
69553
- }
69554
- async function findPerstackConfigStringRecursively(cwd) {
69555
- try {
69556
- const tomlString = await readFile(path2.resolve(cwd, "perstack.toml"), "utf-8");
69557
- return tomlString;
69558
- } catch {
69559
- if (cwd === path2.parse(cwd).root) {
69560
- return null;
69561
- }
69562
- return await findPerstackConfigStringRecursively(path2.dirname(cwd));
69563
- }
69564
- }
69565
- async function parsePerstackConfig(config) {
69566
- const toml = dist_default.parse(config ?? "");
69567
- return parseWithFriendlyError(perstackConfigSchema, toml, "perstack.toml");
69568
- }
69569
- async function findConfigPath(configPath) {
69570
- if (configPath) {
69571
- return path2.resolve(process.cwd(), configPath);
69572
- }
69573
- return await findConfigPathRecursively(process.cwd());
69574
- }
69575
- async function findConfigPathRecursively(cwd) {
69576
- const configPath = path2.resolve(cwd, "perstack.toml");
69577
- try {
69578
- await readFile(configPath);
69579
- return configPath;
69580
- } catch {
69581
- if (cwd === path2.parse(cwd).root) {
69582
- throw new Error("perstack.toml not found. Create one or specify --config path.");
69583
- }
69584
- return await findConfigPathRecursively(path2.dirname(cwd));
69585
- }
69586
- }
69587
69601
 
69588
69602
  // ../../packages/installer/src/lockfile-generator.ts
69589
69603
  function expertToLockfileExpert(expert, toolDefinitions) {
@@ -69599,15 +69613,12 @@ function expertToLockfileExpert(expert, toolDefinitions) {
69599
69613
  toolDefinitions
69600
69614
  };
69601
69615
  }
69602
- function generateLockfileToml(lockfile) {
69603
- return dist_default.stringify(lockfile);
69604
- }
69605
69616
 
69606
69617
  // ../../packages/installer/src/handler.ts
69607
69618
  async function installHandler(options) {
69608
69619
  try {
69609
- const configPath = await findConfigPath(options.config);
69610
- const config = await getPerstackConfig(options.config);
69620
+ const configPath = options.configPath;
69621
+ const config = options.perstackConfig;
69611
69622
  const envPath = options.envPath && options.envPath.length > 0 ? options.envPath : config.envPath ?? [".env", ".env.local"];
69612
69623
  const env = getEnv(envPath);
69613
69624
  console.log("Resolving experts...");
@@ -69626,10 +69637,10 @@ async function installHandler(options) {
69626
69637
  const lockfile = {
69627
69638
  version: "1",
69628
69639
  generatedAt: Date.now(),
69629
- configPath: path2.basename(configPath),
69640
+ configPath: path.basename(configPath),
69630
69641
  experts: lockfileExperts
69631
69642
  };
69632
- const lockfilePath = path2.join(path2.dirname(configPath), "perstack.lock");
69643
+ const lockfilePath = path.join(path.dirname(configPath), "perstack.lock");
69633
69644
  const lockfileContent = generateLockfileToml(lockfile);
69634
69645
  await writeFile(lockfilePath, lockfileContent, "utf-8");
69635
69646
  console.log(`Generated ${lockfilePath}`);
@@ -69653,12 +69664,12 @@ function storeJob(job) {
69653
69664
  if (!existsSync(jobDir)) {
69654
69665
  mkdirSync(jobDir, { recursive: true });
69655
69666
  }
69656
- const jobPath = path2.resolve(jobDir, "job.json");
69667
+ const jobPath = path.resolve(jobDir, "job.json");
69657
69668
  writeFileSync(jobPath, JSON.stringify(job, null, 2));
69658
69669
  }
69659
69670
  function retrieveJob(jobId) {
69660
69671
  const jobDir = getJobDir(jobId);
69661
- const jobPath = path2.resolve(jobDir, "job.json");
69672
+ const jobPath = path.resolve(jobDir, "job.json");
69662
69673
  if (!existsSync(jobPath)) {
69663
69674
  return void 0;
69664
69675
  }
@@ -69676,7 +69687,7 @@ function getAllJobs() {
69676
69687
  }
69677
69688
  const jobs = [];
69678
69689
  for (const jobDirName of jobDirNames) {
69679
- const jobPath = path2.resolve(jobsDir, jobDirName, "job.json");
69690
+ const jobPath = path.resolve(jobsDir, jobDirName, "job.json");
69680
69691
  if (!existsSync(jobPath)) {
69681
69692
  continue;
69682
69693
  }
@@ -69737,7 +69748,7 @@ function getCheckpointsByJobId(jobId) {
69737
69748
  const checkpoints = [];
69738
69749
  for (const file of files) {
69739
69750
  try {
69740
- const content = readFileSync(path2.resolve(checkpointDir, file), "utf-8");
69751
+ const content = readFileSync(path.resolve(checkpointDir, file), "utf-8");
69741
69752
  checkpoints.push(checkpointSchema.parse(JSON.parse(content)));
69742
69753
  } catch {
69743
69754
  }
@@ -69758,13 +69769,13 @@ function getAllRuns() {
69758
69769
  }
69759
69770
  const runs = [];
69760
69771
  for (const jobDirName of jobDirNames) {
69761
- const runsDir = path2.resolve(jobsDir, jobDirName, "runs");
69772
+ const runsDir = path.resolve(jobsDir, jobDirName, "runs");
69762
69773
  if (!existsSync(runsDir)) {
69763
69774
  continue;
69764
69775
  }
69765
69776
  const runDirNames = readdirSync(runsDir, { withFileTypes: true }).filter((dir) => dir.isDirectory()).map((dir) => dir.name);
69766
69777
  for (const runDirName of runDirNames) {
69767
- const runSettingPath = path2.resolve(runsDir, runDirName, "run-setting.json");
69778
+ const runSettingPath = path.resolve(runsDir, runDirName, "run-setting.json");
69768
69779
  if (!existsSync(runSettingPath)) {
69769
69780
  continue;
69770
69781
  }
@@ -69798,7 +69809,7 @@ function getEventContents(jobId, runId, maxStepNumber) {
69798
69809
  const events = [];
69799
69810
  for (const { file } of eventFiles) {
69800
69811
  try {
69801
- const content = readFileSync(path2.resolve(runDir, file), "utf-8");
69812
+ const content = readFileSync(path.resolve(runDir, file), "utf-8");
69802
69813
  events.push(JSON.parse(content));
69803
69814
  } catch {
69804
69815
  }
@@ -69806,7 +69817,7 @@ function getEventContents(jobId, runId, maxStepNumber) {
69806
69817
  return events;
69807
69818
  }
69808
69819
  function getRunIdsByJobId(jobId) {
69809
- const runsDir = path2.resolve(getJobDir(jobId), "runs");
69820
+ const runsDir = path.resolve(getJobDir(jobId), "runs");
69810
69821
  if (!existsSync(runsDir)) {
69811
69822
  return [];
69812
69823
  }
@@ -69874,7 +69885,7 @@ function createLogDataFetcher(storage) {
69874
69885
  }
69875
69886
  function getJobDirMtime(basePath, jobId) {
69876
69887
  try {
69877
- const jobDir = path2.join(basePath, "jobs", jobId);
69888
+ const jobDir = path.join(basePath, "jobs", jobId);
69878
69889
  const stats = statSync(jobDir);
69879
69890
  return stats.mtimeMs;
69880
69891
  } catch {
@@ -69890,7 +69901,7 @@ function createStorageAdapter(basePath) {
69890
69901
  getEventContents: async (jobId, runId, maxStep) => getEventContents(jobId, runId, maxStep),
69891
69902
  getAllRuns: async () => getAllRuns(),
69892
69903
  getJobIds: () => {
69893
- const jobsDir = path2.join(basePath, "jobs");
69904
+ const jobsDir = path.join(basePath, "jobs");
69894
69905
  if (!existsSync(jobsDir)) return [];
69895
69906
  return readdirSync(jobsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
69896
69907
  },
@@ -70681,7 +70692,7 @@ function getAllEventContentsForJob(jobId, maxStepNumber) {
70681
70692
  var defaultProvider = "anthropic";
70682
70693
  var defaultModel = "claude-sonnet-4-5";
70683
70694
  async function resolveRunContext(input) {
70684
- const perstackConfig = input.perstackConfig ?? await getPerstackConfig(input.configPath);
70695
+ const perstackConfig = input.perstackConfig;
70685
70696
  let checkpoint;
70686
70697
  if (input.resumeFrom) {
70687
70698
  if (!input.continueJob) {
@@ -70713,6 +70724,7 @@ async function resolveRunContext(input) {
70713
70724
  {
70714
70725
  name,
70715
70726
  version: expert.version ?? "1.0.0",
70727
+ minRuntimeVersion: expert.minRuntimeVersion,
70716
70728
  description: expert.description,
70717
70729
  instruction: expert.instruction,
70718
70730
  skills: expert.skills,
@@ -70771,7 +70783,7 @@ function parseInteractiveToolCallResultJson(query) {
70771
70783
 
70772
70784
  // ../../packages/tui/src/run-handler.ts
70773
70785
  var defaultEventListener = (event) => console.log(JSON.stringify(event));
70774
- async function runHandler(expertKey, query, options) {
70786
+ async function runHandler(expertKey, query, options, handlerOptions) {
70775
70787
  const input = parseWithFriendlyError(runCommandInputSchema, { expertKey, query, options });
70776
70788
  let eventListener = defaultEventListener;
70777
70789
  if (input.options.filter && input.options.filter.length > 0) {
@@ -70790,7 +70802,7 @@ async function runHandler(expertKey, query, options) {
70790
70802
  }
70791
70803
  try {
70792
70804
  const { perstackConfig, checkpoint, env, providerConfig, model, experts } = await resolveRunContext({
70793
- configPath: input.options.config,
70805
+ perstackConfig: handlerOptions.perstackConfig,
70794
70806
  provider: input.options.provider,
70795
70807
  model: input.options.model,
70796
70808
  envPath: input.options.envPath,
@@ -70799,8 +70811,7 @@ async function runHandler(expertKey, query, options) {
70799
70811
  resumeFrom: input.options.resumeFrom,
70800
70812
  expertKey: input.expertKey
70801
70813
  });
70802
- const lockfilePath = findLockfile();
70803
- const lockfile = lockfilePath ? loadLockfile(lockfilePath) ?? void 0 : void 0;
70814
+ const lockfile = handlerOptions.lockfile;
70804
70815
  const jobId = checkpoint?.jobId ?? input.options.jobId ?? createId();
70805
70816
  const runId = createId();
70806
70817
  await run(
@@ -72845,17 +72856,18 @@ async function startHandler(expertKey, query, options, handlerOptions) {
72845
72856
  const input = parseWithFriendlyError(startCommandInputSchema, { expertKey, query, options });
72846
72857
  try {
72847
72858
  const { perstackConfig, checkpoint, env, providerConfig, model, experts } = await resolveRunContext({
72848
- configPath: input.options.config,
72859
+ perstackConfig: handlerOptions.perstackConfig,
72849
72860
  provider: input.options.provider,
72850
72861
  model: input.options.model,
72851
72862
  envPath: input.options.envPath,
72852
72863
  continue: input.options.continue,
72853
72864
  continueJob: input.options.continueJob,
72854
72865
  resumeFrom: input.options.resumeFrom,
72855
- expertKey: input.expertKey,
72856
- perstackConfig: handlerOptions?.perstackConfig
72866
+ expertKey: input.expertKey
72857
72867
  });
72858
- if (handlerOptions?.additionalEnv) ;
72868
+ if (handlerOptions?.additionalEnv) {
72869
+ Object.assign(env, handlerOptions.additionalEnv(env));
72870
+ }
72859
72871
  const maxSteps = input.options.maxSteps ?? perstackConfig.maxSteps;
72860
72872
  const maxRetries = input.options.maxRetries ?? perstackConfig.maxRetries ?? defaultMaxRetries;
72861
72873
  const timeout = input.options.timeout ?? perstackConfig.timeout ?? defaultTimeout;
@@ -72907,8 +72919,7 @@ async function startHandler(expertKey, query, options, handlerOptions) {
72907
72919
  );
72908
72920
  return;
72909
72921
  }
72910
- const lockfilePath = findLockfile();
72911
- const lockfile = lockfilePath ? loadLockfile(lockfilePath) ?? void 0 : void 0;
72922
+ const lockfile = handlerOptions.lockfile;
72912
72923
  let currentQuery = selection.query;
72913
72924
  let currentJobId = currentCheckpoint?.jobId ?? input.options.jobId ?? createId();
72914
72925
  let isNextQueryInteractiveToolResult = input.options.interactiveToolCallResult ?? false;
@@ -72988,10 +72999,16 @@ async function startHandler(expertKey, query, options, handlerOptions) {
72988
72999
  // package.json
72989
73000
  var package_default2 = {
72990
73001
  name: "perstack",
72991
- version: "0.0.87",
73002
+ version: "0.0.88",
72992
73003
  description: "PerStack CLI"};
72993
73004
 
72994
73005
  // bin/cli.ts
73006
+ async function resolveConfigAndLockfile(configOption) {
73007
+ const perstackConfig = await getPerstackConfig(configOption);
73008
+ const lockfilePath = findLockfile(configOption);
73009
+ const lockfile = lockfilePath ? loadLockfile(lockfilePath) ?? void 0 : void 0;
73010
+ return { perstackConfig, lockfile };
73011
+ }
72995
73012
  var program = new Command().name(package_default2.name).description(package_default2.description).version(package_default2.version);
72996
73013
  program.command("start").description("Start Perstack with interactive TUI").argument("[expertKey]", "Expert key to run (optional, will prompt if not provided)").argument("[query]", "Query to run (optional, will prompt if not provided)").option("--config <configPath>", "Path to perstack.toml config file").option("--provider <provider>", "Provider to use").option("--model <model>", "Model to use").option(
72997
73014
  "--reasoning-budget <budget>",
@@ -73010,7 +73027,10 @@ program.command("start").description("Start Perstack with interactive TUI").argu
73010
73027
  ).option("--verbose", "Enable verbose logging").option("--continue", "Continue the most recent job with new query").option("--continue-job <jobId>", "Continue the specified job with new query").option(
73011
73028
  "--resume-from <checkpointId>",
73012
73029
  "Resume from a specific checkpoint (requires --continue or --continue-job)"
73013
- ).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").action((expertKey, query, options) => startHandler(expertKey, query, options));
73030
+ ).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").action(async (expertKey, query, options) => {
73031
+ const { perstackConfig, lockfile } = await resolveConfigAndLockfile(options.config);
73032
+ await startHandler(expertKey, query, options, { perstackConfig, lockfile });
73033
+ });
73014
73034
  program.command("run").description("Run Perstack with JSON output").argument("<expertKey>", "Expert key to run").argument("<query>", "Query to run").option("--config <configPath>", "Path to perstack.toml config file").option("--provider <provider>", "Provider to use").option("--model <model>", "Model to use").option(
73015
73035
  "--reasoning-budget <budget>",
73016
73036
  "Reasoning budget for native LLM reasoning (minimal, low, medium, high, or token count)"
@@ -73031,7 +73051,10 @@ program.command("run").description("Run Perstack with JSON output").argument("<e
73031
73051
  ).option("-i, --interactive-tool-call-result", "Query is interactive tool call result").option(
73032
73052
  "--filter <types>",
73033
73053
  "Filter events by type (comma-separated, e.g., completeRun,stopRunByError)"
73034
- ).action((expertKey, query, options) => runHandler(expertKey, query, options));
73054
+ ).action(async (expertKey, query, options) => {
73055
+ const { perstackConfig, lockfile } = await resolveConfigAndLockfile(options.config);
73056
+ await runHandler(expertKey, query, options, { perstackConfig, lockfile });
73057
+ });
73035
73058
  program.command("log").description("View execution history and events for debugging").option("--job <jobId>", "Show events for a specific job").option("--run <runId>", "Show events for a specific run").option("--checkpoint <checkpointId>", "Show checkpoint details").option("--step <step>", "Filter by step number (e.g., 5, >5, 1-10)").option("--type <type>", "Filter by event type").option("--errors", "Show error-related events only").option("--tools", "Show tool call events only").option("--delegations", "Show delegation events only").option("--filter <expression>", "Simple filter expression").option("--json", "Output as JSON").option("--pretty", "Pretty-print JSON output").option("--verbose", "Show full event details").option(
73036
73059
  "--take <n>",
73037
73060
  "Number of events to display (default: 100, use 0 for all)",
@@ -73050,7 +73073,11 @@ program.command("install").description("Generate perstack.lock with tool definit
73050
73073
  "Path to the environment file (can be specified multiple times)",
73051
73074
  (value, previous) => previous.concat(value),
73052
73075
  []
73053
- ).action((options) => installHandler(options));
73076
+ ).action(async (options) => {
73077
+ const configPath = await findConfigPath(options.config);
73078
+ const perstackConfig = await getPerstackConfig(options.config);
73079
+ await installHandler({ configPath, perstackConfig, envPath: options.envPath });
73080
+ });
73054
73081
  program.parse();
73055
73082
  /*! Bundled license information:
73056
73083