@promptbook/cli 0.89.0-15 โ†’ 0.89.0-16

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/esm/index.es.js CHANGED
@@ -46,7 +46,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
46
46
  * @generated
47
47
  * @see https://github.com/webgptorg/promptbook
48
48
  */
49
- const PROMPTBOOK_ENGINE_VERSION = '0.89.0-15';
49
+ const PROMPTBOOK_ENGINE_VERSION = '0.89.0-16';
50
50
  /**
51
51
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
52
52
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -106,6 +106,7 @@ const ADMIN_GITHUB_NAME = 'hejny';
106
106
  * @public exported from `@promptbook/core`
107
107
  */
108
108
  const CLAIM = `It's time for a paradigm shift. The future of software in plain English, French or Latin`;
109
+ // <- TODO: [๐ŸŠ] Pick the best claim
109
110
  /**
110
111
  * When the title is not provided, the default title is used
111
112
  *
@@ -136,6 +137,12 @@ const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
136
137
  * @private within the repository
137
138
  */
138
139
  const GENERATOR_WARNING_BY_PROMPTBOOK_CLI = `โš ๏ธ WARNING: This code has been generated by \`@promptbook/cli\` so that any manual changes will be overwritten`;
140
+ /**
141
+ * Warning message for the automatically generated sections of `.env` files
142
+ *
143
+ * @private within the repository
144
+ */
145
+ const GENERATOR_WARNING_IN_ENV = `Note: Added by Promptbook`;
139
146
  // <- TODO: [๐Ÿง ] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
140
147
  /**
141
148
  * The maximum number of iterations for a loops
@@ -216,7 +223,7 @@ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
216
223
  */
217
224
  const DEFAULT_BOOKS_DIRNAME = './books';
218
225
  // <- TODO: [๐Ÿ•] Make also `BOOKS_DIRNAME_ALTERNATIVES`
219
- // TODO: !!!!!! Just .promptbook dir, hardocode others
226
+ // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
220
227
  /**
221
228
  * Where to store the temporary downloads
222
229
  *
@@ -272,11 +279,20 @@ const MOMENT_ARG_THRESHOLDS = {
272
279
  ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
273
280
  };
274
281
  /**
275
- * @@@
282
+ * Available remote servers for the Promptbook
276
283
  *
277
284
  * @public exported from `@promptbook/core`
278
285
  */
279
- const DEFAULT_REMOTE_SERVER_URL = 'https://api.pavolhejny.com/promptbook';
286
+ const REMOTE_SERVER_URLS = [
287
+ 'https://s1.ptbk.io/promptbook',
288
+ 'https://api.pavolhejny.com/promptbook',
289
+ ];
290
+ /**
291
+ * Default remote server URL for the Promptbook
292
+ *
293
+ * @public exported from `@promptbook/core`
294
+ */
295
+ const DEFAULT_REMOTE_SERVER_URL = REMOTE_SERVER_URLS[0];
280
296
  // <- TODO: [๐Ÿงœโ€โ™‚๏ธ]
281
297
  /**
282
298
  * @@@
@@ -487,44 +503,42 @@ class WrappedError extends Error {
487
503
  constructor(whatWasThrown) {
488
504
  const tag = `[๐Ÿคฎ]`;
489
505
  console.error(tag, whatWasThrown);
490
- super(spaceTrim$1((block) => `
491
- ${ /* Fixing tests !!! block(valueToString(whatWasThrown)) */block(`non-Error object was thrown`)}
492
-
493
- Note: Look for ${tag} in the console for more details
494
- !!! Note: \`WrappedError\` indicates that somewhere in the code non-Error object was thrown and it was wrapped
495
-
496
- Please report issue on ${ADMIN_EMAIL}
506
+ super(spaceTrim$1(`
507
+ Non-Error object was thrown
497
508
 
498
- `));
509
+ Note: Look for ${tag} in the console for more details
510
+ Please report issue on ${ADMIN_EMAIL}
511
+ `));
499
512
  this.name = 'WrappedError';
500
513
  Object.setPrototypeOf(this, WrappedError.prototype);
501
514
  }
502
515
  }
503
516
 
