perstack 0.0.98 → 0.0.99

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,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "../chunk-D_gEzPfs.js";
3
- import { $ as never, A as startCommandInputSchema, At as defaultPerstackApiBaseUrl, B as ZodOptional$1, C as skipDelegates, Ct as defineLazy, D as stopRunByError, Dt as knownModels, E as stopRunByDelegate, Et as NEVER, F as isCoordinatorExpert, G as array$1, H as _instanceof, I as validateDelegation, J as discriminatedUnion, K as boolean, L as checkpointSchema, M as lockfileSchema, Mt as createId, N as jobSchema, O as stopRunByInteractiveTool, Ot as PerstackError, P as expertSchema, Q as looseObject, R as number$1, S as runSettingSchema, St as clone, T as startRun, Tt as $constructor, U as _null, V as _enum, W as any, X as lazy, Y as intersection, Z as literal, _ as proceedToInteractiveTools, _t as $ZodType, a as getFilteredEnv, at as strictObject, b as retry, bt as safeParse$1, c as createGeneralToolActivity, ct as union, d as continueToNextStep, dt as safeParseAsync$2, et as number, f as createRuntimeEvent, ft as datetime, g as parseExpertKey, gt as $ZodObject, h as finishToolCall, ht as meta$1, i as validateEventFilter, it as record, j as perstackConfigSchema, jt as defaultTimeout, k as runCommandInputSchema, kt as defaultMaxRetries, l as callTools, lt as unknown, m as finishMcpTools, mt as describe$1, n as parseWithFriendlyError, nt as optional, o as BASE_SKILL_PREFIX, ot as string, p as createStreamingEvent, pt as toJSONSchema, q as custom, r as createFilteredEventListener, rt as preprocess, s as createBaseToolActivity, st as tuple, t as createApiClient, tt as object$2, u as completeRun, ut as url, v as resolveToolResults, vt as parse$1, w as startGeneration, wt as normalizeParams, x as runParamsSchema, xt as safeParseAsync$1, y as resumeFromStop, yt as parseAsync, z as ZodIssueCode$1 } from "../dist-HjVmXsKn.js";
3
+ import { $ as lazy, A as runCommandInputSchema, At as PerstackError, B as resolveModelTier, C as runSettingSchema, Ct as safeParse$1, D as stopRunByDelegate, Dt as normalizeParams, E as startRun, Et as defineLazy, F as expertSchema, G as _instanceof, H as ZodIssueCode$1, I as isCoordinatorExpert, J as array$1, K as _null, L as validateDelegation, M as perstackConfigSchema, Mt as defaultPerstackApiBaseUrl, N as lockfileSchema, Nt as defaultTimeout, O as stopRunByError, Ot as $constructor, P as jobSchema, Pt as createId, Q as intersection, R as checkpointSchema, S as runParamsSchema, St as parseAsync, T as startGeneration, Tt as clone, U as ZodOptional$1, V as number$1, W as _enum, X as custom, Y as boolean, Z as discriminatedUnion, _ as parseExpertKey, _t as describe$1, a as validateEventFilter, at as optional, b as resumeFromStop, bt as $ZodType, c as createBaseToolActivity, ct as strictObject, d as completeRun, dt as union, et as literal, f as continueToNextStep, ft as unknown, g as finishToolCall, gt as toJSONSchema, h as finishMcpTools, ht as datetime, i as createFilteredEventListener, it as object$2, j as startCommandInputSchema, jt as defaultMaxRetries, k as stopRunByInteractiveTool, kt as NEVER, l as createGeneralToolActivity, lt as string, m as createStreamingEvent, mt as safeParseAsync$2, n as parseWithFriendlyError, nt as never, o as getFilteredEnv, ot as preprocess, p as createRuntimeEvent, pt as url, q as any, r as truncateText$1, rt as number, s as BASE_SKILL_PREFIX, st as record, t as createApiClient, tt as looseObject, u as callTools, ut as tuple, v as proceedToInteractiveTools, vt as meta$1, w as skipDelegates, wt as safeParseAsync$1, x as retry, xt as parse$1, y as resolveToolResults, yt as $ZodObject, z as knownModels } from "../dist-Bm8UQoRz.js";
4
4
  import { t as require_token_error } from "../token-error-_b-fOBh2.js";
