@bike4mind/cli 0.17.1 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { $ as ProjectEvents, $t as parseRateLimitHeaders, A as GenerateImageToolCallSchema, At as dayjsConfig_default, B as InviteEvents, Bt as obfuscateApiKey, C as ElabsEvents, Ct as UnauthorizedError, D as ForbiddenError, Dt as VideoModels, E as FileEvents, Et as VideoGenerationUsageTransaction, F as ImageEditUsageTransaction, Ft as isGPTImageModel, G as ModalEvents, Gt as settingsMap, H as KnowledgeType, Ht as resolveNavigationIntents, I as ImageGenerationUsageTransaction, It as isModelAccessible, J as OpenAIEmbeddingModel, K as ModelBackend, Kt as substituteArguments$1, L as ImageModels, Lt as isSupportedEmbeddingModel, M as GenericCreditDeductTransaction, Mt as getMcpProviderMetadata, N as HTTPError, Nt as getViewById, O as FriendshipEvents, Ot as XAI_IMAGE_MODELS, P as HttpStatus, Pt as isGPTImage2Model, Q as ProfileEvents, Qt as isNearLimit, R as InboxEvents, Rt as isZodError, S as DashboardParamsSchema, St as UiNavigationEvents, T as FeedbackEvents, Tt as VIDEO_SIZE_CONSTRAINTS, U as LLMEvents, Ut as sanitizeTelemetryError, V as InviteType, Vt as parseSkillArguments, W as MiscEvents, Wt as secureParameters, X as Permission, Xt as buildRateLimitLogEntry, Y as OpenAIImageGenerationInput, Z as PermissionDeniedError, Zt as extractSnippetMeta, _ as ChatCompletionCreateInputSchema, _t as TaskScheduleHandler, a as ALERT_THRESHOLDS, at as ReceivedCreditTransaction, b as CompletionApiUsageTransaction, bt as ToolUsageTransaction, c as ApiKeyScope, ct as ResearchModeParamsSchema, d as ArtifactTypeSchema, dt as ResearchTaskType, en as CollectionType, et as PromptIntentSchema, f as AuthEvents, ft as SessionEvents, gt as TagType, h as BadRequestError, ht as SupportedFabFileMimeTypes, it as RealtimeVoiceUsageTransaction, j as GenericCreditAddTransaction, jt as getAccessibleDataLakes, k as GEMINI_IMAGE_MODELS, kt as b4mLLMTools, l as ApiKeyType, lt as ResearchTaskExecutionType, m as BFL_SAFETY_TOLERANCE, mt as SubscriptionCreditTransaction, n as logger, nt as PurchaseTransaction, o as AiEvents, ot as RechartsChartTypeList, p as BFL_IMAGE_MODELS, pt as SpeechToTextUsageTransaction, q as NotFoundError, qt as toDataLakeConfig, rt as QuestMasterParamsSchema, s as ApiKeyEvents, st as RegInviteEvents, t as ConfigStore, tt as PromptMetaZodSchema, u as AppFileEvents, ut as ResearchTaskPeriodicFrequencyType, v as ChatModels, vt as TextGenerationUsageTransaction, w as FavoriteDocumentType, wt as UnprocessableEntityError, x as CorruptedFileError, xt as TransferCreditTransaction, y as ClaudeArtifactMimeTypes, yt as TooManyRequestsError, z as InternalServerError, zt as mapMimeTypeToArtifactType } from "./ConfigStore-gV8aHo9b.mjs";
3
- import { a as isUserLockedOut, c as userCanDisableMFA, d as userRequiresMFA, f as verifyBackupCode, i as getLockoutTimeRemaining, l as userEligibleForMFA, n as generateBackupCodes, o as recordFailedAttempt, p as verifyTOTPToken, r as generateTOTPSetup, s as shouldResetFailedAttempts, t as clearFailedAttempts, u as userHasMFAConfigured } from "./utils-PpNti-tY.mjs";
2
+ import { $ as PermissionDeniedError, $t as extractSnippetMeta, A as FriendshipEvents, At as XAI_IMAGE_MODELS, B as InboxEvents, Bt as isZodError, C as CorruptedFileError, Ct as TransferCreditTransaction, D as FeedbackEvents, Dt as VIDEO_SIZE_CONSTRAINTS, E as FavoriteDocumentType, Et as UnprocessableEntityError, F as HTTPError, Ft as getViewById, G as LLMEvents, Gt as sanitizeTelemetryError, H as InviteEvents, Ht as obfuscateApiKey, I as HttpStatus, It as isGPTImage2Model, J as ModelBackend, Jt as substituteArguments$1, K as MiscEvents, Kt as secureParameters, L as ImageEditUsageTransaction, Lt as isGPTImageModel, M as GenerateImageToolCallSchema, Mt as dayjsConfig_default, N as GenericCreditAddTransaction, Nt as getAccessibleDataLakes, O as FileEvents, Ot as VideoGenerationUsageTransaction, P as GenericCreditDeductTransaction, Pt as getMcpProviderMetadata, Q as Permission, Qt as buildRateLimitLogEntry, R as ImageGenerationUsageTransaction, Rt as isModelAccessible, S as CompletionApiUsageTransaction, St as ToolUsageTransaction, T as ElabsEvents, Tt as UnauthorizedError, U as InviteType, Ut as parseSkillArguments, V as InternalServerError, Vt as mapMimeTypeToArtifactType, W as KnowledgeType, Wt as resolveNavigationIntents, X as OpenAIEmbeddingModel, Y as NotFoundError, Yt as toDataLakeConfig, Z as OpenAIImageGenerationInput, _ as BadRequestError, _t as SupportedFabFileMimeTypes, at as QuestMasterParamsSchema, b as ChatModels, bt as TextGenerationUsageTransaction, c as AiEvents, ct as RechartsChartTypeList, d as ApiKeyType, dt as ResearchTaskExecutionType, en as isNearLimit, et as ProfileEvents, f as AppFileEvents, ft as ResearchTaskPeriodicFrequencyType, g as BFL_SAFETY_TOLERANCE, gt as SubscriptionCreditTransaction, h as BFL_IMAGE_MODELS, ht as SpeechToTextUsageTransaction, it as PurchaseTransaction, j as GEMINI_IMAGE_MODELS, jt as b4mLLMTools, k as ForbiddenError, kt as VideoModels, l as ApiKeyEvents, lt as RegInviteEvents, m as AuthEvents, mt as SessionEvents, n as logger, nn as CollectionType, nt as PromptIntentSchema, ot as RealtimeVoiceUsageTransaction, p as ArtifactTypeSchema, pt as ResearchTaskType, q as ModalEvents, qt as settingsMap, rt as PromptMetaZodSchema, s as ALERT_THRESHOLDS, st as ReceivedCreditTransaction, t as ConfigStore, tn as parseRateLimitHeaders, tt as ProjectEvents, u as ApiKeyScope, ut as ResearchModeParamsSchema, vt as TagType, w as DashboardParamsSchema, wt as UiNavigationEvents, x as ClaudeArtifactMimeTypes, xt as TooManyRequestsError, y as ChatCompletionCreateInputSchema, yt as TaskScheduleHandler, z as ImageModels, zt as isSupportedEmbeddingModel } from "./ConfigStore-yJU1dxpP.mjs";
3
+ import { a as isUserLockedOut, c as userCanDisableMFA, d as userRequiresMFA, f as verifyBackupCode, i as getLockoutTimeRemaining, l as userEligibleForMFA, n as generateBackupCodes, o as recordFailedAttempt, p as verifyTOTPToken, r as generateTOTPSetup, s as shouldResetFailedAttempts, t as clearFailedAttempts, u as userHasMFAConfigured } from "./utils-fqhJmuB8.mjs";
4
4
  import { n as isPathAllowed, t as assertPathAllowed } from "./pathValidation-D8tjkQXE-1HwvsuYT.mjs";