504
517
  /**
505
- * !!!@@@
518
+ * Helper used in catch blocks to assert that the error is an instance of `Error`
506
519
  *
507
- * @param whatWasThrown !!!@@@
508
- * @returns !!!@@@
520
+ * @param whatWasThrown Any object that was thrown
521
+ * @returns Nothing if the error is an instance of `Error`
522
+ * @throws `WrappedError` or `UnexpectedError` if the error is not standard
509
523
  *
510
524
  * @private within the repository
511
525
  */
512
526
  function assertsError(whatWasThrown) {
513
- // Case 1: !!!@@@
527
+ // Case 1: Handle error which was rethrown as `WrappedError`
514
528
  if (whatWasThrown instanceof WrappedError) {
515
529
  const wrappedError = whatWasThrown;
516
530
  throw wrappedError;
517
531
  }
518
- // Case 2: !!!@@@
532
+ // Case 2: Handle unexpected errors
519
533
  if (whatWasThrown instanceof UnexpectedError) {
520
534
  const unexpectedError = whatWasThrown;
521
535
  throw unexpectedError;
522
536
  }
523
- // Case 3: !!!@@@
537
+ // Case 3: Handle standard errors - keep them up to consumer
524
538
  if (whatWasThrown instanceof Error) {
525
539
  return;
526
540
  }
527
- // Case 4: !!!@@@
541
+ // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
528
542
  throw new WrappedError(whatWasThrown);
529
543
  }
530
544
 
@@ -968,6 +982,40 @@ function $sideEffect(...sideEffectSubjects) {
968
982
  keepUnused(...sideEffectSubjects);
969
983
  }
970
984
 
985
+ /**
986
+ * Convert identification to Promptbook token
987
+ *
988
+ * @param identification
989
+ *
990
+ * @public exported from `@promptbook/core`
991
+ */
992
+ function identificationToPromptbookToken(identification) {
993
+ const { appId, userId, userToken } = identification;
994
+ const promptbookToken = `${appId}-${userId}-${userToken}`;
995
+ return promptbookToken;
996
+ }
997
+
998
+ /**
999
+ * Convert Promptbook token to identification
1000
+ *
1001
+ * @param promptbookToken
1002
+ *
1003
+ * @public exported from `@promptbook/core`
1004
+ */
1005
+ function promptbookTokenToIdentification(promptbookToken) {
1006
+ const [appId, userId, userToken] = promptbookToken.split('-');
1007
+ if (!appId || !userId || !userToken) {
1008
+ throw new Error(`Invalid promptbook token: ${promptbookToken}`);
1009
+ }
1010
+ const identification = {
1011
+ appId,
1012
+ userId,
1013
+ userToken,
1014
+ isAnonymous: false,
1015
+ };
1016
+ return identification;
1017
+ }
1018
+
971
1019
  /**
972
1020
  * Just marks a place of place where should be something implemented
973
1021
  * No side effects.
@@ -1093,7 +1141,7 @@ async function $provideEnvFilename() {
1093
1141
  */
1094
1142
 
1095
1143
  /**
1096
- * Stores data in .env variables (Remove !!! nonce 1)
1144
+ * Stores data in .env variables
1097
1145
  *
1098
1146
  * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes to `process.env`
1099
1147
  *
@@ -1151,15 +1199,19 @@ class $EnvStorage {
1151
1199
  async setItem(key, value) {
1152
1200
  const envFilename = await this.$provideOrCreateEnvFile();
1153
1201
  const envContent = await readFile(envFilename, 'utf-8');
1202
+ const transformedKey = this.transformKey(key);
1203
+ const updatedEnvContent = envContent
1204
+ .split('\n')
1205
+ .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
1206
+ .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
1207
+ .join('\n');
1154
1208
  const newEnvContent = spaceTrim((block) => `
1155
- ${block(envContent)}
1156
-
1157
- # Note: Added by Promptbook
1158
- ${this.transformKey(key)}=${JSON.stringify(value)}
1209
+ ${block(updatedEnvContent)}
1159
1210
 
1211
+ # ${GENERATOR_WARNING_IN_ENV}
1212
+ ${transformedKey}=${JSON.stringify(value)}
1160
1213
  `);
1161
- // <- TODO: !!! Add note and use spacetrim
1162
- writeFile(envFilename, newEnvContent, 'utf-8');
1214
+ await writeFile(envFilename, newEnvContent, 'utf-8');
1163
1215
  }
1164
1216
  /**
1165
1217
  * Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
@@ -1168,6 +1220,9 @@ class $EnvStorage {
1168
1220
  throw new NotYetImplementedError('Method `$EnvStorage.removeItem` not implemented.');
1169
1221
  }
1170
1222
  }
1223
+ /**
1224
+ * TODO: Write file more securely - ensure that there can be no accidental overwriting of existing variables and other content
1225
+ */
1171
1226
 