5
5
  import fs, { constants, lstat, mkdir, open, readFile, stat, writeFile } from "node:fs/promises";
6
6
  import path, { dirname, extname } from "node:path";
@@ -16299,7 +16299,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
16299
16299
  //#endregion
16300
16300
  //#region ../base/package.json
16301
16301
  var name$5 = "@perstack/base";
16302
- var version$2 = "0.0.68";
16302
+ var version$2 = "0.0.70";
16303
16303
 
16304
16304
  //#endregion
16305
16305
  //#region ../base/src/tools/todo.ts
@@ -16428,8 +16428,8 @@ async function editTextFile(input) {
16428
16428
  await applyFileEdit(validatedPath, newText, oldText);
16429
16429
  return {
16430
16430
  path: validatedPath,
16431
- newText,
16432
- oldText
16431
+ newText: truncateText$1(newText),
16432
+ oldText: truncateText$1(oldText)
16433
16433
  };
16434
16434
  }
16435
16435
  function normalizeLineEndings(text) {
@@ -16479,7 +16479,7 @@ async function exec$2(input) {
16479
16479
  if (input.stdout) output += stdout;
16480
16480
  if (input.stderr) output += stderr;
16481
16481
  if (!output.trim()) output = "Command executed successfully, but produced no output.";
16482
- return { output };
16482
+ return { output: truncateText$1(output) };
16483
16483
  }
16484
16484
  function registerExec(server) {
16485
16485
  server.registerTool("exec", {
@@ -16510,8 +16510,8 @@ function registerExec(server) {
16510
16510
  } else if (error instanceof Error) message = error.message;
16511
16511
  else message = "An unknown error occurred.";
16512
16512
  const result = { error: message };
16513
- if (stdout && input.stdout) result.stdout = stdout;
16514
- if (stderr && input.stderr) result.stderr = stderr;
16513
+ if (stdout && input.stdout) result.stdout = truncateText$1(stdout);
16514
+ if (stderr && input.stderr) result.stderr = truncateText$1(stderr);
16515
16515
  return { content: [{
16516
16516
  type: "text",
16517
16517
  text: JSON.stringify(result)
@@ -16616,7 +16616,7 @@ async function readTextFile(input) {
16616
16616
  const toLine = to ?? lines.length;
16617
16617
  return {
16618
16618
  path,
16619
- content: lines.slice(fromLine, toLine).join("\n"),
16619
+ content: truncateText$1(lines.slice(fromLine, toLine).join("\n")),
16620
16620
  from: fromLine,
16621
16621
  to: toLine
16622
16622
  };
@@ -16784,7 +16784,7 @@ async function writeTextFile(input) {
16784
16784
  await safeWriteFile(validatedPath, text);
16785
16785
  return {
16786
16786
  path: validatedPath,
16787
- text
16787
+ text: truncateText$1(text)
16788
16788
  };
16789
16789
  }
16790
16790
  function registerWriteTextFile(server) {
@@ -21116,9 +21116,179 @@ async function buildOutput(fetcher, options, filterOptions, storagePath) {
21116
21116
  };
21117
21117
  }
21118
21118
 
21119
+ //#endregion
21120
+ //#region ../../packages/studio/src/client.ts
21121
+ function resolveApiKey(cliApiKey) {
21122
+ const apiKey = cliApiKey ?? process.env.PERSTACK_API_KEY;
21123
+ if (!apiKey) throw new PerstackError("PERSTACK_API_KEY is required. Set it as an environment variable or pass --api-key.");
21124
+ return apiKey;
21125
+ }
21126
+ function createStudioClient(options) {
21127
+ return createApiClient({
21128
+ apiKey: options.apiKey,
21129
+ baseUrl: options.baseUrl
21130
+ });
21131
+ }
21132
+
21133
+ //#endregion
21134
+ //#region ../../packages/studio/src/draft-handlers.ts
21135
+ async function expertListHandler(options) {
21136
+ const result = await createStudioClient({
21137
+ apiKey: resolveApiKey(options.apiKey),
21138
+ baseUrl: options.baseUrl
21139
+ }).expertDrafts.list({
21140
+ filter: options.filter,
21141
+ take: options.take,
21142
+ skip: options.skip
21143
+ });
21144
+ if (!result.ok) throw new PerstackError(`Failed to list drafts: ${result.error.message}`);
21145
+ const { data, meta } = result.data;
21146
+ if (data.length === 0) {
21147
+ console.log("No draft scopes found.");
21148
+ return;
21149
+ }
21150
+ console.log(`Draft scopes (${meta.total} total):\n`);
21151
+ for (const draft of data) {
21152
+ const version = draft.currentVersion?.version ?? "-";
21153
+ const refsCount = draft.draftRefs?.length ?? 0;
21154
+ console.log(` ${draft.name}`);
21155
+ console.log(` ID: ${draft.id}`);
21156
+ console.log(` Refs: ${refsCount} Version: ${version}`);
21157
+ console.log();
21158
+ }
21159
+ }
21160
+ async function expertCreateHandler(scopeName, options) {
21161
+ const result = await createStudioClient({
21162
+ apiKey: resolveApiKey(options.apiKey),
21163
+ baseUrl: options.baseUrl
21164
+ }).expertDrafts.create({
21165
+ scopeName,
21166
+ applicationId: options.app
21167
+ });
21168
+ if (!result.ok) throw new PerstackError(`Failed to create draft: ${result.error.message}`);
21169
+ const draft = result.data.data;
21170
+ console.log(`Draft scope created:`);
21171
+ console.log(` Name: ${draft.name}`);
21172
+ console.log(` ID: ${draft.id}`);
21173
+ }
21174
+ async function expertDeleteHandler(draftId, options) {
21175
+ const result = await createStudioClient({
21176
+ apiKey: resolveApiKey(options.apiKey),
21177
+ baseUrl: options.baseUrl
21178
+ }).expertDrafts.delete(draftId);
21179
+ if (!result.ok) throw new PerstackError(`Failed to delete draft: ${result.error.message}`);
21180
+ console.log(`Draft scope deleted: ${draftId}`);
21181
+ }
21182
+ async function expertPushHandler(draftId, options) {
21183
+ const client = createStudioClient({
21184
+ apiKey: resolveApiKey(options.apiKey),
21185
+ baseUrl: options.baseUrl
21186
+ });
21187
+ const perstackConfig = await getPerstackConfig(options.config);
21188
+ if (!perstackConfig.experts || Object.keys(perstackConfig.experts).length === 0) throw new PerstackError("No experts defined in perstack.toml");
21189
+ const experts = Object.entries(perstackConfig.experts).map(([key, configExpert]) => configExpertToExpert(key, configExpert));
21190
+ const result = await client.expertDrafts.refs.create(draftId, { experts });
21191
+ if (!result.ok) throw new PerstackError(`Failed to push experts: ${result.error.message}`);
21192
+ const { draftRef, definition } = result.data.data;
21193
+ const expertKeys = Object.keys(definition.experts);
21194
+ console.log(`Draft ref created:`);
21195
+ console.log(` Ref ID: ${draftRef.id}`);
21196
+ console.log(` Experts: ${expertKeys.join(", ")}`);
21197
+ }
21198
+ async function expertRefsHandler(draftId, options) {
21199
+ const result = await createStudioClient({
21200
+ apiKey: resolveApiKey(options.apiKey),
21201
+ baseUrl: options.baseUrl
21202
+ }).expertDrafts.refs.list(draftId, {
21203
+ take: options.take,
21204
+ skip: options.skip
21205
+ });
21206
+ if (!result.ok) throw new PerstackError(`Failed to list refs: ${result.error.message}`);
21207
+ const { data, meta } = result.data;
21208
+ if (data.length === 0) {
21209
+ console.log("No draft refs found.");
21210
+ return;
21211
+ }
21212
+ console.log(`Draft refs (${meta.total} total):\n`);
21213
+ for (const ref of data) {
21214
+ console.log(` ${ref.id}`);
21215
+ console.log(` Created: ${ref.createdAt}`);
21216
+ console.log();
21217
+ }
21218
+ }
21219
+
21220
+ //#endregion
21221
+ //#region ../../packages/studio/src/publish-handlers.ts
21222
+ async function expertPublishHandler(scopeName, options) {
21223
+ const result = await createStudioClient({
21224
+ apiKey: resolveApiKey(options.apiKey),
21225
+ baseUrl: options.baseUrl
21226
+ }).experts.publish(scopeName);
21227
+ if (!result.ok) throw new PerstackError(`Failed to publish: ${result.error.message}`);
21228
+ console.log(`Expert scope published: ${scopeName}`);
21229
+ }
21230
+ async function expertUnpublishHandler(scopeName, options) {
21231
+ const result = await createStudioClient({
21232
+ apiKey: resolveApiKey(options.apiKey),
21233
+ baseUrl: options.baseUrl
21234
+ }).experts.unpublish(scopeName);
21235
+ if (!result.ok) throw new PerstackError(`Failed to unpublish: ${result.error.message}`);
21236
+ console.log(`Expert scope unpublished: ${scopeName}`);
21237
+ }
21238
+ async function expertYankHandler(key, options) {
21239
+ const result = await createStudioClient({
21240
+ apiKey: resolveApiKey(options.apiKey),
21241
+ baseUrl: options.baseUrl
21242
+ }).experts.yank(key);
21243
+ if (!result.ok) throw new PerstackError(`Failed to yank: ${result.error.message}`);
21244
+ console.log(`Expert version yanked: ${key}`);
21245
+ }
21246
+
21247
+ //#endregion
21248
+ //#region ../../packages/studio/src/version-handlers.ts
21249
+ async function expertVersionHandler(draftId, refId, version, options) {
21250
+ const client = createStudioClient({
21251
+ apiKey: resolveApiKey(options.apiKey),
21252
+ baseUrl: options.baseUrl
21253
+ });
21254
+ let readme;
21255
+ if (options.readme) readme = await readFile(options.readme, "utf-8");
21256
+ const result = await client.expertDrafts.refs.assignVersion(draftId, refId, {
21257
+ version,
21258
+ tag: options.tag,
21259
+ readme
21260
+ });
21261
+ if (!result.ok) throw new PerstackError(`Failed to assign version: ${result.error.message}`);
21262
+ const { scope, version: ver } = result.data.data;
21263
+ console.log(`Version assigned:`);
21264
+ console.log(` Scope: ${scope.name}`);
21265
+ console.log(` Version: ${ver.version}`);
21266
+ console.log(` Tags: ${ver.tags.length > 0 ? ver.tags.join(", ") : "-"}`);
21267
+ }
21268
+ async function expertVersionsHandler(scopeName, options) {
21269
+ const result = await createStudioClient({
21270
+ apiKey: options.apiKey ?? process.env.PERSTACK_API_KEY,
21271
+ baseUrl: options.baseUrl
21272
+ }).experts.versions.list(scopeName);
21273
+ if (!result.ok) throw new PerstackError(`Failed to list versions: ${result.error.message}`);
21274
+ const { versions } = result.data.data;
21275
+ if (versions.length === 0) {
21276
+ console.log("No published versions found.");
21277
+ return;
21278
+ }
21279
+ console.log(`Versions for ${scopeName}:\n`);
21280
+ for (const ver of versions) {
21281
+ const tags = ver.tags.length > 0 ? ` [${ver.tags.join(", ")}]` : "";
21282
+ const yanked = ver.yanked ? " (yanked)" : "";
21283
+ console.log(` ${ver.version}${tags}${yanked}`);
21284
+ console.log(` Created: ${ver.createdAt}`);
21285
+ console.log();
21286
+ }
21287
+ }
21288
+
21119
21289
  //#endregion
21120
21290
  //#region ../../packages/runtime/package.json
21121
- var version$1 = "0.0.118";
21291
+ var version$1 = "0.0.121";
21122
21292
 
21123
21293
  //#endregion
21124
21294
  //#region ../../packages/runtime/src/helpers/usage.ts
@@ -77079,7 +77249,7 @@ function validateRuntimeVersion(experts) {
77079
77249
  //#endregion
77080
77250
  //#region ../../packages/runtime/src/helpers/setup-experts.ts
77081
77251
  async function setupExperts(setting, resolveExpertToRun) {
77082
- const resolveFn = resolveExpertToRun ?? (await import("../resolve-expert-CvhUOfWF.js")).resolveExpertToRun;
77252
+ const resolveFn = resolveExpertToRun ?? (await import("../resolve-expert-C4hjjIyE.js")).resolveExpertToRun;
77083
77253
  const { expertKey } = setting;
77084
77254
  const experts = { ...setting.experts };
77085
77255
  const clientOptions = {
@@ -90193,7 +90363,10 @@ async function resolvingToolResultLogic({ setting, checkpoint, step }) {
90193
90363
  type: "toolResultPart",
90194
90364
  toolCallId: toolResult.id,
90195
90365
  toolName: toolCall?.toolName ?? toolResult.toolName,
90196
- contents: toolResult.result.filter((part) => part.type === "textPart" || part.type === "imageInlinePart" || part.type === "fileInlinePart")
90366
+ contents: toolResult.result.filter((part) => part.type === "textPart" || part.type === "imageInlinePart" || part.type === "fileInlinePart").map((part) => part.type === "textPart" ? {
90367
+ ...part,
90368
+ text: truncateText$1(part.text)
90369
+ } : part)
90197
90370
  };
90198
90371
  }))] });
90199
90372
  }
@@ -90797,8 +90970,15 @@ var DelegationExecutor = class {
90797
90970
  async executeSingleDelegation(delegation, parentSetting, parentContext, parentExpert, runFn, parentOptions) {
90798
90971
  const { expert, toolCallId, toolName, query } = delegation;
90799
90972
  const delegateRunId = createId();
90973
+ let delegateModel = parentSetting.model;
90974
+ const delegateExpert = parentSetting.experts?.[expert.key];
90975
+ if (delegateExpert?.defaultModelTier) {
90976
+ const tierModel = resolveModelTier(parentSetting.providerConfig.providerName, delegateExpert.defaultModelTier);
90977
+ if (tierModel) delegateModel = tierModel;
90978
+ }
90800
90979
  const delegateSetting = {
90801
90980
  ...parentSetting,
90981
+ model: delegateModel,
90802
90982
  runId: delegateRunId,
90803
90983
  expertKey: expert.key,
90804
90984
  input: { text: query }
@@ -91195,7 +91375,8 @@ async function resolveRunContext(input) {
91195
91375
  instruction: expert.instruction,
91196
91376
  skills: expert.skills,
91197
91377
  delegates: expert.delegates,
91198
- tags: expert.tags
91378
+ tags: expert.tags,
91379
+ defaultModelTier: expert.defaultModelTier
91199
91380
  }];
91200
91381
  }));
91201
91382
  return {
@@ -91257,6 +91438,14 @@ async function runHandler(expertKey, query, options, handlerOptions) {
91257
91438
  resumeFrom: input.options.resumeFrom,
91258
91439
  expertKey: input.expertKey
91259
91440
  });
91441
+ let resolvedModel = model;
91442
+ if (!input.options.model) {
91443
+ const expertConfig = perstackConfig.experts?.[input.expertKey];
91444
+ if (expertConfig?.defaultModelTier) {
91445
+ const tierModel = resolveModelTier(providerConfig.providerName, expertConfig.defaultModelTier);
91446
+ if (tierModel) resolvedModel = tierModel;
91447
+ }
91448
+ }
91260
91449
  if (handlerOptions?.additionalEnv) Object.assign(env, handlerOptions.additionalEnv(env));
91261
91450
  const lockfile = handlerOptions.lockfile;
91262
91451
  await run({
@@ -91266,7 +91455,7 @@ async function runHandler(expertKey, query, options, handlerOptions) {
91266
91455
  expertKey: input.expertKey,
91267
91456
  input: input.options.interactiveToolCallResult ? parseInteractiveToolCallResultJson(input.query) ?? (checkpoint ? parseInteractiveToolCallResult(input.query, checkpoint) : { text: input.query }) : { text: input.query },
91268
91457
  experts,
91269
- model,
91458
+ model: resolvedModel,
91270
91459
  providerConfig,
91271
91460
  reasoningBudget: input.options.reasoningBudget ?? perstackConfig.reasoningBudget,
91272
91461
  maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
@@ -119490,6 +119679,14 @@ async function startHandler(expertKey, query, options, handlerOptions) {
119490
119679
  console.error(`Checkpoint expert key ${currentCheckpoint.expert.key} does not match input expert key ${selection.expertKey}`);
119491
119680
  return;
119492
119681
  }
119682
+ let resolvedModel = model;
119683
+ if (!input.options.model) {
119684
+ const expertConfig = perstackConfig.experts?.[selection.expertKey];
119685
+ if (expertConfig?.defaultModelTier) {
119686
+ const tierModel = resolveModelTier(providerConfig.providerName, expertConfig.defaultModelTier);
119687
+ if (tierModel) resolvedModel = tierModel;
119688
+ }
119689
+ }
119493
119690
  const lockfile = handlerOptions.lockfile;
119494
119691
  let currentQuery = input.query ?? null;
119495
119692
  let currentJobId = currentCheckpoint?.jobId ?? input.options.jobId ?? createId();
@@ -119504,7 +119701,7 @@ async function startHandler(expertKey, query, options, handlerOptions) {
119504
119701
  query: currentQuery ?? void 0,
119505
119702
  config: {
119506
119703
  runtimeVersion,
119507
- model,
119704
+ model: resolvedModel,
119508
119705
  maxRetries,
119509
119706
  timeout,
119510
119707
  contextWindowUsage: currentCheckpoint?.contextWindowUsage ?? 0
@@ -119519,7 +119716,7 @@ async function startHandler(expertKey, query, options, handlerOptions) {
119519
119716
  expertKey: selection.expertKey,
119520
119717
  input: isNextQueryInteractiveToolResult && currentCheckpoint ? parseInteractiveToolCallResult(resolvedQuery, currentCheckpoint) : { text: resolvedQuery },
119521
119718
  experts,
119522
- model,
119719
+ model: resolvedModel,
119523
119720
  providerConfig,
119524
119721
  reasoningBudget: input.options.reasoningBudget ?? perstackConfig.reasoningBudget,
119525
119722
  maxRetries: input.options.maxRetries ?? perstackConfig.maxRetries,
@@ -119556,7 +119753,7 @@ async function startHandler(expertKey, query, options, handlerOptions) {
119556
119753
  //#endregion
119557
119754
  //#region package.json
119558
119755
  var name = "perstack";
119559
- var version = "0.0.98";
119756
+ var version = "0.0.99";
119560
119757
  var description = "PerStack CLI";
119561
119758
 
119562
119759
  //#endregion
@@ -119592,6 +119789,59 @@ program.command("install").description("Generate perstack.lock with tool definit
119592
119789
  envPath: options.envPath
119593
119790
  });
119594
119791
  });
119792
+ function getParentOptions(cmd) {
119793
+ const parent = cmd.parent?.opts();
119794
+ return {
119795
+ apiKey: parent?.apiKey,
119796
+ baseUrl: parent?.baseUrl
119797
+ };
119798
+ }
119799
+ const expertCmd = program.command("expert").description("Manage experts on Perstack API").option("--api-key <key>", "Perstack API key (default: PERSTACK_API_KEY env)").option("--base-url <url>", "Custom API base URL");
119800
+ expertCmd.command("list").description("List draft scopes").option("--filter <name>", "Filter by name").option("--take <n>", "Limit results", Number.parseInt).option("--skip <n>", "Offset", Number.parseInt).action(async function(options) {
119801
+ await expertListHandler({
119802
+ ...getParentOptions(this),
119803
+ ...options
119804
+ });
119805
+ });
119806
+ expertCmd.command("create").description("Create a new draft scope").argument("<scopeName>", "Expert scope name").requiredOption("--app <id>", "Application ID").action(async function(scopeName, options) {
119807
+ await expertCreateHandler(scopeName, {
119808
+ ...getParentOptions(this),
119809
+ ...options
119810
+ });
119811
+ });
119812
+ expertCmd.command("delete").description("Delete a draft scope").argument("<draftId>", "Draft scope ID").action(async function(draftId) {
119813
+ await expertDeleteHandler(draftId, getParentOptions(this));
119814
+ });
119815
+ expertCmd.command("push").description("Push local expert definitions to a draft ref").argument("<draftId>", "Draft scope ID").option("--config <path>", "Path to perstack.toml config file").action(async function(draftId, options) {
119816
+ await expertPushHandler(draftId, {
119817
+ ...getParentOptions(this),
119818
+ ...options
119819
+ });
119820
+ });
119821
+ expertCmd.command("refs").description("List draft refs for a draft scope").argument("<draftId>", "Draft scope ID").option("--take <n>", "Limit results", Number.parseInt).option("--skip <n>", "Offset", Number.parseInt).action(async function(draftId, options) {
119822
+ await expertRefsHandler(draftId, {
119823
+ ...getParentOptions(this),
119824
+ ...options
119825
+ });
119826
+ });
119827
+ expertCmd.command("version").description("Assign a version to a draft ref").argument("<draftId>", "Draft scope ID").argument("<refId>", "Draft ref ID").argument("<version>", "Semantic version (e.g., 1.0.0)").option("--tag <tag>", "Version tag (e.g., latest)").option("--readme <path>", "Path to README file").action(async function(draftId, refId, version, options) {
119828
+ await expertVersionHandler(draftId, refId, version, {
119829
+ ...getParentOptions(this),
119830
+ ...options
119831
+ });
119832
+ });
119833
+ expertCmd.command("versions").description("List published versions for an expert scope").argument("<scopeName>", "Expert scope name").action(async function(scopeName) {
119834
+ await expertVersionsHandler(scopeName, getParentOptions(this));
119835
+ });
119836
+ expertCmd.command("publish").description("Make an expert scope public").argument("<scopeName>", "Expert scope name").action(async function(scopeName) {
119837
+ await expertPublishHandler(scopeName, getParentOptions(this));
119838
+ });
119839
+ expertCmd.command("unpublish").description("Make an expert scope private").argument("<scopeName>", "Expert scope name").action(async function(scopeName) {
119840
+ await expertUnpublishHandler(scopeName, getParentOptions(this));
119841
+ });
119842
+ expertCmd.command("yank").description("Deprecate a specific expert version").argument("<key>", "Expert key with version (e.g., my-expert@1.0.0)").action(async function(key) {
119843
+ await expertYankHandler(key, getParentOptions(this));
119844
+ });
119595
119845
  program.parseAsync().catch((error) => {
119596
119846
  if (error instanceof PerstackError) {
119597
119847
  console.error(error.message);