5
- import { t as version } from "./package-Dzetdo6D.mjs";
5
+ import { t as version } from "./package-B3f78bSl.mjs";
6
6
  import { execFile, execFileSync, spawn } from "child_process";
7
7
  import crypto, { createHash, randomBytes, randomUUID } from "crypto";
8
8
  import { existsSync, promises, readFileSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "fs";
@@ -3300,6 +3300,12 @@ const MIME_TO_EXT = {
3300
3300
  };
3301
3301
  const INFINITE_VALUE = 14;
3302
3302
  const MAX_FILE_SIZE$2 = 6e3;
3303
+ /** Cap on generated images surfaced to the model for editing (keeps the context note small). */
3304
+ const MAX_RECENT_GENERATED_IMAGES = 6;
3305
+ /** Chars of the originating prompt kept per generated image, for context without bloat. */
3306
+ const RECENT_IMAGE_PROMPT_PREVIEW_CHARS = 120;
3307
+ /** quest.images also holds non-image generated artifacts (e.g. .xlsx); only these extensions are editable. */
3308
+ const EDITABLE_IMAGE_KEY_RE = /\.(jpe?g|png|webp|gif)$/i;
3303
3309
  const PREVIEW_CHUNK = 700;
3304
3310
  const CHARS_PER_TOKEN = 3.5;
3305
3311
  const MAX_IMAGE_DIMENSION_PX = 2e3;
@@ -3407,70 +3413,85 @@ async function fetchAndProcessPreviousMessages(session, historyCount = null, { d
3407
3413
  chatHistoryItems.splice(0, chatHistoryItems.length, ...filtered);
3408
3414
  }
3409
3415
  const oldestIncludedQuestId = chatHistoryItems[0]?.id ?? null;
3410
- return [
3411
- chatHistoryItems.reduce((acc, cur) => {
3412
- if (cur.prompt) acc.push({
3416
+ const convertedMessages = chatHistoryItems.reduce((acc, cur) => {
3417
+ if (cur.prompt) acc.push({
3418
+ role: "user",
3419
+ content: cur.prompt
3420
+ });
3421
+ if (cur.structuredReplies && cur.structuredReplies.length > 0) {
3422
+ for (const structuredReply of cur.structuredReplies) acc.push({
3423
+ role: "assistant",
3424
+ content: structuredReply.content
3425
+ });
3426
+ if (cur.toolResults && cur.toolResults.length > 0) acc.push({
3413
3427
  role: "user",
3414
- content: cur.prompt
3428
+ content: cur.toolResults.map((tr) => ({
3429
+ type: "tool_result",
3430
+ tool_use_id: tr.tool_use_id,
3431
+ content: tr.content,
3432
+ is_error: tr.is_error
3433
+ }))
3434
+ });
3435
+ } else if (cur.promptMeta?.functionCalls && cur.promptMeta.functionCalls.length > 0 && cur.promptMeta.functionCalls.some((fc) => fc.id)) {
3436
+ const textReply = cur.replies?.find((reply) => !reply.trim().startsWith("<think>")) || "";
3437
+ const assistantContent = [];
3438
+ if (textReply) assistantContent.push({
3439
+ type: "text",
3440
+ text: textReply
3415
3441
  });
3416
- if (cur.structuredReplies && cur.structuredReplies.length > 0) {
3417
- for (const structuredReply of cur.structuredReplies) acc.push({
3442
+ for (const fc of cur.promptMeta.functionCalls) if (fc.id && fc.name) assistantContent.push({
3443
+ type: "tool_use",
3444
+ id: fc.id,
3445
+ name: fc.name,
3446
+ input: fc.parameters || {}
3447
+ });
3448
+ if (assistantContent.length > 0) {
3449
+ acc.push({
3418
3450
  role: "assistant",
3419
- content: structuredReply.content
3451
+ content: assistantContent
3420
3452
  });
3421
- if (cur.toolResults && cur.toolResults.length > 0) acc.push({
3453
+ const toolResults = cur.promptMeta.functionCalls.filter((fc) => fc.id && fc.name).map((fc) => ({
3454
+ type: "tool_result",
3455
+ tool_use_id: fc.id,
3456
+ content: fc.returnValue ?? (fc.success === false ? "Tool execution failed" : ""),
3457
+ is_error: fc.success === false
3458
+ }));
3459
+ if (toolResults.length > 0) acc.push({
3422
3460
  role: "user",
3423
- content: cur.toolResults.map((tr) => ({
3424
- type: "tool_result",
3425
- tool_use_id: tr.tool_use_id,
3426
- content: tr.content,
3427
- is_error: tr.is_error
3428
- }))
3429
- });
3430
- } else if (cur.promptMeta?.functionCalls && cur.promptMeta.functionCalls.length > 0 && cur.promptMeta.functionCalls.some((fc) => fc.id)) {
3431
- const textReply = cur.replies?.find((reply) => !reply.trim().startsWith("<think>")) || "";
3432
- const assistantContent = [];
3433
- if (textReply) assistantContent.push({
3434
- type: "text",
3435
- text: textReply
3436
- });
3437
- for (const fc of cur.promptMeta.functionCalls) if (fc.id && fc.name) assistantContent.push({
3438
- type: "tool_use",
3439
- id: fc.id,
3440
- name: fc.name,
3441
- input: fc.parameters || {}
3442
- });
3443
- if (assistantContent.length > 0) {
3444
- acc.push({
3445
- role: "assistant",
3446
- content: assistantContent
3447
- });
3448
- const toolResults = cur.promptMeta.functionCalls.filter((fc) => fc.id && fc.name).map((fc) => ({
3449
- type: "tool_result",
3450
- tool_use_id: fc.id,
3451
- content: fc.returnValue ?? (fc.success === false ? "Tool execution failed" : ""),
3452
- is_error: fc.success === false
3453
- }));
3454
- if (toolResults.length > 0) acc.push({
3455
- role: "user",
3456
- content: toolResults
3457
- });
3458
- }
3459
- } else if (cur.replies && Array.isArray(cur.replies)) {
3460
- const validReply = cur.replies.find((reply) => !reply.trim().startsWith("<think>"));
3461
- if (validReply) acc.push({
3462
- role: "assistant",
3463
- content: validReply
3461
+ content: toolResults
3464
3462
  });
3465
3463
  }
3466
- return acc;
3467
- }, new Array()),
3464
+ } else if (cur.replies && Array.isArray(cur.replies)) {
3465
+ const validReply = cur.replies.find((reply) => !reply.trim().startsWith("<think>"));
3466
+ if (validReply) acc.push({
3467
+ role: "assistant",
3468
+ content: validReply
3469
+ });
3470
+ }
3471
+ return acc;
3472
+ }, new Array());
3473
+ const recentGeneratedImages = [];
3474
+ for (let i = chatHistoryItems.length - 1; i >= 0 && recentGeneratedImages.length < MAX_RECENT_GENERATED_IMAGES; i--) {
3475
+ const item = chatHistoryItems[i];
3476
+ if (!Array.isArray(item.images) || item.images.length === 0) continue;
3477
+ const prompt = (item.prompt ?? "").slice(0, RECENT_IMAGE_PROMPT_PREVIEW_CHARS);
3478
+ for (const key of item.images) {
3479
+ if (recentGeneratedImages.length >= MAX_RECENT_GENERATED_IMAGES) break;
3480
+ if (typeof key === "string" && EDITABLE_IMAGE_KEY_RE.test(key)) recentGeneratedImages.push({
3481
+ key,
3482
+ prompt
3483
+ });
3484
+ }
3485
+ }
3486
+ return [
3487
+ convertedMessages,
3468
3488
  chatHistoryItems.length,
3469
3489
  {
3470
3490
  cacheHit: fetchTime < 50,
3471
3491
  fetchTime,
3472
3492
  itemCount: chatHistoryItems.length,
3473
- oldestIncludedQuestId
3493
+ oldestIncludedQuestId,
3494
+ recentGeneratedImages
3474
3495
  }
3475
3496
  ];
3476
3497
  }
@@ -8822,6 +8843,36 @@ function sanitizeJsonStringWithMeta(jsonStr, options) {
8822
8843
  }
8823
8844
  //#endregion
8824
8845
  //#region ../../b4m-core/quantum/dist/index.mjs
8846
+ /**
8847
+ * Scheduling's objective is makespan (lower is better), rendered in time units.
8848
+ * This is the `ObjectiveMeta` every scheduling `SolverResult` carries so that
8849
+ * shared, family-agnostic UI can render scheduling results too.
8850
+ */
8851
+ const SCHEDULING_OBJECTIVE_META = {
8852
+ label: "makespan",
8853
+ unit: "t",
8854
+ direction: "min",
8855
+ format: { suffix: "t" }
8856
+ };
8857
+ /**
8858
+ * Build a scheduling `SolverResult` from the domain-native quantities a solver
8859
+ * produces (a schedule + its makespan), filling in the shared-contract fields.
8860
+ * Keeps the makespan→objective mapping in one place across all 11 solvers.
8861
+ */
8862
+ function makeSchedulingResult(args) {
8863
+ return {
8864
+ solverId: args.solverId,
8865
+ solverName: args.solverName,
8866
+ objective: args.makespan,
8867
+ internalCost: args.makespan,
8868
+ objectiveMeta: SCHEDULING_OBJECTIVE_META,
8869
+ solution: args.schedule,
8870
+ elapsedMs: args.elapsedMs,
8871
+ iterations: args.iterations,
8872
+ trace: args.trace,
8873
+ metadata: args.metadata
8874
+ };
8875
+ }
8825
8876
  const OperationSchema = z.object({
8826
8877
  jobId: z.number(),
8827
8878
  machineId: z.number(),
@@ -8899,19 +8950,19 @@ const greedySolver = {
8899
8950
  if (options?.onProgress) options.onProgress({
8900
8951
  solverId: "greedy",
8901
8952
  percentage: Math.round(opsScheduled / totalOps * 100),
8902
- bestMakespan: opEnd,
8953
+ bestObjective: opEnd,
8903
8954
  currentIteration: opsScheduled,
8904
8955
  totalIterations: totalOps
8905
8956
  });
8906
8957
  }
8907
- return {
8958
+ return makeSchedulingResult({
8908
8959
  solverId: "greedy",
8909
8960
  solverName: "Greedy (Earliest Start)",
8910
8961
  makespan: Math.max(...schedule.map((op) => op.endTime)),
8911
8962
  schedule,
8912
8963
  elapsedMs: performance.now() - startTime,
8913
8964
  iterations: totalOps
8914
- };
8965
+ });
8915
8966
  }
8916
8967
  };
8917
8968
  /**
@@ -9094,7 +9145,7 @@ const naiveSolver = {
9094
9145
  if (options?.onProgress && count % 100 === 0) options.onProgress({
9095
9146
  solverId: "naive",
9096
9147
  percentage: Math.min(99, Math.round(count / cappedTotal * 100)),
9097
- bestMakespan,
9148
+ bestObjective: bestMakespan,
9098
9149
  currentIteration: count,
9099
9150
  totalIterations: cappedTotal
9100
9151
  });
@@ -9102,18 +9153,18 @@ const naiveSolver = {
9102
9153
  options?.onProgress?.({
9103
9154
  solverId: "naive",
9104
9155
  percentage: 100,
9105
- bestMakespan,
9156
+ bestObjective: bestMakespan,
9106
9157
  currentIteration: count,
9107
9158
  totalIterations: cappedTotal
9108
9159
  });
9109
- return {
9160
+ return makeSchedulingResult({
9110
9161
  solverId: "naive",
9111
9162
  solverName: "Naive (Brute Force)",
9112
9163
  makespan: bestMakespan,
9113
9164
  schedule: bestSchedule,
9114
9165
  elapsedMs: performance.now() - startTime,
9115
9166
  iterations: count
9116
- };
9167
+ });
9117
9168
  }
9118
9169
  };
9119
9170
  function factorial(n) {
@@ -9166,19 +9217,19 @@ const randomRestartSolver = {
9166
9217
  options?.onProgress?.({
9167
9218
  solverId: "random-restart",
9168
9219
  percentage: Math.round((restart + 1) / RESTARTS * 100),
9169
- bestMakespan: globalBestMakespan,
9220
+ bestObjective: globalBestMakespan,
9170
9221
  currentIteration: restart + 1,
9171
9222
  totalIterations: RESTARTS
9172
9223
  });
9173
9224
  }
9174
- return {
9225
+ return makeSchedulingResult({
9175
9226
  solverId: "random-restart",
9176
9227
  solverName: "Random Restart Hill Climbing",
9177
9228
  makespan: globalBestMakespan,
9178
9229
  schedule: globalBestSchedule,
9179
9230
  elapsedMs: performance.now() - startTime,
9180
9231
  iterations: totalIterations
9181
- };
9232
+ });
9182
9233
  }
9183
9234
  };
9184
9235
  const SA_CONFIGS = [
@@ -9242,7 +9293,7 @@ function createSASolver(config) {
9242
9293
  if (options?.onProgress && i % progressInterval === 0) options.onProgress({
9243
9294
  solverId: config.id,
9244
9295
  percentage: Math.round(i / config.iterations * 100),
9245
- bestMakespan,
9296
+ bestObjective: bestMakespan,
9246
9297
  currentIteration: i,
9247
9298
  totalIterations: config.iterations
9248
9299
  });
@@ -9250,18 +9301,18 @@ function createSASolver(config) {
9250
9301
  options?.onProgress?.({
9251
9302
  solverId: config.id,
9252
9303
  percentage: 100,
9253
- bestMakespan,
9304
+ bestObjective: bestMakespan,
9254
9305
  currentIteration: config.iterations,
9255
9306
  totalIterations: config.iterations
9256
9307
  });
9257
- return {
9308
+ return makeSchedulingResult({
9258
9309
  solverId: config.id,
9259
9310
  solverName: config.name,
9260
9311
  makespan: bestMakespan,
9261
9312
  schedule: bestSchedule,
9262
9313
  elapsedMs: performance.now() - startTime,
9263
9314
  iterations: config.iterations
9264
- };
9315
+ });
9265
9316
  }
9266
9317
  };
9267
9318
  }
@@ -9328,7 +9379,7 @@ const tabuSolver = {
9328
9379
  if (options?.onProgress && iter % progressInterval === 0) options.onProgress({
9329
9380
  solverId: "tabu",
9330
9381
  percentage: Math.round(iter / ITERATIONS$1 * 100),
9331
- bestMakespan,
9382
+ bestObjective: bestMakespan,
9332
9383
  currentIteration: iter,
9333
9384
  totalIterations: ITERATIONS$1
9334
9385
  });
@@ -9336,18 +9387,18 @@ const tabuSolver = {
9336
9387
  options?.onProgress?.({
9337
9388
  solverId: "tabu",
9338
9389
  percentage: 100,
9339
- bestMakespan,
9390
+ bestObjective: bestMakespan,
9340
9391
  currentIteration: ITERATIONS$1,
9341
9392
  totalIterations: ITERATIONS$1
9342
9393
  });
9343
- return {
9394
+ return makeSchedulingResult({
9344
9395
  solverId: "tabu",
9345
9396
  solverName: "Tabu Search",
9346
9397
  makespan: bestMakespan,
9347
9398
  schedule: bestSchedule,
9348
9399
  elapsedMs: performance.now() - startTime,
9349
9400
  iterations: ITERATIONS$1
9350
- };
9401
+ });
9351
9402
  }
9352
9403
  };
9353
9404
  /**
@@ -9399,20 +9450,20 @@ const geneticAlgorithmSolver = {
9399
9450
  options?.onProgress?.({
9400
9451
  solverId: "genetic-algorithm",
9401
9452
  percentage: Math.round((gen + 1) / GENERATIONS * 100),
9402
- bestMakespan: bestIndividual.makespan,
9453
+ bestObjective: bestIndividual.makespan,
9403
9454
  currentIteration: gen + 1,
9404
9455
  totalIterations: GENERATIONS
9405
9456
  });
9406
9457
  }
9407
9458
  const bestSchedule = decodePermutation(bestIndividual.perm, problem);
9408
- return {
9459
+ return makeSchedulingResult({
9409
9460
  solverId: "genetic-algorithm",
9410
9461
  solverName: "Genetic Algorithm",
9411
9462
  makespan: bestIndividual.makespan,
9412
9463
  schedule: bestSchedule,
9413
9464
  elapsedMs: performance.now() - startTime,
9414
9465
  iterations: GENERATIONS * POPULATION_SIZE
9415
- };
9466
+ });
9416
9467
  }
9417
9468
  };
9418
9469
  function tournamentSelect(population, size, rng) {
@@ -9504,19 +9555,19 @@ const antColonySolver = {
9504
9555
  options?.onProgress?.({
9505
9556
  solverId: "ant-colony",
9506
9557
  percentage: Math.round((iter + 1) / ITERATIONS * 100),
9507
- bestMakespan,
9558
+ bestObjective: bestMakespan,
9508
9559
  currentIteration: iter + 1,
9509
9560
  totalIterations: ITERATIONS
9510
9561
  });
9511
9562
  }
9512
- return {
9563
+ return makeSchedulingResult({
9513
9564
  solverId: "ant-colony",
9514
9565
  solverName: "Ant Colony Optimization",
9515
9566
  makespan: bestMakespan,
9516
9567
  schedule: bestSchedule,
9517
9568
  elapsedMs: performance.now() - startTime,
9518
9569
  iterations: ITERATIONS * NUM_ANTS
9519
- };
9570
+ });
9520
9571
  }
9521
9572
  };
9522
9573
  /**
@@ -9792,7 +9843,7 @@ const highsSolver = {
9792
9843
  options?.onProgress?.({
9793
9844
  solverId: "highs",
9794
9845
  percentage,
9795
- bestMakespan
9846
+ bestObjective: bestMakespan
9796
9847
  });
9797
9848
  };
9798
9849
  reportProgress(0);
@@ -9842,14 +9893,14 @@ const highsSolver = {
9842
9893
  throw new Error(`[HiGHS] Solution validation failed: ${errorDetails}`);
9843
9894
  }
9844
9895
  reportProgress(100, makespan);
9845
- return {
9896
+ return makeSchedulingResult({
9846
9897
  solverId: "highs",
9847
9898
  solverName: "HiGHS (WASM)",
9848
9899
  makespan,
9849
9900
  schedule,
9850
9901
  elapsedMs: elapsed(startTime),
9851
9902
  iterations: 1
9852
- };
9903
+ });
9853
9904
  } catch (error) {
9854
9905
  reportProgress(0);
9855
9906
  throw error;
@@ -10496,26 +10547,27 @@ const allSolvers = [
10496
10547
  progress(0);
10497
10548
  const greedyResult = await greedySolver.solve(problem, {});
10498
10549
  progress(10);
10499
- const maxTime = greedyResult.makespan;
10500
- const encoded = encodeSchedulingWithMetadata(problem, maxTime);
10550
+ const greedyMakespan = greedyResult.objective;
10551
+ const greedySchedule = greedyResult.solution;
10552
+ const encoded = encodeSchedulingWithMetadata(problem, greedyMakespan);
10501
10553
  const numQubits = encoded.qubo.size;
10502
10554
  if (numQubits > MAX_QUBITS || numQubits === 0) {
10503
10555
  progress(100);
10504
- return {
10556
+ return makeSchedulingResult({
10505
10557
  solverId: "qaoa-local",
10506
10558
  solverName: "QAOA (Local)",
10507
- makespan: greedyResult.makespan,
10508
- schedule: greedyResult.schedule,
10559
+ makespan: greedyMakespan,
10560
+ schedule: greedySchedule,
10509
10561
  elapsedMs: elapsed(),
10510
10562
  metadata: {
10511
10563
  layers: LAYERS$1,
10512
10564
  shots: 0,
10513
10565
  gamma: 0,
10514
10566
  beta: 0,
10515
- rawMakespan: greedyResult.makespan,
10567
+ rawMakespan: greedyMakespan,
10516
10568
  usedFallback: true
10517
10569
  }
10518
- };
10570
+ });
10519
10571
  }
10520
10572
  const ising = quboToIsing(encoded.qubo);
10521
10573
  const backend = new LocalSimBackend();
@@ -10530,26 +10582,27 @@ const allSolvers = [
10530
10582
  const { probabilities } = await backend.run(numQubits, gates);
10531
10583
  const samples = sampleFromProbabilities(probabilities, FINAL_SHOTS$1);
10532
10584
  progress(90);
10533
- const candidates = [decodeFromArgmax(problem, encoded.variables, probabilities, greedyResult.schedule), decodeSamples(problem, encoded.variables, samples)].filter((d) => d !== null);
10585
+ const candidates = [decodeFromArgmax(problem, encoded.variables, probabilities, greedySchedule), decodeSamples(problem, encoded.variables, samples)].filter((d) => d !== null);
10534
10586
  const bestQuantum = candidates.length > 0 ? candidates.reduce((a, b) => b.makespan < a.makespan ? b : a) : null;
10535
- const usedFallback = bestQuantum === null || bestQuantum.makespan >= greedyResult.makespan;
10536
- const winner = usedFallback ? greedyResult : bestQuantum;
10587
+ const usedFallback = bestQuantum === null || bestQuantum.makespan >= greedyMakespan;
10588
+ const winnerMakespan = usedFallback ? greedyMakespan : bestQuantum.makespan;
10589
+ const winnerSchedule = usedFallback ? greedySchedule : bestQuantum.schedule;
10537
10590
  progress(100);
10538
- return {
10591
+ return makeSchedulingResult({
10539
10592
  solverId: "qaoa-local",
10540
10593
  solverName: "QAOA (Local)",
10541
- makespan: winner.makespan,
10542
- schedule: winner.schedule,
10594
+ makespan: winnerMakespan,
10595
+ schedule: winnerSchedule,
10543
10596
  elapsedMs: elapsed(),
10544
10597
  metadata: {
10545
10598
  layers: LAYERS$1,
10546
10599
  shots: FINAL_SHOTS$1,
10547
10600
  gamma,
10548
10601
  beta,
10549
- rawMakespan: bestQuantum?.makespan ?? greedyResult.makespan,
10602
+ rawMakespan: bestQuantum?.makespan ?? greedyMakespan,
10550
10603
  usedFallback
10551
10604
  }
10552
- };
10605
+ });
10553
10606
  }
10554
10607
  }
10555
10608
  ];
@@ -11228,7 +11281,7 @@ function continuousToy() {
11228
11281
  }
11229
11282
  schedulingToy(), routingToy(), packingToy(), assignmentToy(), networkToy(), partitioningToy(), selectionToy(), economicToy(), continuousToy();
11230
11283
  //#endregion
11231
- //#region ../../b4m-core/services/dist/tools-Dzibx4fx.mjs
11284
+ //#region ../../b4m-core/services/dist/tools-B2RLL9dT.mjs
11232
11285
  async function performDeepResearch(context, params, config = {}) {
11233
11286
  const maxDepth = config.maxDepth || 7;
11234
11287
  const duration = config.duration || 4.5;
@@ -12966,6 +13019,39 @@ async function getImageFromFileId(fileId, context) {
12966
13019
  if (fabFile.fileUrl) return fabFile.fileUrl;
12967
13020
  throw new Error(`File ${fileId} has no accessible URL`);
12968
13021
  }
13022
+ /**
13023
+ * Resolve a generated-image storage key (the bare key persisted in
13024
+ * `quest.images`, e.g. "86cdc650-….jpg") to a downloadable URL.
13025
+ *
13026
+ * image_generation / edit_image upload their output to `imageGenerateStorage`
13027
+ * and persist only the bare key — no fabFile record is created — so a generated
13028
+ * image is NOT addressable as a fabFile ObjectId. Resolving it against the image
13029
+ * bucket is what lets a follow-up edit ("make it cartoonish") target a
13030
+ * previously generated image. The model learns these keys from the "Recently
13031
+ * generated images" system note assembled in ChatCompletionProcess.
13032
+ */
13033
+ async function getGeneratedImageUrl(storageKey, context) {
13034
+ try {
13035
+ return await context.imageGenerateStorage.getSignedUrl(storageKey);
13036
+ } catch (error) {
13037
+ const detail = error instanceof Error ? error.message : String(error);
13038
+ throw new Error(`Could not resolve generated image "${storageKey}". Use the exact id from the "Recently generated images" system note, a fabFile ID from "Available Files", or a full URL. (${detail})`);
13039
+ }
13040
+ }
13041
+ /**
13042
+ * Resolve an image input (source or mask) to a downloadable URL. Accepts, in
13043
+ * priority order:
13044
+ * • an http(s)/data URL — passed straight through
13045
+ * • a fabFile ObjectId (24-char hex) — an uploaded image from "Available Files"
13046
+ * • otherwise a generated-image storage key (the bare key in quest.images,
13047
+ * e.g. "86cdc650-….jpg") — resolved against the image bucket
13048
+ * Source and mask share this so a generated-image key works for either.
13049
+ */
13050
+ async function resolveImageInputUrl(input, context) {
13051
+ if (input.startsWith("http://") || input.startsWith("https://") || input.startsWith("data:")) return input;
13052
+ if (/^[0-9a-fA-F]{24}$/.test(input)) return getImageFromFileId(input, context);
13053
+ return getGeneratedImageUrl(input, context);
13054
+ }
12969
13055
  async function processAndStoreImage(imageUrl, context) {
12970
13056
  const buffer = await downloadImage(imageUrl);
12971
13057
  const fileType = await fileTypeFromBuffer(buffer);
@@ -13039,17 +13125,9 @@ Please select a supported edit model in your image settings modal.`;
13039
13125
  quality: imageConfig?.quality,
13040
13126
  prompt
13041
13127
  });
13042
- let sourceImageUrl;
13043
- if (toolImage.startsWith("http://") || toolImage.startsWith("https://") || toolImage.startsWith("data:")) sourceImageUrl = toolImage;
13044
- else sourceImageUrl = await getImageFromFileId(toolImage, context);
13045
- const sourceBase64Image = await imageUrlToBase64(sourceImageUrl);
13128
+ const sourceBase64Image = await imageUrlToBase64(await resolveImageInputUrl(toolImage, context));
13046
13129
  let maskBase64Image = null;
13047
- if (toolMask) {
13048
- let maskImageUrl;
13049
- if (toolMask.startsWith("http://") || toolMask.startsWith("https://") || toolMask.startsWith("data:")) maskImageUrl = toolMask;
13050
- else maskImageUrl = await getImageFromFileId(toolMask, context);
13051
- maskBase64Image = await imageUrlToBase64(maskImageUrl);
13052
- }
13130
+ if (toolMask) maskBase64Image = await imageUrlToBase64(await resolveImageInputUrl(toolMask, context));
13053
13131
  if (isBFLModel) {
13054
13132
  const service = new BFLImageService(await (0, apiKeyService_exports.getEffectiveApiKey)(context.userId, { type: ApiKeyType.bfl }, { db: context.db }), context.logger, context.imageProcessorLambdaName);
13055
13133
  let bflModel = editModel;
@@ -13143,13 +13221,13 @@ Please check your BFL API key in settings and ensure it is configured correctly.
13143
13221
  },
13144
13222
  toolSchema: {
13145
13223
  name: "edit_image",
13146
- description: "Edit an existing image based on a text prompt. Use this when the user wants to modify, change, edit, or transform an image they have uploaded or attached to the conversation. Supports removing backgrounds, changing colors, adding/removing objects, and other visual modifications.",
13224
+ description: "Edit an existing image based on a text prompt. Use this when the user wants to modify, change, edit, or transform an image — whether they uploaded/attached it OR it was generated earlier in this conversation (e.g. \"make the previous image more cartoonish\", \"adjust the angle\"). Supports removing backgrounds, changing colors, adding/removing objects, and other visual modifications.",
13147
13225
  parameters: {
13148
13226
  type: "object",
13149
13227
  properties: {
13150
13228
  image: {
13151
13229
  type: "string",
13152
- description: "The file ID of the image to edit (e.g., \"67abc123def456\"). Look for image file IDs in the \"Available Files\" system message. You can also use an S3 URL or data URL if provided by the user."
13230
+ description: "The image to edit. Provide one of: the exact id of a previously generated image from the \"Recently generated images\" system note (e.g. \"86cdc650-43d2-416e-aca6-23ff4fe23081.jpg\"); a fabFile ID of an uploaded image from the \"Available Files\" system message (e.g. \"67abc123def456\"); or a full http(s)/data URL."
13153
13231
  },
13154
13232
  prompt: {
13155
13233
  type: "string",
@@ -13613,9 +13691,12 @@ const getWikipediaOnThisDay = async (parameters = {}) => {
13613
13691
  try {
13614
13692
  const { month, day } = parseMonthDay(date);
13615
13693
  const url = `https://en.wikipedia.org/api/rest_v1/feed/onthisday/${type}/${month}/${day}`;
13694
+ const brand = process.env.APP_NAME || "";
13695
+ const websiteUrl = process.env.WEBSITE_URL || "";
13696
+ const userAgent = brand ? `${brand}/1.0${websiteUrl ? ` (${websiteUrl})` : ""}` : "App/1.0";
13616
13697
  const response = await fetch(url, { headers: {
13617
13698
  Accept: "application/json",
13618
- "User-Agent": "Bike4Mind/1.0 (https://bike4mind.com; contact@bike4mind.com)"
13699
+ "User-Agent": userAgent
13619
13700
  } });
13620
13701
  if (!response.ok) {
13621
13702
  if (response.status === 404) throw new Error(`No data available for ${month}-${day}. The date may be invalid.`);
@@ -15229,13 +15310,13 @@ const knowledgeBaseRetrieveTool = {
15229
15310
  function formatResult$1(result) {
15230
15311
  const lines = [
15231
15312
  `Solver: ${result.solverName} (${result.solverId})`,
15232
- `Makespan: ${result.makespan}`,
15313
+ `Makespan: ${result.objective}`,
15233
15314
  `Elapsed: ${result.elapsedMs.toFixed(1)}ms`
15234
15315
  ];
15235
15316
  if (result.iterations !== void 0) lines.push(`Iterations: ${result.iterations}`);
15236
15317
  lines.push("Schedule:");
15237
15318
  const byMachine = /* @__PURE__ */ new Map();
15238
- for (const op of result.schedule) {
15319
+ for (const op of result.solution) {
15239
15320
  if (!byMachine.has(op.machineId)) byMachine.set(op.machineId, []);
15240
15321
  byMachine.get(op.machineId).push(op);
15241
15322
  }
@@ -15272,13 +15353,13 @@ async function runQuantumSchedule(params) {
15272
15353
  }
15273
15354
  }
15274
15355
  if (results.length === 0) return `Error: No solvers completed successfully.\n${errors.join("\n")}`;
15275
- results.sort((a, b) => a.makespan - b.makespan);
15356
+ results.sort((a, b) => a.objective - b.objective);
15276
15357
  const lines = [];
15277
15358
  lines.push(`## Scheduling Results for "${problem.name}"`);
15278
15359
  lines.push(`Problem: ${problem.jobs.length} jobs, ${problem.machines.length} machines, ${problem.jobs.reduce((s, j) => s + j.operations.length, 0)} operations`);
15279
15360
  lines.push("");
15280
15361
  if (results.length > 1) {
15281
- lines.push(`### Winner: ${results[0].solverName} (makespan: ${results[0].makespan})`);
15362
+ lines.push(`### Winner: ${results[0].solverName} (makespan: ${results[0].objective})`);
15282
15363
  lines.push("");
15283
15364
  }
15284
15365
  for (const result of results) {
@@ -16053,7 +16134,8 @@ function applyCellStyle(cell, style) {
16053
16134
  */
16054
16135
  async function generateExcel(params) {
16055
16136
  const workbook = new ExcelJS.Workbook();
16056
- workbook.creator = "Bike4Mind AI";
16137
+ const brand = process.env.APP_NAME || "";
16138
+ workbook.creator = brand ? `${brand} AI` : "AI";
16057
16139
  workbook.created = /* @__PURE__ */ new Date();
16058
16140
  for (const sheetData of params.sheets) {
16059
16141
  const worksheet = workbook.addWorksheet(sheetData.name.slice(0, LIMITS.MAX_SHEET_NAME_LENGTH));
@@ -16118,7 +16200,18 @@ const excelGenerationTool = {
16118
16200
  },
16119
16201
  toolSchema: {
16120
16202
  name: "excel_generation",
16121
- description: `Generate Excel (.xlsx) files with formatting. Supports: multiple sheets, formulas (SUM, AVERAGE, IF, etc.), styling (bold, colors, borders), number formats, merged cells, frozen panes. Limits: max ${LIMITS.MAX_SHEETS} sheets, ${LIMITS.MAX_CELLS_PER_SHEET} cells/sheet, rows 1-${LIMITS.MAX_ROW}, cols 1-${LIMITS.MAX_COL}.`,
16203
+ description: `Generate a well-formed Excel (.xlsx) workbook. Supports: multiple sheets, formulas (SUM, AVERAGE, IF, VLOOKUP, etc.; only a safe whitelisted subset), styling (bold, colors, borders), number formats, merged cells, frozen panes.
16204
+
16205
+ HARD LIMITS (the request is REJECTED if any are exceeded, not truncated, so data is never silently dropped):
16206
+ - At most ${LIMITS.MAX_SHEETS} sheets per workbook.
16207
+ - At most ${LIMITS.MAX_CELLS_PER_SHEET} populated cells per sheet (count the cell objects you pass in "data", not the grid area).
16208
+ - Row numbers 1-${LIMITS.MAX_ROW} and column numbers 1-${LIMITS.MAX_COL} only.
16209
+ - Sheet names: 1-${LIMITS.MAX_SHEET_NAME_LENGTH} characters.
16210
+ - Formulas may only use whitelisted functions; volatile/external ones (HYPERLINK, WEBSERVICE, CMD, etc.) are blocked.
16211
+
16212
+ Addressing is 1-indexed numeric row/col (row 1, col 1 = cell A1); do NOT pass A1-style strings. Provide only the cells you want populated; empty cells need no entry.
16213
+
16214
+ Before calling: if the user's request would exceed any limit (e.g. a dataset larger than ${LIMITS.MAX_CELLS_PER_SHEET} cells or more than ${LIMITS.MAX_SHEETS} sheets), do not promise the full result; tell the user what you can deliver within these limits and either split the data across sheets/files or summarize. Only commit to what this tool can actually produce.`,
16122
16215
  parameters: {
16123
16216
  type: "object",
16124
16217
  properties: {
@@ -17695,7 +17788,7 @@ var mfaService_exports$1 = /* @__PURE__ */ __exportAll$3({
17695
17788
  * This generates the secret and backup codes but doesn't enable MFA yet
17696
17789
  * The user must verify the setup before MFA is enabled
17697
17790
  */
17698
- async function setupMFA({ user, appName = "Bike4Mind" }, userRepository) {
17791
+ async function setupMFA({ user, appName = process.env.APP_NAME || "" }, userRepository) {
17699
17792
  if (!userEligibleForMFA(user)) throw new Error("User is not eligible for MFA setup.");
17700
17793
  if (user.mfa && user.mfa.totpEnabled) throw new Error("MFA is already enabled for this user.");
17701
17794
  if (user.mfa && user.mfa.totpEnabled === false) user.mfa = null;
@@ -17725,7 +17818,7 @@ async function setupMFA({ user, appName = "Bike4Mind" }, userRepository) {
17725
17818
  async function verifyMFASetup(user, token, userRepository) {
17726
17819
  if (!user.mfa || !user.mfa.totpSecret) throw new Error("No MFA setup in progress for this user.");
17727
17820
  if (user.mfa.totpEnabled) throw new Error("MFA is already enabled for this user.");
17728
- const { verifyTOTPToken } = await import("./utils-BGtSXfce.mjs");
17821
+ const { verifyTOTPToken } = await import("./utils-CLjLKvqQ.mjs");
17729
17822
  if (!verifyTOTPToken(user.mfa.totpSecret, token)) throw new Error("Invalid TOTP code.");
17730
17823
  const updatedMFA = { ...user.mfa };
17731
17824
  updatedMFA.totpEnabled = true;
@@ -20146,6 +20239,7 @@ z.object({
20146
20239
  surface: z.string().optional(),
20147
20240
  enabledTools: z.array(z.string()).optional(),
20148
20241
  disabledTools: z.array(z.string()).optional(),
20242
+ disableUserIntegrations: z.boolean().optional(),
20149
20243
  forceKnowledgeRetrieval: z.boolean().optional(),
20150
20244
  retrievalTags: z.array(z.string()).optional(),
20151
20245
  citationStyle: z.enum(["named", "indexed"]).optional(),
@@ -20160,8 +20254,7 @@ z.object({
20160
20254
  clonedSourceId: z.string().optional().nullable(),
20161
20255
  forkedSourceId: z.string().optional().nullable(),
20162
20256
  projectId: z.string().optional(),
20163
- lastUsedModel: z.string().optional().nullable(),
20164
- optiHashi: z.boolean().optional()
20257
+ lastUsedModel: z.string().optional().nullable()
20165
20258
  });
20166
20259
  z.object({ id: z.string() });
20167
20260
  z.object({ id: z.string() });