@bike4mind/cli 0.2.31-b4m-cli-undo-command.19534 → 0.2.31-b4m-cli-undo-command.19598

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import "./chunk-GQGOWACU.js";
3
- import "./chunk-F4PXVLZX.js";
4
- import "./chunk-ERV5G6MX.js";
3
+ import "./chunk-4P27WV34.js";
4
+ import "./chunk-S6AUIWWB.js";
5
5
  import "./chunk-BPFEGDC7.js";
6
6
  import "./chunk-BDQBOLYG.js";
7
7
  import {
8
8
  getEffectiveApiKey,
9
9
  getOpenWeatherKey,
10
10
  getSerperKey
11
- } from "./chunk-JWJF6O4L.js";
11
+ } from "./chunk-DQHCE3TN.js";
12
12
  import {
13
13
  ConfigStore,
14
14
  logger
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  checkForUpdate,
18
18
  package_default
19
- } from "./chunk-WVFOWKNW.js";
19
+ } from "./chunk-BXNVLTPU.js";
20
20
  import {
21
21
  selectActiveBackgroundAgents,
22
22
  useCliStore
@@ -32,7 +32,7 @@ import {
32
32
  OpenAIBackend,
33
33
  OpenAIImageService,
34
34
  XAIImageService
35
- } from "./chunk-3SPW5FYJ.js";
35
+ } from "./chunk-PV6PZFPC.js";
36
36
  import {
37
37
  AiEvents,
38
38
  ApiKeyEvents,
@@ -90,7 +90,7 @@ import {
90
90
  getMcpProviderMetadata,
91
91
  getViewById,
92
92
  resolveNavigationIntents
93
- } from "./chunk-NI22LIK3.js";
93
+ } from "./chunk-PLA2VBQW.js";
94
94
  import {
95
95
  Logger
96
96
  } from "./chunk-PFBYGCOW.js";
@@ -1368,11 +1368,11 @@ var JobItem = React8.memo(function JobItem2({
1368
1368
  job,
1369
1369
  indented = false
1370
1370
  }) {
1371
- const elapsed = Math.round((Date.now() - job.startTime) / 1e3);
1371
+ const elapsed2 = Math.round((Date.now() - job.startTime) / 1e3);
1372
1372
  const maxTaskLength = indented ? 50 : 60;
1373
1373
  const taskPreview = job.task.length > maxTaskLength ? job.task.slice(0, maxTaskLength - 3) + "..." : job.task;
1374
1374
  const isQueued = job.status === "queued";
1375
- return /* @__PURE__ */ React8.createElement(Box7, null, indented && /* @__PURE__ */ React8.createElement(Text7, null, " "), isQueued ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u23F3") : /* @__PURE__ */ React8.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner2, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text7, { color: isQueued ? "yellow" : "blue" }, " ", job.agentName), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, " ", "[", job.id, "] ", taskPreview, " ", isQueued ? "(queued)" : `(${elapsed}s)`));
1375
+ return /* @__PURE__ */ React8.createElement(Box7, null, indented && /* @__PURE__ */ React8.createElement(Text7, null, " "), isQueued ? /* @__PURE__ */ React8.createElement(Text7, { color: "yellow" }, "\u23F3") : /* @__PURE__ */ React8.createElement(Text7, { color: "blue" }, /* @__PURE__ */ React8.createElement(Spinner2, { type: "dots" })), /* @__PURE__ */ React8.createElement(Text7, { color: isQueued ? "yellow" : "blue" }, " ", job.agentName), /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, " ", "[", job.id, "] ", taskPreview, " ", isQueued ? "(queued)" : `(${elapsed2}s)`));
1376
1376
  });