1172
1227
  /**
1173
1228
  * Orders JSON object by keys
@@ -2216,7 +2271,7 @@ class PipelineExecutionError extends Error {
2216
2271
  }
2217
2272
  }
2218
2273
  /**
2219
- * TODO: !!!!!! Add id to all errors
2274
+ * TODO: [๐Ÿง ][๐ŸŒ‚] Add id to all errors
2220
2275
  */
2221
2276
 
2222
2277
  /**
@@ -3158,19 +3213,27 @@ async function $provideLlmToolsForWizzardOrCli(options) {
3158
3213
  throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
3159
3214
  }
3160
3215
  options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
3161
- const { strategy, isCacheReloaded } = options;
3216
+ const { isLoginloaded, strategy, isCacheReloaded } = options;
3162
3217
  let llmExecutionTools;
3163
3218
  if (strategy === 'REMOTE_SERVER') {
3164
3219
  const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
3165
- const storage = new $EnvStorage(); // <- TODO: !!!!!! Save to `.promptbook` folder
3220
+ const storage = new $EnvStorage();
3166
3221
  let key = `PROMPTBOOK_TOKEN`;
3167
3222
  if (remoteServerUrl !== DEFAULT_REMOTE_SERVER_URL) {
3168
3223
  key = `${key}_${remoteServerUrl.replace(/^https?:\/\//i, '')}`;
3169
3224
  }
3170
- let identification = await storage.getItem(key);
3171
- if (identification === null) {
3225
+ let identification = null;
3226
+ let promptbookToken = await storage.getItem(key);
3227
+ if (promptbookToken === null || isLoginloaded) {
3172
3228
  identification = await loginPrompt();
3173
- await storage.setItem(key, identification);
3229
+ // Note: When login prompt fails, `process.exit(1)` is called so no need to check for null
3230
+ if (identification.isAnonymous === false) {
3231
+ promptbookToken = identificationToPromptbookToken(identification);
3232
+ await storage.setItem(key, promptbookToken);
3233
+ }
3234
+ }
3235
+ else {
3236
+ identification = promptbookTokenToIdentification(promptbookToken);
3174
3237
  }
3175
3238
  llmExecutionTools = new RemoteLlmExecutionTools({
3176
3239
  remoteServerUrl,
@@ -3250,8 +3313,8 @@ function isValidEmail(email) {
3250
3313
  /**
3251
3314
  * @private utility of CLI
3252
3315
  */