1377
1377
  function formatStatusCounts(jobs) {
1378
1378
  let running = 0;
@@ -2912,13 +2912,16 @@ var CheckpointStore = class {
2912
2912
  try {
2913
2913
  let hasChanges = false;
2914
2914
  for (const filePath of filePaths) {
2915
- const absolutePath = path6.resolve(this.projectDir, filePath);
2915
+ const absolutePath = this.validatePathWithinProject(filePath);
2916
2916
  const shadowPath = path6.join(this.shadowRepoDir, filePath);
2917
2917
  const shadowDir = path6.dirname(shadowPath);
2918
2918
  const absentMarkerPath = path6.join(shadowDir, `${path6.basename(filePath)}${ABSENT_MARKER}`);
2919
2919
  await fs5.mkdir(shadowDir, { recursive: true });
2920
2920
  if (existsSync4(absolutePath)) {
2921
- const stats = await fs5.stat(absolutePath);
2921
+ const stats = await fs5.lstat(absolutePath);
2922
+ if (stats.isSymbolicLink()) {
2923
+ continue;
2924
+ }
2922
2925
  if (stats.size > MAX_FILE_SIZE2) {
2923
2926
  continue;
2924
2927
  }
@@ -2995,7 +2998,7 @@ var CheckpointStore = class {
2995
2998
  throw new Error(`Checkpoint #${index} not found. Use /checkpoints to see available restore points.`);
2996
2999
  }
2997
3000
  for (const filePath of checkpoint.filePaths) {
2998
- const absolutePath = path6.resolve(this.projectDir, filePath);
3001
+ const absolutePath = this.validatePathWithinProject(filePath);
2999
3002
  try {
3000
3003
  const content = this.git("show", `${checkpoint.id}:${filePath}`);
3001
3004
  await fs5.mkdir(path6.dirname(absolutePath), { recursive: true });
@@ -3031,7 +3034,9 @@ var CheckpointStore = class {
3031
3034
  }
3032
3035
  const diffParts = [];
3033
3036
  for (const filePath of checkpoint.filePaths) {
3034
- const absolutePath = path6.resolve(this.projectDir, filePath);
3037
+ const absolutePath = this.validatePathWithinProject(filePath);
3038
+ const tmpCheckpoint = path6.join(this.shadowRepoDir, ".diff-a");
3039
+ const tmpCurrent = path6.join(this.shadowRepoDir, ".diff-b");
3035
3040
  try {
3036
3041
  let checkpointContent;
3037
3042
  try {
@@ -3046,8 +3051,6 @@ var CheckpointStore = class {
3046
3051
  if (checkpointContent === currentContent) {
3047
3052
  continue;
3048
3053
  }
3049
- const tmpCheckpoint = path6.join(this.shadowRepoDir, ".diff-a");
3050
- const tmpCurrent = path6.join(this.shadowRepoDir, ".diff-b");
3051
3054
  writeFileSync(tmpCheckpoint, checkpointContent, "utf-8");
3052
3055
  writeFileSync(tmpCurrent, currentContent, "utf-8");
3053
3056
  try {
@@ -3070,12 +3073,16 @@ ${output}`);
3070
3073
  }
3071
3074
  }
3072
3075
  }
3076
+ } catch {
3077
+ } finally {
3073
3078
  try {
3074
3079
  unlinkSync(tmpCheckpoint);
3080
+ } catch {
3081
+ }
3082
+ try {
3075
3083
  unlinkSync(tmpCurrent);
3076
3084
  } catch {
3077
3085
  }
3078
- } catch {
3079
3086
  }
3080
3087
  }
3081
3088
  return diffParts.join("\n");
@@ -3109,6 +3116,18 @@ ${output}`);
3109
3116
  }
3110
3117
  }
3111
3118
  // --- Private helpers ---
3119
+ /**
3120
+ * Validate that a file path resolves within the project directory.
3121
+ * Prevents path traversal attacks (e.g., ../../etc/passwd).
3122
+ */
3123
+ validatePathWithinProject(filePath) {
3124
+ const absolutePath = path6.resolve(this.projectDir, filePath);
3125
+ const normalizedProject = path6.resolve(this.projectDir) + path6.sep;
3126
+ if (!absolutePath.startsWith(normalizedProject) && absolutePath !== path6.resolve(this.projectDir)) {
3127
+ throw new Error(`Path traversal detected: ${filePath}`);
3128
+ }
3129
+ return absolutePath;
3130
+ }
3112
3131
  /**
3113
3132
  * Execute a git command in the shadow repo
3114
3133
  */
@@ -10531,7 +10550,8 @@ var SchedulingProblemSchema = z139.object({
10531
10550
  name: z139.string(),
10532
10551
  description: z139.string().optional(),
10533
10552
  jobs: z139.array(JobSchema),
10534
- machines: z139.array(MachineSchema)
10553
+ machines: z139.array(MachineSchema),
10554
+ solvedJobUrl: z139.string().url().optional()
10535
10555
  });
10536
10556
  var SolverIdSchema = z139.enum([
10537
10557
  "greedy",
@@ -11196,6 +11216,351 @@ function constructSolution(allOps, pheromone, heuristic, rng) {
11196
11216
  return result;
11197
11217
  }
11198
11218
 
11219
+ // ../../b4m-core/packages/quantum/dist/src/solvers/highs-formulation.js
11220
+ function analyzeProblemComplexity(problem) {
11221
+ const numJobs = problem.jobs.length;
11222
+ const numMachines = problem.machines.length;
11223
+ const opsPerJob = problem.jobs[0]?.operations.length || 0;
11224
+ const totalOps = problem.jobs.reduce((sum2, j) => sum2 + j.operations.length, 0);
11225
+ const machineOpCounts = /* @__PURE__ */ new Map();
11226
+ for (const job of problem.jobs) {
11227
+ for (const op of job.operations) {
11228
+ machineOpCounts.set(op.machineId, (machineOpCounts.get(op.machineId) || 0) + 1);
11229
+ }
11230
+ }
11231
+ const opCounts = Array.from(machineOpCounts.values());
11232
+ const minOps = opCounts.length > 0 ? Math.min(...opCounts) : 0;
11233
+ const maxOps = opCounts.length > 0 ? Math.max(...opCounts) : 0;
11234
+ const avgOps = opCounts.length > 0 ? opCounts.reduce((a, b) => a + b, 0) / opCounts.length : 0;
11235
+ let binaryVars = 0;
11236
+ for (const n of opCounts) {
11237
+ binaryVars += n * (n - 1) / 2;
11238
+ }
11239
+ const startTimeVars = totalOps;
11240
+ const totalVars = startTimeVars + binaryVars + 1;
11241
+ const jobPrecedenceConstraints = problem.jobs.reduce((sum2, j) => sum2 + Math.max(0, j.operations.length - 1), 0);
11242
+ const machineDisjunctionConstraints = 2 * binaryVars;
11243
+ const makespanConstraints = totalOps;
11244
+ const totalConstraints = jobPrecedenceConstraints + machineDisjunctionConstraints + makespanConstraints;
11245
+ return {
11246
+ numJobs,
11247
+ numMachines,
11248
+ opsPerJob,
11249
+ totalOps,
11250
+ startTimeVars,
11251
+ binaryVars,
11252
+ totalVars,
11253
+ jobPrecedenceConstraints,
11254
+ machineDisjunctionConstraints,
11255
+ makespanConstraints,
11256
+ totalConstraints,
11257
+ opsPerMachine: { min: minOps, max: maxOps, avg: Math.round(avgOps * 10) / 10 }
11258
+ };
11259
+ }
11260
+ function estimateViability(c) {
11261
+ if (c.opsPerMachine.max > 10) {
11262
+ return {
11263
+ viable: false,
11264
+ risk: "high",
11265
+ recommendation: `Too many ops on one machine (${c.opsPerMachine.max}). Add more machines to spread the load, or use Simulated Annealing.`
11266
+ };
11267
+ }
11268
+ if (c.binaryVars <= 80 && c.totalOps <= 40 && c.opsPerMachine.max <= 6) {
11269
+ return {
11270
+ viable: true,
11271
+ risk: "low",
11272
+ recommendation: "Should solve quickly (< 1 second)"
11273
+ };
11274
+ }
11275
+ if (c.binaryVars <= 150 && c.totalOps <= 80 && c.opsPerMachine.max <= 8) {
11276
+ return {
11277
+ viable: true,
11278
+ risk: "medium",
11279
+ recommendation: "Should solve in 1-30 seconds. WASM may have occasional instability."
11280
+ };
11281
+ }
11282
+ if (c.binaryVars > 150) {
11283
+ return {
11284
+ viable: false,
11285
+ risk: "high",
11286
+ recommendation: `Too many binary vars (${c.binaryVars} > 150). Use Simulated Annealing or Tabu Search for this size.`
11287
+ };
11288
+ }
11289
+ if (c.totalOps > 80) {
11290
+ return {
11291
+ viable: false,
11292
+ risk: "high",
11293
+ recommendation: `Too many operations (${c.totalOps} > 80). Use Simulated Annealing or Tabu Search for this size.`
11294
+ };
11295
+ }
11296
+ return {
11297
+ viable: false,
11298
+ risk: "high",
11299
+ recommendation: "Exceeds tested parameters. Consider using Simulated Annealing or Tabu Search."
11300
+ };
11301
+ }
11302
+ function generateLPFormulation(problem) {
11303
+ const ops = [];
11304
+ for (const job of problem.jobs) {
11305
+ for (let opIdx = 0; opIdx < job.operations.length; opIdx++) {
11306
+ const op = job.operations[opIdx];
11307
+ const varName = `sJ${job.id}O${opIdx + 1}`;
11308
+ ops.push({
11309
+ jobId: job.id,
11310
+ machineId: op.machineId,
11311
+ opIndex: opIdx,
11312
+ duration: op.duration,
11313
+ varName
11314
+ });
11315
+ }
11316
+ }
11317
+ const bigM = ops.reduce((sum2, op) => sum2 + op.duration, 0);
11318
+ const machineOps = /* @__PURE__ */ new Map();
11319
+ for (const op of ops) {
11320
+ const machOps = machineOps.get(op.machineId) || [];
11321
+ machOps.push(op);
11322
+ machineOps.set(op.machineId, machOps);
11323
+ }
11324
+ const lines = [];
11325
+ lines.push("Minimize obj: Cmax");
11326
+ lines.push("");
11327
+ lines.push("Subject To");
11328
+ for (const job of problem.jobs) {
11329
+ for (let i = 0; i < job.operations.length - 1; i++) {
11330
+ const op1VarName = `sJ${job.id}O${i + 1}`;
11331
+ const op2VarName = `sJ${job.id}O${i + 2}`;
11332
+ const duration = job.operations[i].duration;
11333
+ const constraintName = `job${op1VarName}to${op2VarName}`;
11334
+ lines.push(` ${constraintName}: ${op1VarName} - ${op2VarName} <= ${-duration}`);
11335
+ }
11336
+ }
11337
+ const binaryVars = [];
11338
+ for (const [, machOps] of machineOps) {
11339
+ if (machOps.length < 2)
11340
+ continue;
11341
+ for (let i = 0; i < machOps.length; i++) {
11342
+ for (let j = i + 1; j < machOps.length; j++) {
11343
+ const op1 = machOps[i];
11344
+ const op2 = machOps[j];
11345
+ const yVar = `y${op1.varName}x${op2.varName}`;
11346
+ binaryVars.push(yVar);
11347
+ const c1Name = `d${op1.varName}b${op2.varName}`;
11348
+ lines.push(` ${c1Name}: ${op1.varName} - ${op2.varName} + ${bigM} ${yVar} <= ${bigM - op1.duration}`);
11349
+ const c2Name = `d${op2.varName}b${op1.varName}`;
11350
+ lines.push(` ${c2Name}: ${op2.varName} - ${op1.varName} - ${bigM} ${yVar} <= ${-op2.duration}`);
11351
+ }
11352
+ }
11353
+ }
11354
+ for (const op of ops) {
11355
+ const constraintName = `mk${op.varName}`;
11356
+ lines.push(` ${constraintName}: ${op.varName} - Cmax <= ${-op.duration}`);
11357
+ }
11358
+ lines.push("");
11359
+ lines.push("Bounds");
11360
+ for (const op of ops) {
11361
+ lines.push(` ${op.varName} >= 0`);
11362
+ }
11363
+ lines.push(" Cmax >= 0");
11364
+ lines.push("");
11365
+ if (binaryVars.length > 0) {
11366
+ lines.push("Binary");
11367
+ for (const v of binaryVars) {
11368
+ lines.push(` ${v}`);
11369
+ }
11370
+ lines.push("");
11371
+ }
11372
+ lines.push("End");
11373
+ return lines.join("\n");
11374
+ }
11375
+ function parseSolution(problem, columns) {
11376
+ const schedule = [];
11377
+ const varToOp = /* @__PURE__ */ new Map();
11378
+ for (const job of problem.jobs) {
11379
+ for (let opIdx = 0; opIdx < job.operations.length; opIdx++) {
11380
+ const op = job.operations[opIdx];
11381
+ const varName = `sJ${job.id}O${opIdx + 1}`;
11382
+ varToOp.set(varName, {
11383
+ jobId: job.id,
11384
+ machineId: op.machineId,
11385
+ opIndex: opIdx,
11386
+ duration: op.duration
11387
+ });
11388
+ }
11389
+ }
11390
+ for (const [varName, col] of Object.entries(columns)) {
11391
+ if (varName.startsWith("sJ")) {
11392
+ const opInfo = varToOp.get(varName);
11393
+ if (opInfo) {
11394
+ const startTime = Math.round(col.Primal);
11395
+ schedule.push({
11396
+ jobId: opInfo.jobId,
11397
+ machineId: opInfo.machineId,
11398
+ operationIndex: opInfo.opIndex,
11399
+ startTime,
11400
+ endTime: startTime + opInfo.duration
11401
+ });
11402
+ }
11403
+ }
11404
+ }
11405
+ schedule.sort((a, b) => a.startTime - b.startTime);
11406
+ return schedule;
11407
+ }
11408
+ function validateSchedule(problem, schedule) {
11409
+ const errors = [];
11410
+ const scheduledKeys = new Set(schedule.map((s) => `${s.jobId}-${s.operationIndex}`));
11411
+ for (const job of problem.jobs) {
11412
+ for (let opIdx = 0; opIdx < job.operations.length; opIdx++) {
11413
+ if (!scheduledKeys.has(`${job.id}-${opIdx}`)) {
11414
+ errors.push(`Operation (job=${job.id}, opIndex=${opIdx}) not scheduled`);
11415
+ }
11416
+ }
11417
+ }
11418
+ const byMachine = /* @__PURE__ */ new Map();
11419
+ for (const s of schedule) {
11420
+ const mOps = byMachine.get(s.machineId) || [];
11421
+ mOps.push(s);
11422
+ byMachine.set(s.machineId, mOps);
11423
+ }
11424
+ for (const [machineId, mOps] of byMachine) {
11425
+ mOps.sort((a, b) => a.startTime - b.startTime);
11426
+ for (let i = 0; i < mOps.length - 1; i++) {
11427
+ if (mOps[i].endTime > mOps[i + 1].startTime) {
11428
+ errors.push(`Machine ${machineId}: (job=${mOps[i].jobId},op=${mOps[i].operationIndex}) ends ${mOps[i].endTime} overlaps (job=${mOps[i + 1].jobId},op=${mOps[i + 1].operationIndex}) starts ${mOps[i + 1].startTime}`);
11429
+ }
11430
+ }
11431
+ }
11432
+ const opEndTime = /* @__PURE__ */ new Map();
11433
+ for (const s of schedule) {
11434
+ opEndTime.set(`${s.jobId}-${s.operationIndex}`, s.endTime);
11435
+ }
11436
+ for (const job of problem.jobs) {
11437
+ for (let i = 0; i < job.operations.length - 1; i++) {
11438
+ const op1End = opEndTime.get(`${job.id}-${i}`) || 0;
11439
+ const op2 = schedule.find((s) => s.jobId === job.id && s.operationIndex === i + 1);
11440
+ if (op2 && op1End > op2.startTime) {
11441
+ errors.push(`Job ${job.id}: op ${i} ends at ${op1End} but op ${i + 1} starts at ${op2.startTime}`);
11442
+ }
11443
+ }
11444
+ }
11445
+ return { valid: errors.length === 0, errors };
11446
+ }
11447
+
11448
+ // ../../b4m-core/packages/quantum/dist/src/solvers/highs-solver.js
11449
+ var MAX_BINARY_VARS = 150;
11450
+ var MAX_TOTAL_OPS = 80;
11451
+ var MAX_OPS_PER_MACHINE = 8;
11452
+ async function loadHiGHS() {
11453
+ const highsLoader = (await import("highs")).default;
11454
+ const highs = await highsLoader({
11455
+ locateFile: (file) => {
11456
+ const globalSelf = globalThis;
11457
+ if (globalSelf.location?.origin) {
11458
+ return `${globalSelf.location.origin}/${file}`;
11459
+ }
11460
+ return file;
11461
+ }
11462
+ });
11463
+ return highs;
11464
+ }
11465
+ function elapsed(startTime) {
11466
+ return typeof performance !== "undefined" ? performance.now() - startTime : Date.now() - startTime;
11467
+ }
11468
+ var highsSolver = {
11469
+ id: "highs",
11470
+ name: "HiGHS (WASM)",
11471
+ description: "Open-source MIP solver providing provably optimal solutions for small-to-medium scheduling problems via WASM.",
11472
+ async solve(problem, options) {
11473
+ const startTime = typeof performance !== "undefined" ? performance.now() : Date.now();
11474
+ const reportProgress = (percentage, bestMakespan) => {
11475
+ options?.onProgress?.({
11476
+ solverId: "highs",
11477
+ percentage,
11478
+ bestMakespan
11479
+ });
11480
+ };
11481
+ reportProgress(0);
11482
+ try {
11483
+ reportProgress(5);
11484
+ const highs = await loadHiGHS();
11485
+ reportProgress(10);
11486
+ const complexity = analyzeProblemComplexity(problem);
11487
+ const viability = estimateViability(complexity);
11488
+ if (complexity.binaryVars > MAX_BINARY_VARS) {
11489
+ throw new Error(`Problem has too many binary variables for HiGHS WASM: ${complexity.binaryVars} (max ${MAX_BINARY_VARS}). Tip: More machines spreads ops and reduces binary vars. Current: ${complexity.numMachines} machines. For this size, use Simulated Annealing or Tabu Search.`);
11490
+ }
11491
+ if (complexity.totalOps > MAX_TOTAL_OPS) {
11492
+ throw new Error(`Problem too large for HiGHS WASM: ${complexity.totalOps} operations (max ${MAX_TOTAL_OPS}). For larger problems, use Simulated Annealing or Tabu Search.`);
11493
+ }
11494
+ if (complexity.opsPerMachine.max > MAX_OPS_PER_MACHINE) {
11495
+ throw new Error(`Too many operations on one machine: ${complexity.opsPerMachine.max} ops (max ${MAX_OPS_PER_MACHINE}). Tip: Add more machines to spread the load. For this size, use Simulated Annealing or Tabu Search.`);
11496
+ }
11497
+ if (viability.risk === "high") {
11498
+ console.warn(`[HiGHS] Warning: ${viability.recommendation}`);
11499
+ }
11500
+ reportProgress(15);
11501
+ const lpString = generateLPFormulation(problem);
11502
+ if (!lpString.includes("Subject To") || !lpString.includes("Bounds")) {
11503
+ throw new Error("Invalid LP formulation - missing required sections");
11504
+ }
11505
+ reportProgress(20);
11506
+ let solution;
11507
+ try {
11508
+ solution = highs.solve(lpString, {
11509
+ time_limit: options?.timeoutMs ? options.timeoutMs / 1e3 : 60,
11510
+ mip_rel_gap: 0,
11511
+ presolve: "on",
11512
+ log_to_console: true,
11513
+ // MUST BE TRUE - see file header
11514
+ output_flag: true
11515
+ // MUST BE TRUE - see file header
11516
+ });
11517
+ } catch (solveError) {
11518
+ console.error("[HiGHS] Solve error:", solveError);
11519
+ console.error("[HiGHS] Problem config:", {
11520
+ jobs: problem.jobs.length,
11521
+ machines: problem.machines.length,
11522
+ totalOps: problem.jobs.reduce((sum2, j) => sum2 + j.operations.length, 0)
11523
+ });
11524
+ const errMsg = solveError instanceof Error ? solveError.message : String(solveError);
11525
+ if (errMsg.includes("Aborted")) {
11526
+ throw new Error(`HiGHS WASM crashed. This may be a numerical issue with the problem configuration. Jobs: ${problem.jobs.length}, Machines: ${problem.machines.length}. Check browser console for details.`);
11527
+ }
11528
+ throw solveError;
11529
+ }
11530
+ if (solution.Status === "Infeasible") {
11531
+ throw new Error("Problem is infeasible - check constraints");
11532
+ }
11533
+ if (solution.Status === "Unbounded") {
11534
+ throw new Error("Problem is unbounded - check objective");
11535
+ }
11536
+ if (solution.Status !== "Optimal" && solution.Status !== "Time limit reached" && solution.Status !== "Bound on objective reached") {
11537
+ throw new Error(`HiGHS returned unexpected status: ${solution.Status}`);
11538
+ }
11539
+ reportProgress(90);
11540
+ const schedule = parseSolution(problem, solution.Columns);
11541
+ const makespan = Math.ceil(solution.ObjectiveValue);
11542
+ const validation = validateSchedule(problem, schedule);
11543
+ if (!validation.valid) {
11544
+ console.warn("[HiGHS] Solution validation failed:", validation.errors);
11545
+ const errorDetails = validation.errors && validation.errors.length > 0 ? validation.errors.join("; ") : "Unknown validation error";
11546
+ throw new Error(`[HiGHS] Solution validation failed: ${errorDetails}`);
11547
+ }
11548
+ reportProgress(100, makespan);
11549
+ return {
11550
+ solverId: "highs",
11551
+ solverName: "HiGHS (WASM)",
11552
+ makespan,
11553
+ schedule,
11554
+ elapsedMs: elapsed(startTime),
11555
+ iterations: 1
11556
+ };
11557
+ } catch (error) {
11558
+ reportProgress(0);
11559
+ throw error;
11560
+ }
11561
+ }
11562
+ };
11563
+
11199
11564
  // ../../b4m-core/packages/quantum/dist/src/solvers/metadata.js
11200
11565
  var solverMetadata = {
11201
11566
  naive: {
@@ -11464,7 +11829,6 @@ var solverMetadata = {
11464
11829
  color: "success",
11465
11830
  complexity: "Seconds to minutes",
11466
11831
  requires: "Browser compute (WASM)",
11467
- available: false,
11468
11832
  tagline: "Open-source solver rivaling commercial giants",
11469
11833
  fullDescription: "HiGHS (High-performance Interior-point, Gradient-descent, Simplex) is an MIT-licensed open-source solver that achieves 90%+ of commercial solver performance. Developed at the University of Edinburgh, it has rapidly become the leading open-source alternative to Gurobi and COPT for linear and mixed-integer programming.",
11470
11834
  howItWorks: [
@@ -11538,7 +11902,10 @@ var solverMetadata = {
11538
11902
  wikipedia: "https://en.wikipedia.org/wiki/Quantum_approximate_optimization_algorithm",
11539
11903
  otherResources: [
11540
11904
  { label: "Farhi et al. (2014) \u2014 Original QAOA Paper", url: "https://arxiv.org/abs/1411.4028" },
11541
- { label: "QUBO Formulation Guide", url: "https://en.wikipedia.org/wiki/Quadratic_unconstrained_binary_optimization" }
11905
+ {
11906
+ label: "QUBO Formulation Guide",
11907
+ url: "https://en.wikipedia.org/wiki/Quadratic_unconstrained_binary_optimization"
11908
+ }
11542
11909
  ]
11543
11910
  },
11544
11911
  "ionq-qaoa": {
@@ -11596,7 +11963,8 @@ var allSolvers = [
11596
11963
  simulatedAnnealingLargeSolver,
11597
11964
  tabuSolver,
11598
11965
  geneticAlgorithmSolver,
11599
- antColonySolver
11966
+ antColonySolver,
11967
+ highsSolver
11600
11968
  ];
11601
11969
  var solverRegistry = new Map(allSolvers.map((s) => [s.id, s]));
11602
11970
  function getSolver(id) {
@@ -11607,7 +11975,6 @@ function getAvailableSolverIds() {
11607
11975
  }
11608
11976
  var displaySolvers = [
11609
11977
  ...allSolvers.map((s) => ({ id: s.id, name: s.name, description: s.description })),
11610
- { id: "highs", name: "HiGHS (WASM)", description: solverMetadata.highs.tagline },
11611
11978
  { id: "simulated-qaoa", name: "Simulated QAOA", description: solverMetadata["simulated-qaoa"].tagline },
11612
11979
  { id: "ionq-qaoa", name: "IonQ QAOA", description: solverMetadata["ionq-qaoa"].tagline }
11613
11980
  ];
@@ -11632,11 +11999,17 @@ ${allSolvers.map((s) => `- **${s.name}** (\`${s.id}\`): ${s.description}`).join(
11632
11999
 
11633
12000
  ## How to Help Users
11634
12001
 
11635
- ### Problem Formulation
11636
- When a user describes a scheduling scenario:
11637
- 1. Use \`quantum_formulate\` to convert their description into a structured problem
11638
- 2. Present the formulated problem clearly, showing jobs, machines, and operation sequences
11639
- 3. Ask if adjustments are needed before solving
12002
+ ### Concierge Flow (Default)
12003
+ When a user describes a scheduling problem:
12004
+ 1. Use \`quantum_formulate\` to convert their description \u2014 the problem auto-loads into the Problem Editor
12005
+ 2. Call \`navigate_view\` with viewId "opti.scheduling.problem" so the user gets a button to open the Problem tab
12006
+ 3. Let the user review, tweak machines/durations, and run solvers from the dashboard
12007
+ Do NOT auto-call \`quantum_schedule\` unless the user explicitly asks to solve in chat.
12008
+
12009
+ ### Power User Fast Path
12010
+ If the user says "solve it", "find the optimal schedule", or explicitly requests an in-chat solution,
12011
+ use both \`quantum_formulate\` AND \`quantum_schedule\`. The problem still loads into the Editor
12012
+ so the user can explore results in the dashboard too.
11640
12013
 
11641
12014
  ### Running Solvers
11642
12015
  When solving a problem:
@@ -11701,6 +12074,581 @@ RESPOND WITH ONLY A JSON OBJECT matching this schema:
11701
12074
 
11702
12075
  No markdown, no explanation, no code blocks \u2014 just the raw JSON object.`;
11703
12076
 
12077
+ // ../../b4m-core/packages/quantum/dist/src/patterns.js
12078
+ var patternFamilies = [
12079
+ {
12080
+ id: "scheduling",
12081
+ name: "Scheduling",
12082
+ description: "Job shop, flow shop, resource allocation over time",
12083
+ complexity: "NP-hard",
12084
+ color: "#e53935",
12085
+ quboFit: "excellent",
12086
+ examples: ["Job Shop Scheduling", "Task Scheduling", "Production Planning"],
12087
+ status: "available",
12088
+ tagline: "When to do things, in what order, on what resources",
12089
+ asciiDiagram: [
12090
+ " 0 2 4 6 8 10 12",
12091
+ " \u251C\u2500\u2500\u253C\u2500\u2500\u253C\u2500\u2500\u253C\u2500\u2500\u253C\u2500\u2500\u253C\u2500\u2500\u2524",
12092
+ "A [\u25A0\u25A0\u25A0\u25A0\u25A0][ \u2591\u2591\u2591\u2591\u2591\u2591 ]",
12093
+ "B [\u2591\u2591\u2591\u2591\u2591][ \u25A0\u25A0\u25A0\u25A0\u25A0 ]",
12094
+ "C [\u25A0\u25A0\u25A0] [\u2591\u2591\u2591\u2591\u2591\u2591]",
12095
+ " \u2500\u2500\u2500\u2500 time \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25BA"
12096
+ ].join("\n"),
12097
+ subPatterns: [
12098
+ {
12099
+ name: "Job Shop Scheduling",
12100
+ subtitle: "The Classic",
12101
+ description: "Assign jobs to machines with precedence constraints. Each job has a sequence of operations that must be processed on specific machines in order. The goal is to minimize the total makespan.",
12102
+ asciiDiagram: [
12103
+ "J1: [M-A 3t]->[M-B 2t]->[M-C 4t]",
12104
+ "J2: [M-B 2t]->[M-C 3t]->[M-A 2t]",
12105
+ "J3: [M-C 4t]->[M-A 1t]->[M-B 3t]",
12106
+ "",
12107
+ "Objective: Minimize total completion time"
12108
+ ].join("\n"),
12109
+ quboFitStars: 5
12110
+ },
12111
+ {
12112
+ name: "Flow Shop Scheduling",
12113
+ subtitle: "Fixed Sequence",
12114
+ description: "All jobs follow the same machine order. Simpler than job shop but still NP-hard for 3+ machines. Common in assembly lines and manufacturing pipelines.",
12115
+ asciiDiagram: [
12116
+ "Job 1: -->[M1]-->[M2]-->[M3]--> Done",
12117
+ "Job 2: -->[M1]-->[M2]-->[M3]--> Done",
12118
+ "Job 3: -->[M1]-->[M2]-->[M3]--> Done",
12119
+ " Fixed order through all machines"
12120
+ ].join("\n"),
12121
+ quboFitStars: 5
12122
+ },
12123
+ {
12124
+ name: "Timetabling",
12125
+ subtitle: "Conflict Avoidance",
12126
+ description: "Schedule events into time slots while avoiding conflicts. No professor teaches two classes at once, no student has overlapping classes, room capacities are respected.",
12127
+ asciiDiagram: [
12128
+ " Mon Tue Wed Thu",
12129
+ " 9:00 |CS101| |CS101| |",
12130
+ "10:00 | |MATH | |MATH |",
12131
+ "11:00 |PHYS | |PHYS | |",
12132
+ " No conflicts for shared resources!"
12133
+ ].join("\n"),
12134
+ quboFitStars: 4
12135
+ },
12136
+ {
12137
+ name: "Sequencing with Changeover",
12138
+ subtitle: "Order Matters",
12139
+ description: "Transition costs between tasks depend on the sequence. Paint lines minimize cleaning by ordering light-to-dark. Semiconductor fabs batch similar wafers together.",
12140
+ asciiDiagram: [
12141
+ "White->Yellow->Orange $0 each",
12142
+ "Orange->Red->Black $0 each",
12143
+ "White->Black directly $50 clean!",
12144
+ "",
12145
+ "Objective: Minimize total changeover cost"
12146
+ ].join("\n"),
12147
+ quboFitStars: 4
12148
+ },
12149
+ {
12150
+ name: "Dynamic Scheduling",
12151
+ subtitle: "Continuous Arrival",
12152
+ description: "New jobs arrive during execution, requiring real-time rescheduling. Common in hospitals, data centers, and cloud computing where demand is unpredictable.",
12153
+ asciiDiagram: [
12154
+ "Time --------------------------->",
12155
+ "J1 ========",
12156
+ " J2 ==========",
12157
+ " J3 ======= (arrived t=3)",
12158
+ " J4 === (arrived t=5)",
12159
+ " Must reschedule as jobs arrive!"
12160
+ ].join("\n"),
12161
+ quboFitStars: 3
12162
+ }
12163
+ ],
12164
+ quboExplainer: "Each binary variable x(j,m,t) = 1 if job j starts on machine m at time t. Penalty terms enforce: (1) each operation scheduled exactly once, (2) precedence constraints respected, (3) no machine processes two jobs simultaneously. Qubit count scales as O(jobs x machines x time_horizon).",
12165
+ useCases: [
12166
+ { industry: "Manufacturing", application: "Factory floor scheduling" },
12167
+ { industry: "Healthcare", application: "Operating room scheduling" },
12168
+ { industry: "Airlines", application: "Crew and gate scheduling" },
12169
+ { industry: "Data Centers", application: "Batch job scheduling" },
12170
+ { industry: "Construction", application: "Project task sequencing" },
12171
+ { industry: "Restaurants", application: "Kitchen order optimization" }
12172
+ ]
12173
+ },
12174
+ {
12175
+ id: "routing",
12176
+ name: "Routing",
12177
+ description: "Vehicle routing, TSP, network path optimization",
12178
+ complexity: "NP-hard",
12179
+ color: "#66bb6a",
12180
+ quboFit: "excellent",
12181
+ examples: ["Traveling Salesman", "Vehicle Routing", "Delivery Optimization"],
12182
+ status: "coming-soon",
12183
+ tagline: "How to move through space efficiently",
12184
+ asciiDiagram: [
12185
+ " A",
12186
+ " /|\\",
12187
+ " 5/ | \\3",
12188
+ " / | \\",
12189
+ " B---+---C",
12190
+ " \\ | /",
12191
+ " 7\\ | /2",
12192
+ " \\|/",
12193
+ " D"
12194
+ ].join("\n"),
12195
+ subPatterns: [
12196
+ {
12197
+ name: "Traveling Salesman (TSP)",
12198
+ subtitle: "The Classic",
12199
+ description: "Visit all cities exactly once and return home via the shortest route. One of the most famous optimization problems \u2014 100+ cities makes exhaustive search impossible.",
12200
+ asciiDiagram: [
12201
+ "Start -> A -> B -> C -> D -> Start",
12202
+ "",
12203
+ "Find the shortest tour that visits",
12204
+ "every city exactly once!"
12205
+ ].join("\n"),
12206
+ quboFitStars: 5
12207
+ },
12208
+ {
12209
+ name: "Vehicle Routing (VRP)",
12210
+ subtitle: "Multiple Vehicles",
12211
+ description: "Partition customers among a fleet of vehicles, each with capacity limits and time windows. TSP generalized to multiple routes from a central depot.",
12212
+ asciiDiagram: [
12213
+ " Depot",
12214
+ " / | \\",
12215
+ " / | \\",
12216
+ " Route1 Route2 Route3",
12217
+ " A->B D->E G->H",
12218
+ " ->C ->F ->I"
12219
+ ].join("\n"),
12220
+ quboFitStars: 4
12221
+ },
12222
+ {
12223
+ name: "Shortest Path",
12224
+ subtitle: "Point-to-Point",
12225
+ description: "Find the minimum-cost path between two nodes in a weighted graph. Foundation for GPS navigation, network routing, and supply chain logistics.",
12226
+ asciiDiagram: [
12227
+ "S --3-- A --2-- T",
12228
+ "| | |",
12229
+ "5 1 4",
12230
+ "| | |",
12231
+ "B --6-- C --2-- D"
12232
+ ].join("\n"),
12233
+ quboFitStars: 3
12234
+ }
12235
+ ],
12236
+ quboExplainer: "Binary variable x(i,t) = 1 if city i is visited at step t. Constraints: each city visited exactly once, each step visits exactly one city. Objective minimizes total edge weights along the tour. Classic QUBO formulation.",
12237
+ useCases: [
12238
+ { industry: "Logistics", application: "Delivery route optimization" },
12239
+ { industry: "Ride-sharing", application: "Driver dispatch routing" },
12240
+ { industry: "Telecom", application: "Network packet routing" },
12241
+ { industry: "Retail", application: "Supply chain distribution" },
12242
+ { industry: "Field Service", application: "Technician visit scheduling" }
12243
+ ]
12244
+ },
12245
+ {
12246
+ id: "packing",
12247
+ name: "Packing",
12248
+ description: "Bin packing, knapsack, container optimization",
12249
+ complexity: "NP-complete",
12250
+ color: "#e91e63",
12251
+ quboFit: "good",
12252
+ examples: ["Bin Packing", "Knapsack Problem", "Container Loading"],
12253
+ status: "coming-soon",
12254
+ tagline: "How to fit things into space efficiently",
12255
+ asciiDiagram: [
12256
+ "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
12257
+ "\u2502 \u2588\u2588\u2588\u2588 \u2591\u2591\u2591\u2591 \u2588\u2588\u2588\u2588\u2588\u2588 \u2502 92%",
12258
+ "\u2502 \u2588\u2588\u2588\u2588 \u2591\u2591\u2591\u2591 \u2588\u2588\u2588\u2588\u2588\u2588 \u2502",
12259
+ "\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524",
12260
+ "\u2502 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2502 68%",
12261
+ "\u2502 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2502",
12262
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"
12263
+ ].join("\n"),
12264
+ subPatterns: [
12265
+ {
12266
+ name: "Bin Packing",
12267
+ subtitle: "1D/2D/3D",
12268
+ description: "Fit items into the minimum number of bins. 1D (rod cutting, memory), 2D (sheet cutting, floor plans), 3D (container loading, truck packing). Items arrive online or in batch.",
12269
+ asciiDiagram: [
12270
+ "Items: [3] [5] [2] [4] [6]",
12271
+ "",
12272
+ "Bin 1: [3][5][2] = 10/10",
12273
+ "Bin 2: [4][6] = 10/10",
12274
+ "Minimum bins: 2"
12275
+ ].join("\n"),
12276
+ quboFitStars: 4
12277
+ },
12278
+ {
12279
+ name: "Knapsack",
12280
+ subtitle: "Value vs Weight",
12281
+ description: "Select items to maximize total value without exceeding weight capacity. The 0/1 knapsack is a direct binary problem \u2014 include or exclude each item.",
12282
+ asciiDiagram: [
12283
+ "Item Value Weight",
12284
+ " A 60 10",
12285
+ " B 100 20 <-- pick",
12286
+ " C 120 30 <-- pick",
12287
+ "Capacity: 50 Best: $220"
12288
+ ].join("\n"),
12289
+ quboFitStars: 5
12290
+ },
12291
+ {
12292
+ name: "Cutting Stock",
12293
+ subtitle: "Minimize Waste",
12294
+ description: "Cut raw material (steel rolls, fabric bolts, lumber) into required pieces with minimal waste. Dual of bin packing \u2014 subtract from fixed-size stock.",
12295
+ asciiDiagram: [
12296
+ "Stock roll: |============|",
12297
+ "Cut: |==A==|==B==|=C=|xx|",
12298
+ " waste",
12299
+ "Objective: Minimize total waste"
12300
+ ].join("\n"),
12301
+ quboFitStars: 4
12302
+ }
12303
+ ],
12304
+ quboExplainer: "Binary variable x(i,b) = 1 if item i is placed in bin b. Constraints: each item in exactly one bin, bin capacity not exceeded. For knapsack, x(i) = 1 if item i is selected, with weight constraint as penalty term.",
12305
+ useCases: [
12306
+ { industry: "Shipping", application: "Container loading optimization" },
12307
+ { industry: "Manufacturing", application: "Raw material cutting" },
12308
+ { industry: "Cloud Computing", application: "VM placement on servers" },
12309
+ { industry: "Retail", application: "Warehouse space allocation" },
12310
+ { industry: "Finance", application: "Budget allocation (knapsack)" }
12311
+ ]
12312
+ },
12313
+ {
12314
+ id: "assignment",
12315
+ name: "Assignment",
12316
+ description: "Matching agents to tasks, resource allocation",
12317
+ complexity: "NP-complete",
12318
+ color: "#42a5f5",
12319
+ quboFit: "excellent",
12320
+ examples: ["Task Assignment", "Resource Matching", "Workforce Allocation"],
12321
+ status: "coming-soon",
12322
+ tagline: "Who does what \u2014 optimal matching",
12323
+ asciiDiagram: [
12324
+ " Agents Tasks",
12325
+ " [A] \u2500\u2500\u2500\u2500\u2500\u2500 [1]",
12326
+ " [B] \u2500\u2500\u2510",
12327
+ " \u2514\u2500\u2500 [2]",
12328
+ " [C] \u2500\u2500\u2500\u2500\u2500\u2500 [3]",
12329
+ " [D] \u2500\u2500\u2500\u2500\u2500\u2500 [4]"
12330
+ ].join("\n"),
12331
+ subPatterns: [
12332
+ {
12333
+ name: "Bipartite Matching",
12334
+ subtitle: "One-to-One",
12335
+ description: "Match agents to tasks where each agent handles exactly one task and vice versa. Minimize total cost or maximize total benefit across all assignments.",
12336
+ asciiDiagram: [
12337
+ "Workers Jobs",
12338
+ " Alice ---> Design cost: 3",
12339
+ " Bob -----> Code cost: 2",
12340
+ " Carol ---> Test cost: 4",
12341
+ "Total cost: 9 (optimal)"
12342
+ ].join("\n"),
12343
+ quboFitStars: 5
12344
+ },
12345
+ {
12346
+ name: "Quadratic Assignment",
12347
+ subtitle: "Location Matters",
12348
+ description: "Assign facilities to locations minimizing the product of flow between facilities and distance between locations. Used for factory layout and chip placement.",
12349
+ asciiDiagram: [
12350
+ "Facility Flow Location Dist",
12351
+ " A <-50-> B L1 <-3-> L2",
12352
+ " A <-20-> C L1 <-5-> L3",
12353
+ "Minimize: sum(flow*distance)"
12354
+ ].join("\n"),
12355
+ quboFitStars: 5
12356
+ },
12357
+ {
12358
+ name: "Generalized Assignment",
12359
+ subtitle: "Many-to-One",
12360
+ description: "Assign tasks to agents where each agent can handle multiple tasks within their capacity. Workers have different skills and capacities across task types.",
12361
+ asciiDiagram: [
12362
+ "Agent A (cap 10): [T1:3][T2:4][T3:3]",
12363
+ "Agent B (cap 8): [T4:5][T5:3]",
12364
+ "Agent C (cap 12): [T6:6][T7:4]",
12365
+ "Maximize quality within capacity"
12366
+ ].join("\n"),
12367
+ quboFitStars: 4
12368
+ }
12369
+ ],
12370
+ quboExplainer: "Binary variable x(i,j) = 1 if agent i is assigned to task j. Constraints: each task assigned to exactly one agent (row sums = 1), each agent at most one task (column sums <= 1). Cost matrix entries become QUBO coefficients.",
12371
+ useCases: [
12372
+ { industry: "HR", application: "Employee-to-project matching" },
12373
+ { industry: "Education", application: "Student-to-course assignment" },
12374
+ { industry: "Healthcare", application: "Doctor-to-shift assignment" },
12375
+ { industry: "Military", application: "Weapon-target assignment" },
12376
+ { industry: "Sports", application: "Referee-to-game assignment" }
12377
+ ]
12378
+ },
12379
+ {
12380
+ id: "network",
12381
+ name: "Network",
12382
+ description: "Graph partitioning, max cut, community detection",
12383
+ complexity: "NP-hard",
12384
+ color: "#f4511e",
12385
+ quboFit: "excellent",
12386
+ examples: ["Graph Partitioning", "Max Cut", "Network Design"],
12387
+ status: "coming-soon",
12388
+ tagline: "How to structure and divide networks",
12389
+ asciiDiagram: [
12390
+ " a-b-c | d-e",
12391
+ " | | | | |",
12392
+ " f-g | h-i",
12393
+ " -------+-------",
12394
+ " Group A | Group B",
12395
+ " max cut \u2702"
12396
+ ].join("\n"),
12397
+ subPatterns: [
12398
+ {
12399
+ name: "Max Cut",
12400
+ subtitle: "The QUBO Natural",
12401
+ description: "Partition graph nodes into two groups to maximize edges crossing the cut. The most natural QUBO problem \u2014 maps directly without any reformulation tricks.",
12402
+ asciiDiagram: [
12403
+ "Group 0 | Group 1",
12404
+ " a--b | d--e",
12405
+ " | | |",
12406
+ " c ------+------ f",
12407
+ " cut edges = 3 (max!)"
12408
+ ].join("\n"),
12409
+ quboFitStars: 5
12410
+ },
12411
+ {
12412
+ name: "Graph Partitioning",
12413
+ subtitle: "Balanced Split",
12414
+ description: "Divide nodes into k equal-sized groups minimizing edges between groups. Used for parallel computing load balancing and VLSI chip layout.",
12415
+ asciiDiagram: [
12416
+ "Before: tangled graph",
12417
+ "After: [ A ] | [ B ] | [ C ]",
12418
+ " n/3 | n/3 | n/3",
12419
+ "Minimize cross-partition edges"
12420
+ ].join("\n"),
12421
+ quboFitStars: 5
12422
+ },
12423
+ {
12424
+ name: "Community Detection",
12425
+ subtitle: "Find Clusters",
12426
+ description: "Discover densely connected groups within a network. Social networks, protein interactions, citation graphs. Related to modularity maximization.",
12427
+ asciiDiagram: [
12428
+ "(a-b-c) (d-e-f)",
12429
+ " dense dense",
12430
+ " \\ /",
12431
+ " sparse",
12432
+ "Find the natural communities"
12433
+ ].join("\n"),
12434
+ quboFitStars: 4
12435
+ }
12436
+ ],
12437
+ quboExplainer: "For Max Cut: x(i) = 0 or 1 assigns node i to a group. Objective maximizes sum of w(i,j) * x(i) * (1-x(j)) over all edges. This is already a QUBO \u2014 no reformulation needed! Graph partitioning adds a balance constraint as a penalty term.",
12438
+ useCases: [
12439
+ { industry: "Social Media", application: "Community detection" },
12440
+ { industry: "VLSI Design", application: "Chip layout partitioning" },
12441
+ { industry: "HPC", application: "Parallel workload balancing" },
12442
+ { industry: "Biology", application: "Protein interaction clustering" },
12443
+ { industry: "Telecom", application: "Network segmentation" }
12444
+ ]
12445
+ },
12446
+ {
12447
+ id: "selection",
12448
+ name: "Selection",
12449
+ description: "Portfolio optimization, feature selection, subset problems",
12450
+ complexity: "NP-complete",
12451
+ color: "#00897b",
12452
+ quboFit: "good",
12453
+ examples: ["Portfolio Selection", "Feature Selection", "Subset Sum"],
12454
+ status: "coming-soon",
12455
+ tagline: "Which items to choose from a set",
12456
+ asciiDiagram: [
12457
+ " [\u25A0] [\xB7] [\u25A0] [\xB7]",
12458
+ " [\xB7] [\u25A0] [\xB7] [\u25A0]",
12459
+ " [\u25A0] [\xB7] [\xB7] [\xB7]",
12460
+ " \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
12461
+ " \u25A0 = selected 5/12",
12462
+ " score: 847 / 1000"
12463
+ ].join("\n"),
12464
+ subPatterns: [
12465
+ {
12466
+ name: "Portfolio Optimization",
12467
+ subtitle: "Risk vs Return",
12468
+ description: "Select assets to maximize return while minimizing risk (variance). Markowitz model is naturally quadratic \u2014 covariance matrix maps directly to QUBO interactions.",
12469
+ asciiDiagram: [
12470
+ "Return ^",
12471
+ " | * efficient frontier",
12472
+ " | *",
12473
+ " | * <- optimal portfolio",
12474
+ " |* ",
12475
+ " +---------> Risk"
12476
+ ].join("\n"),
12477
+ quboFitStars: 5
12478
+ },
12479
+ {
12480
+ name: "Feature Selection",
12481
+ subtitle: "Signal vs Noise",
12482
+ description: "Choose the best subset of features for a machine learning model. Too many features cause overfitting; too few miss signal. Binary choice per feature makes this naturally QUBO.",
12483
+ asciiDiagram: [
12484
+ "Features: [x1] [x2] [x3] ... [xN]",
12485
+ "Select: Y N Y ... N",
12486
+ "",
12487
+ "Maximize: accuracy - lambda*count"
12488
+ ].join("\n"),
12489
+ quboFitStars: 4
12490
+ },
12491
+ {
12492
+ name: "Set Cover",
12493
+ subtitle: "Minimum Coverage",
12494
+ description: "Choose the fewest subsets that together cover all elements. Used for sensor placement, test suite minimization, and service location planning.",
12495
+ asciiDiagram: [
12496
+ "Universe: {1,2,3,4,5,6,7}",
12497
+ "S1={1,2,3} S2={2,4} S3={3,4,5}",
12498
+ "S4={5,6,7} S5={1,6}",
12499
+ "Solution: S1 + S3 + S4 (covers all)"
12500
+ ].join("\n"),
12501
+ quboFitStars: 4
12502
+ }
12503
+ ],
12504
+ quboExplainer: "Binary variable x(i) = 1 if item i is selected. For portfolio: minimize x^T * Sigma * x - lambda * mu^T * x where Sigma is covariance and mu is expected return. The quadratic form IS the QUBO \u2014 no conversion needed.",
12505
+ useCases: [
12506
+ { industry: "Finance", application: "Portfolio construction" },
12507
+ { industry: "Machine Learning", application: "Feature subset selection" },
12508
+ { industry: "Telecom", application: "Cell tower placement" },
12509
+ { industry: "Insurance", application: "Product bundle selection" },
12510
+ { industry: "Military", application: "Sensor network deployment" }
12511
+ ]
12512
+ },
12513
+ {
12514
+ id: "economic",
12515
+ name: "Economic",
12516
+ description: "Market equilibrium, auction design, pricing",
12517
+ complexity: "NP-hard",
12518
+ color: "#ab47bc",
12519
+ quboFit: "experimental",
12520
+ examples: ["Market Clearing", "Auction Optimization", "Price Discovery"],
12521
+ status: "coming-soon",
12522
+ tagline: "Finding optimal prices and market equilibria",
12523
+ asciiDiagram: [
12524
+ " P \u2502\\ /",
12525
+ " \u2502 \\ / Supply",
12526
+ " \u2502 \\/",
12527
+ " \u2502 /\\ \u2190 equilibrium",
12528
+ " \u2502 / \\",
12529
+ " \u2502/ \\ Demand",
12530
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Q"
12531
+ ].join("\n"),
12532
+ subPatterns: [
12533
+ {
12534
+ name: "Market Clearing",
12535
+ subtitle: "Equilibrium",
12536
+ description: "Find prices where supply meets demand across multiple goods simultaneously. Power grid markets clear hourly; financial exchanges clear in microseconds.",
12537
+ asciiDiagram: [
12538
+ "Buyers: B1=$50 B2=$40 B3=$30",
12539
+ "Sellers: S1=$20 S2=$35 S3=$45",
12540
+ "Clear price: $35-40 (2 trades)",
12541
+ "Maximize social welfare"
12542
+ ].join("\n"),
12543
+ quboFitStars: 3
12544
+ },
12545
+ {
12546
+ name: "Combinatorial Auction",
12547
+ subtitle: "Bundle Bidding",
12548
+ description: "Bidders submit bids on bundles of items. Winner determination maximizes revenue while ensuring each item sold at most once. Directly maps to weighted set packing.",
12549
+ asciiDiagram: [
12550
+ "Bid 1: {A,B} = $100",
12551
+ "Bid 2: {B,C} = $80",
12552
+ "Bid 3: {A} = $60",
12553
+ "Bid 4: {C} = $50",
12554
+ "Best: Bid 1 + Bid 4 = $150"
12555
+ ].join("\n"),
12556
+ quboFitStars: 4
12557
+ },
12558
+ {
12559
+ name: "Pricing Optimization",
12560
+ subtitle: "Revenue Maximization",
12561
+ description: "Set prices across products to maximize total revenue considering demand elasticity, competition, and cross-product effects (substitutes and complements).",
12562
+ asciiDiagram: [
12563
+ "Price Demand Revenue",
12564
+ " $10 100 $1000",
12565
+ " $15 70 $1050 <- optimal",
12566
+ " $20 40 $800",
12567
+ " $25 15 $375"
12568
+ ].join("\n"),
12569
+ quboFitStars: 2
12570
+ }
12571
+ ],
12572
+ quboExplainer: "Auction winner determination: x(i) = 1 if bid i is accepted. Maximize sum of bid values. Constraint: for each item, sum of accepted bids containing that item <= 1. Requires discretizing continuous prices into binary tiers for QUBO encoding.",
12573
+ useCases: [
12574
+ { industry: "Energy", application: "Power market clearing" },
12575
+ { industry: "Advertising", application: "Ad auction optimization" },
12576
+ { industry: "Spectrum", application: "FCC spectrum auctions" },
12577
+ { industry: "Retail", application: "Dynamic pricing strategy" },
12578
+ { industry: "Agriculture", application: "Commodity market design" }
12579
+ ]
12580
+ },
12581
+ {
12582
+ id: "continuous",
12583
+ name: "Continuous",
12584
+ description: "Continuous optimization with discretization",
12585
+ complexity: "NP-hard",
12586
+ color: "#78909c",
12587
+ quboFit: "fair",
12588
+ examples: ["Parameter Tuning", "Function Optimization", "Calibration"],
12589
+ status: "coming-soon",
12590
+ tagline: "Finding the best point in continuous space",
12591
+ asciiDiagram: [
12592
+ " f(x)",
12593
+ " \u2502 \u2571\u2572",
12594
+ " \u2502 \u2571 \u2572 \u2571\u2572",
12595
+ " \u2502\u2571 \u2572 \u2571 \u2572",
12596
+ " \u2502 \u2573 \u2572",
12597
+ " \u2502 \u2191 min \u2572",
12598
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 x"
12599
+ ].join("\n"),
12600
+ subPatterns: [
12601
+ {
12602
+ name: "Parameter Tuning",
12603
+ subtitle: "Find the Sweet Spot",
12604
+ description: "Optimize continuous parameters (temperature, pressure, learning rate) by discretizing into binary-encoded levels. Each parameter gets log2(levels) qubits.",
12605
+ asciiDiagram: [
12606
+ "Param A: [0.1, 0.2, 0.3, 0.4]",
12607
+ "Param B: [10, 20, 30, 40, 50]",
12608
+ "",
12609
+ "Encode: 2 bits per param (4 levels)",
12610
+ "Search 4x5 = 20 combinations"
12611
+ ].join("\n"),
12612
+ quboFitStars: 3
12613
+ },
12614
+ {
12615
+ name: "Function Minimization",
12616
+ subtitle: "Global Optimum",
12617
+ description: "Find the global minimum of a multivariate function with many local minima. Discretize the domain and encode as QUBO. Quantum tunneling helps escape local optima.",
12618
+ asciiDiagram: [
12619
+ "f(x) ^",
12620
+ " | /\\ /\\",
12621
+ " | / \\ / \\",
12622
+ " |/ \\/ \\",
12623
+ " | global \\",
12624
+ " +-----min-----> x"
12625
+ ].join("\n"),
12626
+ quboFitStars: 3
12627
+ },
12628
+ {
12629
+ name: "Calibration",
12630
+ subtitle: "Model Fitting",
12631
+ description: "Adjust model parameters to best fit observed data. When the error landscape is non-convex, classical gradient descent gets stuck. QUBO explores the full landscape.",
12632
+ asciiDiagram: [
12633
+ "Data: * * * * * *",
12634
+ "Model: ----\\--/--------",
12635
+ " \\/ <- fit here",
12636
+ "Minimize: sum(error^2)"
12637
+ ].join("\n"),
12638
+ quboFitStars: 2
12639
+ }
12640
+ ],
12641
+ quboExplainer: "Continuous variables are discretized into binary representation. For N levels, use log2(N) qubits per variable. The continuous objective function is approximated as a polynomial in binary variables, yielding a QUBO. Precision trades off against qubit count.",
12642
+ useCases: [
12643
+ { industry: "Engineering", application: "Design parameter optimization" },
12644
+ { industry: "ML/AI", application: "Hyperparameter tuning" },
12645
+ { industry: "Chemistry", application: "Reaction condition optimization" },
12646
+ { industry: "Finance", application: "Model calibration" },
12647
+ { industry: "Manufacturing", application: "Process control tuning" }
12648
+ ]
12649
+ }
12650
+ ];
12651
+
11704
12652
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/quantumSchedule/index.js
11705
12653
  function formatResult(result) {
11706
12654
  const lines = [
@@ -11925,14 +12873,15 @@ ${problem.description}` : "",
11925
12873
  "### Machines:",
11926
12874
  ...problem.machines.map((m) => `- ${m.name} (id: ${m.id})`),
11927
12875
  "",
11928
- "### Structured Problem (JSON):",
11929
- "```json",
11930
- JSON.stringify(problem, null, 2),
11931
- "```",
11932
- "",
11933
- "You can now use the `quantum_schedule` tool to solve this problem with various optimization algorithms."
12876
+ 'A problem is ready to load. Navigate to the Problem tab and click "Load Problem" to review, tweak, and run solvers.'
11934
12877
  ];
11935
- return lines.filter((l) => l !== void 0).join("\n");
12878
+ const humanReadableSummary = lines.filter((l) => l !== void 0).join("\n");
12879
+ return JSON.stringify({
12880
+ __uiSideEffect: true,
12881
+ type: "populateProblem",
12882
+ payload: problem,
12883
+ displayMessage: humanReadableSummary
12884
+ });
11936
12885
  } catch (err) {
11937
12886
  return `Error formulating problem: ${err instanceof Error ? err.message : String(err)}`;
11938
12887
  }
@@ -16733,6 +17682,10 @@ var ServerLlmBackend = class {
16733
17682
  */
16734
17683
  getFallbackModels() {
16735
17684
  return [
17685
+ {
17686
+ id: "claude-sonnet-4-6",
17687
+ name: "Claude 4.6 Sonnet"
17688
+ },
16736
17689
  {
16737
17690
  id: "claude-sonnet-4-5-20250929",
16738
17691
  name: "Claude 4.5 Sonnet"
@@ -16943,6 +17896,7 @@ var WebSocketLlmBackend = class {
16943
17896
  }
16944
17897
  getFallbackModels() {
16945
17898
  return [
17899
+ { id: "claude-sonnet-4-6", name: "Claude 4.6 Sonnet" },
16946
17900
  { id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
16947
17901
  { id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
16948
17902
  { id: "gpt-4o", name: "GPT-4o" },
@@ -17844,6 +18798,7 @@ var MODEL_ALIASES = {
17844
18798
  "claude-haiku": "claude-3-5-haiku-20241022",
17845
18799
  // Version-specific Claude aliases
17846
18800
  "claude-4.6-opus": "claude-opus-4-6",
18801
+ "claude-4.6-sonnet": "claude-sonnet-4-6",
17847
18802
  "claude-4.5-opus": "claude-opus-4-5-20251101",
17848
18803
  "claude-4.5-sonnet": "claude-sonnet-4-5-20250929",
17849
18804
  "claude-4.5-haiku": "claude-haiku-4-5-20251001",
@@ -18605,8 +19560,8 @@ function createBackgroundAgentTools(manager) {
18605
19560
  case "queued":
18606
19561
  return `Agent "${job.agentName}" is queued (waiting for a concurrency slot). Task: ${job.task}`;
18607
19562
  case "running": {
18608
- const elapsed = Math.round((Date.now() - job.startTime) / 1e3);
18609
- return `Agent "${job.agentName}" is still running (${elapsed}s elapsed). Task: ${job.task}`;
19563
+ const elapsed2 = Math.round((Date.now() - job.startTime) / 1e3);
19564
+ return `Agent "${job.agentName}" is still running (${elapsed2}s elapsed). Task: ${job.task}`;
18610
19565
  }
18611
19566
  case "completed": {
18612
19567
  const result = manager.getResult(job_id);
@@ -18638,7 +19593,7 @@ function createBackgroundAgentTools(manager) {
18638
19593
  const jobs = manager.listJobs();
18639
19594
  if (jobs.length === 0) return "No background agents.";
18640
19595
  return jobs.map((job) => {
18641
- const elapsed = Math.round(((job.endTime || Date.now()) - job.startTime) / 1e3);
19596
+ const elapsed2 = Math.round(((job.endTime || Date.now()) - job.startTime) / 1e3);
18642
19597
  const statusIcons = {
18643
19598
  queued: "\u{1F550}",
18644
19599
  running: "\u23F3",
@@ -18647,7 +19602,7 @@ function createBackgroundAgentTools(manager) {
18647
19602
  cancelled: "\u{1F6AB}"
18648
19603
  };
18649
19604
  const statusIcon = statusIcons[job.status] || "\u2753";
18650
- return `${statusIcon} [${job.id}] ${job.agentName} (${job.status}, ${elapsed}s) - ${job.task.slice(0, 80)}`;
19605
+ return `${statusIcon} [${job.id}] ${job.agentName} (${job.status}, ${elapsed2}s) - ${job.task.slice(0, 80)}`;
18651
19606
  }).join("\n");
18652
19607
  },
18653
19608
  toolSchema: {