3253
- function $provideLlmToolsForCli(options) {
3254
- const { cliOptions: {
3316
+ async function $provideLlmToolsForCli(options) {
3317
+ const { isLoginloaded, cliOptions: {
3255
3318
  /* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
3256
3319
  let strategy;
3257
3320
  if (/^b/i.test(provider)) {
@@ -3265,7 +3328,11 @@ function $provideLlmToolsForCli(options) {
3265
3328
  process.exit(1);
3266
3329
  }
3267
3330
  if (strategy === 'BRING_YOUR_OWN_KEYS') {
3268
- return /* not await */ $provideLlmToolsForWizzardOrCli({ strategy, ...options });
3331
+ if (isLoginloaded) {
3332
+ throw new UnexpectedError(`\`$provideLlmToolsForCli\` isLoginloaded is not supported for strategy "BRING_YOUR_OWN_KEYS"`);
3333
+ }
3334
+ const llm = await $provideLlmToolsForWizzardOrCli({ strategy, ...options });
3335
+ return { strategy, llm };
3269
3336
  }
3270
3337
  else if (strategy === 'REMOTE_SERVER') {
3271
3338
  if (!isValidUrl(remoteServerUrlRaw)) {
@@ -3273,7 +3340,8 @@ function $provideLlmToolsForCli(options) {
3273
3340
  process.exit(1);
3274
3341
  }
3275
3342
  const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
3276
- return /* not await */ $provideLlmToolsForWizzardOrCli({
3343
+ const llm = await $provideLlmToolsForWizzardOrCli({
3344
+ isLoginloaded,
3277
3345
  strategy,
3278
3346
  appId: CLI_APP_ID,
3279
3347
  remoteServerUrl,
@@ -3283,6 +3351,10 @@ function $provideLlmToolsForCli(options) {
3283
3351
  console.log(colors.red(`You can not login to remote server in non-interactive mode`));
3284
3352
  process.exit(1);
3285
3353
  }
3354
+ console.info(colors.cyan(spaceTrim(`
3355
+ You will be logged in to ${remoteServerUrl}
3356
+ If you don't have an account, it will be created automatically.
3357
+ `)));
3286
3358
  const { username, password } = await prompts([
3287
3359
  {
3288
3360
  type: 'text',
@@ -3300,7 +3372,6 @@ function $provideLlmToolsForCli(options) {
3300
3372
  },
3301
3373
  ]);
3302
3374
  const loginUrl = `${remoteServerUrl}/login`;
3303
- console.log('!!!', { loginUrl });
3304
3375
  // TODO: [๐Ÿง ] Should we use normal `fetch` or `scraperFetch`
3305
3376
  const response = await promptbookFetch(loginUrl, {
3306
3377
  method: 'POST',
@@ -3313,20 +3384,7 @@ function $provideLlmToolsForCli(options) {
3313
3384
  password,
3314
3385
  }),
3315
3386
  });
3316
- console.log('!!!', {
3317
- loginUrl,
3318
- username,
3319
- password,
3320
- // type: response.type,
3321
- // text: await response.text(),
3322
- });
3323
3387
  const { isSuccess, message, error, identification } = (await response.json());
3324
- console.log('!!!', {
3325
- isSuccess,
3326
- message,
3327
- error,
3328
- identification,
3329
- });
3330
3388
  if (message) {
3331
3389
  if (isSuccess) {
3332
3390
  console.log(colors.green(message));
@@ -3347,6 +3405,7 @@ function $provideLlmToolsForCli(options) {
3347
3405
  return identification;
3348
3406
  },
3349
3407
  });
3408
+ return { strategy, llm };
3350
3409
  }
3351
3410
  else {
3352
3411
  throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
@@ -3368,11 +3427,12 @@ function $initializeListModelsCommand(program) {
3368
3427
  listModelsCommand.alias('models');
3369
3428
  listModelsCommand.alias('llm');
3370
3429
  listModelsCommand.action(handleActionErrors(async (cliOptions) => {
3371
- console.log('!!!', cliOptions);
3372
- // TODO: !!!!!! Not relevant for remote server and also for `about` command
3373
- const llm = await $provideLlmToolsForCli({ cliOptions });
3430
+ const { strategy, llm } = await $provideLlmToolsForCli({ cliOptions });
3374
3431
  $sideEffect(llm);
3375
3432
  // <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
3433
+ if (strategy !== 'BRING_YOUR_OWN_KEYS') {
3434
+ console.warn(colors.yellow(`You are using --strategy ${strategy} but models listed below are relevant for --strategy BRING_YOUR_OWN_KEYS`));
3435
+ }
3376
3436
  console.info($registeredLlmToolsMessage());
3377
3437
  return process.exit(0);
3378
3438
  }));
@@ -3900,6 +3960,7 @@ function $initializeListScrapersCommand(program) {
3900
3960
  `));
3901
3961
  listModelsCommand.alias('scrapers');
3902
3962
  listModelsCommand.action(handleActionErrors(async () => {
3963
+ // TODO: [๐ŸŒž] Do not allow on REMOTE_SERVER strategy
3903
3964
  const scrapers = await $provideScrapersForNode({});
3904
3965
  const executables = await $provideExecutablesForNode();
3905
3966
  console.info(spaceTrim((block) => `
@@ -3935,42 +3996,20 @@ function $initializeLoginCommand(program) {
3935
3996
  loginCommand.description(spaceTrim(`
3936
3997
  Login to the remote Promptbook server
3937
3998
  `));
3938
- loginCommand.action(handleActionErrors(async () => {
3939
- // @@@
3940
- console.error(colors.green(spaceTrim(`
3941
- You will be logged in to https://promptbook.studio server.
3942
- If you don't have an account, it will be created automatically.
3943
- `)));
3944
- // !!!!!!!!! Remove from here and use $provideLlmToolsForCli
3945
- const { email, password } = await prompts([
3946
- {
3947
- type: 'text',
3948
- name: 'email',
3949
- message: 'Enter your email:',
3950
- validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
3999
+ loginCommand.action(handleActionErrors(async (cliOptions) => {
4000
+ // Note: Not interested in return value of this function but the side effect of logging in
4001
+ await $provideLlmToolsForCli({
4002
+ isLoginloaded: true,
4003
+ cliOptions: {
4004
+ ...cliOptions,
4005
+ strategy: 'REMOTE_SERVER', // <- Note: Overriding strategy to `REMOTE_SERVER`
4006
+ // TODO: Do not allow flag `--strategy` in `login` command at all
3951
4007
  },
3952
- {
3953
- type: 'password',
3954
- name: 'password',
3955
- message: 'Enter your password:',
3956
- validate: (value) => value.length /* <- TODO: [๐Ÿง ] Better password validation */ > 0 ? true : 'Password is required',
3957
- },
3958
- ]);
3959
- TODO_USE(email, password);
3960
- await forTime(1000);
3961
- console.error(colors.green(spaceTrim(`
3962
- Your account ${email} was successfully created.
3963
-
3964
- Please verify your email:
3965
- https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
3966
-
3967
- After verification, you will receive 500 000 credits for free ๐ŸŽ‰
3968
- `)));
4008
+ });
3969
4009
  return process.exit(0);
3970
4010
  }));
3971
4011
  }
3972
4012
  /**
3973
- * TODO: Pass remote server URL (and path)
3974
4013
  * TODO: Implement non-interactive login
3975
4014
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
3976
4015
  * Note: [๐ŸŸก] Code in this file should never be published outside of `@promptbook/cli`
@@ -4930,8 +4969,8 @@ function createTask(options) {
4930
4969
  updatedAt = new Date();
4931
4970
  errors.push(...executionResult.errors);
4932
4971
  warnings.push(...executionResult.warnings);
4933
- // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
4934
- // TODO: [๐Ÿง ] !!! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
4972
+ // <- TODO: [๐ŸŒ‚] Only unique errors and warnings should be added (or filtered)
4973
+ // TODO: [๐Ÿง ] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
4935
4974
  // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
4936
4975
  // And delete `ExecutionTask.currentValue.preparedPipeline`
4937
4976
  assertsTaskSuccessful(executionResult);
@@ -11928,7 +11967,7 @@ function $initializeMakeCommand(program) {
11928
11967
  isCacheReloaded,
11929
11968
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
11930
11969
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
11931
- const llm = await $provideLlmToolsForCli({
11970
+ const { llm } = await $provideLlmToolsForCli({
11932
11971
  cliOptions,
11933
11972
  ...prepareAndScrapeOptions,
11934
11973
  });
@@ -12799,7 +12838,6 @@ function $initializeRunCommand(program) {
12799
12838
  runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
12800
12839
  runCommand.option('-s, --save-report <path>', `Save report to file`);
12801
12840
  runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
12802
- console.log('!!!', cliOptions);
12803
12841
  const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
12804
12842
  if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
12805
12843
  console.error(colors.red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
@@ -12825,7 +12863,7 @@ function $initializeRunCommand(program) {
12825
12863
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
12826
12864
  let llm;
12827
12865
  try {
12828
- llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
12866
+ llm = (await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions })).llm;
12829
12867
  }
12830
12868
  catch (error) {
12831
12869
  assertsError(error);
@@ -13717,7 +13755,7 @@ function $initializeStartServerCommand(program) {
13717
13755
  isCacheReloaded,
13718
13756
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13719
13757
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13720
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13758
+ const { /* [0] strategy,*/ llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13721
13759
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13722
13760
  const tools = {
13723
13761
  llm,
@@ -13749,6 +13787,7 @@ function $initializeStartServerCommand(program) {
13749
13787
  TODO_USE({ appId, userId });
13750
13788
  return llm;
13751
13789
  },
13790
+ // <- TODO: [๐Ÿง ][0] Maybe pass here strategy
13752
13791
  });
13753
13792
  keepUnused(server);
13754
13793
  // Note: Already logged by `startRemoteServer`
@@ -13790,7 +13829,7 @@ function $initializeTestCommand(program) {
13790
13829
  isCacheReloaded,
13791
13830
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13792
13831
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13793
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13832
+ const { llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13794
13833
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13795
13834
  tools = {
13796
13835
  llm,