dsh-codex-subscription 2.2.11 → 2.4.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.
package/lib/client.js CHANGED
@@ -2321,6 +2321,796 @@ window.__ModuleLoader__.load({
2321
2321
  }))
2322
2322
  };
2323
2323
  }
2324
+ //#endregion
2325
+ //#region src/sketch-svg.js
2326
+ const MAX_SVG_CHARACTERS = 2e5;
2327
+ const MAX_BEZIER_SEGMENTS = 64;
2328
+ const FLATTEN_STEPS = 10;
2329
+ const NAMED_COLORS = {
2330
+ black: "#000000",
2331
+ white: "#ffffff",
2332
+ red: "#ff0000",
2333
+ green: "#008000",
2334
+ blue: "#0000ff",
2335
+ yellow: "#ffff00",
2336
+ orange: "#ffa500",
2337
+ purple: "#800080",
2338
+ pink: "#ffc0cb",
2339
+ brown: "#a52a2a",
2340
+ gray: "#808080",
2341
+ grey: "#808080",
2342
+ silver: "#c0c0c0",
2343
+ gold: "#ffd700",
2344
+ navy: "#000080",
2345
+ teal: "#008080",
2346
+ maroon: "#800000",
2347
+ olive: "#808000",
2348
+ lime: "#00ff00",
2349
+ aqua: "#00ffff",
2350
+ cyan: "#00ffff",
2351
+ magenta: "#ff00ff",
2352
+ fuchsia: "#ff00ff",
2353
+ ivory: "#fffff0",
2354
+ beige: "#f5f5dc",
2355
+ tan: "#d2b48c",
2356
+ khaki: "#f0e68c",
2357
+ coral: "#ff7f50",
2358
+ salmon: "#fa8072",
2359
+ crimson: "#dc143c",
2360
+ indigo: "#4b0082",
2361
+ violet: "#ee82ee",
2362
+ turquoise: "#40e0d0",
2363
+ skyblue: "#87ceeb",
2364
+ darkgray: "#a9a9a9",
2365
+ darkgrey: "#a9a9a9",
2366
+ lightgray: "#d3d3d3",
2367
+ lightgrey: "#d3d3d3",
2368
+ darkred: "#8b0000",
2369
+ darkgreen: "#006400",
2370
+ darkblue: "#00008b",
2371
+ transparent: "none"
2372
+ };
2373
+ const UNSUPPORTED = /* @__PURE__ */ new Set([
2374
+ "text",
2375
+ "tspan",
2376
+ "image",
2377
+ "foreignObject",
2378
+ "filter",
2379
+ "clipPath",
2380
+ "mask",
2381
+ "pattern",
2382
+ "style",
2383
+ "script",
2384
+ "switch",
2385
+ "marker",
2386
+ "symbol"
2387
+ ]);
2388
+ const IGNORED = /* @__PURE__ */ new Set([
2389
+ "title",
2390
+ "desc",
2391
+ "metadata",
2392
+ "defs",
2393
+ "linearGradient",
2394
+ "radialGradient",
2395
+ "stop",
2396
+ "namedview",
2397
+ "sodipodi:namedview"
2398
+ ]);
2399
+ const decode = (value) => value.split("&quot;").join("\"").split("&apos;").join("'").split("&lt;").join("<").split("&gt;").join(">").split("&amp;").join("&");
2400
+ function parseXml(text) {
2401
+ const tag = /<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<!\[CDATA\[[\s\S]*?\]\]>|<!DOCTYPE[^>]*>|<(\/?)([A-Za-z_][\w:.-]*)((?:\s+[^\s=/>]+\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(\/?)>/g;
2402
+ const attribute = /([^\s=/>]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
2403
+ const root = {
2404
+ name: "#root",
2405
+ attrs: {},
2406
+ children: []
2407
+ };
2408
+ const stack = [root];
2409
+ for (let match = tag.exec(text); match; match = tag.exec(text)) {
2410
+ if (match[2] === void 0) continue;
2411
+ if (match[1] === "/") {
2412
+ if (stack.length > 1 && stack.at(-1).name === match[2]) stack.pop();
2413
+ else throw Error(`SVG is malformed: unexpected </${match[2]}>`);
2414
+ continue;
2415
+ }
2416
+ const attrs = {};
2417
+ for (let item = attribute.exec(match[3]); item; item = attribute.exec(match[3])) attrs[item[1]] = decode(item[2] ?? item[3]);
2418
+ const node = {
2419
+ name: match[2],
2420
+ attrs,
2421
+ children: []
2422
+ };
2423
+ stack.at(-1).children.push(node);
2424
+ if (match[4] !== "/") stack.push(node);
2425
+ }
2426
+ if (stack.length !== 1) throw Error(`SVG is malformed: <${stack.at(-1).name}> is not closed`);
2427
+ return root;
2428
+ }
2429
+ const IDENTITY = [
2430
+ 1,
2431
+ 0,
2432
+ 0,
2433
+ 1,
2434
+ 0,
2435
+ 0
2436
+ ];
2437
+ const multiply = (m, n) => [
2438
+ m[0] * n[0] + m[2] * n[1],
2439
+ m[1] * n[0] + m[3] * n[1],
2440
+ m[0] * n[2] + m[2] * n[3],
2441
+ m[1] * n[2] + m[3] * n[3],
2442
+ m[0] * n[4] + m[2] * n[5] + m[4],
2443
+ m[1] * n[4] + m[3] * n[5] + m[5]
2444
+ ];
2445
+ const apply$1 = (m, x, y) => [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
2446
+ const NUMBER = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/g;
2447
+ const numbers = (text) => (String(text ?? "").match(NUMBER) ?? []).map(Number);
2448
+ function parseTransform(text) {
2449
+ let matrix = IDENTITY;
2450
+ const source = String(text ?? "");
2451
+ const item = /(matrix|translate|scale|rotate|skewX|skewY)\s*\(([^)]*)\)/g;
2452
+ if (source.replace(item, "").replace(/[\s,]/g, "")) throw Error(`Unsupported SVG transform: ${source}`);
2453
+ for (let match = item.exec(source); match; match = item.exec(source)) {
2454
+ const v = numbers(match[2]);
2455
+ let next;
2456
+ if (match[1] === "matrix" && v.length === 6) next = v;
2457
+ else if (match[1] === "translate" && v.length >= 1) next = [
2458
+ 1,
2459
+ 0,
2460
+ 0,
2461
+ 1,
2462
+ v[0],
2463
+ v[1] ?? 0
2464
+ ];
2465
+ else if (match[1] === "scale" && v.length >= 1) next = [
2466
+ v[0],
2467
+ 0,
2468
+ 0,
2469
+ v[1] ?? v[0],
2470
+ 0,
2471
+ 0
2472
+ ];
2473
+ else if (match[1] === "rotate" && v.length >= 1) {
2474
+ const a = v[0] * Math.PI / 180, c = Math.cos(a), s = Math.sin(a);
2475
+ const turn = [
2476
+ c,
2477
+ s,
2478
+ -s,
2479
+ c,
2480
+ 0,
2481
+ 0
2482
+ ];
2483
+ next = v.length >= 3 ? multiply(multiply([
2484
+ 1,
2485
+ 0,
2486
+ 0,
2487
+ 1,
2488
+ v[1],
2489
+ v[2]
2490
+ ], turn), [
2491
+ 1,
2492
+ 0,
2493
+ 0,
2494
+ 1,
2495
+ -v[1],
2496
+ -v[2]
2497
+ ]) : turn;
2498
+ } else if (match[1] === "skewX" && v.length === 1) next = [
2499
+ 1,
2500
+ 0,
2501
+ Math.tan(v[0] * Math.PI / 180),
2502
+ 1,
2503
+ 0,
2504
+ 0
2505
+ ];
2506
+ else if (match[1] === "skewY" && v.length === 1) next = [
2507
+ 1,
2508
+ Math.tan(v[0] * Math.PI / 180),
2509
+ 0,
2510
+ 1,
2511
+ 0,
2512
+ 0
2513
+ ];
2514
+ else throw Error(`Unsupported SVG transform: ${match[0]}`);
2515
+ matrix = multiply(matrix, next);
2516
+ }
2517
+ return matrix;
2518
+ }
2519
+ function parseColor(value) {
2520
+ const text = String(value ?? "").trim().toLowerCase();
2521
+ if (!text || text === "none") return "none";
2522
+ if (text === "currentcolor") return "#000000";
2523
+ if (Object.hasOwn(NAMED_COLORS, text)) return NAMED_COLORS[text];
2524
+ const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/.exec(text);
2525
+ if (hex) return hex[1].length === 3 ? `#${[...hex[1]].map((ch) => ch + ch).join("")}` : text;
2526
+ const rgb = /^rgba?\(([^)]*)\)$/.exec(text);
2527
+ if (rgb) {
2528
+ const parts = rgb[1].split(/[\s,/]+/).filter(Boolean);
2529
+ const channel = (part) => Math.max(0, Math.min(255, Math.round(part.endsWith("%") ? parseFloat(part) * 2.55 : parseFloat(part))));
2530
+ if (parts.length >= 3) return `#${parts.slice(0, 3).map((part) => channel(part).toString(16).padStart(2, "0")).join("")}`;
2531
+ }
2532
+ throw Error(`Unsupported SVG color: ${value}. Use #rrggbb, #rgb, rgb(), a basic color name, none, or a gradient id.`);
2533
+ }
2534
+ function styleOf(node, parent) {
2535
+ const own = { ...node.attrs };
2536
+ if (own.style) for (const rule of own.style.split(";")) {
2537
+ const at = rule.indexOf(":");
2538
+ if (at > 0) own[rule.slice(0, at).trim()] = rule.slice(at + 1).trim();
2539
+ }
2540
+ const pick = (name, fallback) => own[name] === void 0 || own[name] === "inherit" ? fallback : own[name];
2541
+ const number = (name, fallback) => {
2542
+ const value = pick(name, void 0);
2543
+ return value === void 0 ? fallback : Number.parseFloat(value);
2544
+ };
2545
+ return {
2546
+ fill: pick("fill", parent.fill),
2547
+ stroke: pick("stroke", parent.stroke),
2548
+ strokeWidth: number("stroke-width", parent.strokeWidth),
2549
+ fillOpacity: number("fill-opacity", parent.fillOpacity),
2550
+ strokeOpacity: number("stroke-opacity", parent.strokeOpacity),
2551
+ opacity: parent.opacity * number("opacity", 1),
2552
+ display: own.display === "none" || own.visibility === "hidden" ? "none" : "inline"
2553
+ };
2554
+ }
2555
+ function arcToCubics(x1, y1, rx, ry, rotation, large, sweep, x2, y2) {
2556
+ if (x1 === x2 && y1 === y2) return [];
2557
+ rx = Math.abs(rx);
2558
+ ry = Math.abs(ry);
2559
+ if (!rx || !ry) return [[
2560
+ x1,
2561
+ y1,
2562
+ x2,
2563
+ y2,
2564
+ x2,
2565
+ y2
2566
+ ]];
2567
+ const phi = rotation * Math.PI / 180, cos = Math.cos(phi), sin = Math.sin(phi);
2568
+ const dx = (x1 - x2) / 2, dy = (y1 - y2) / 2;
2569
+ const x1p = cos * dx + sin * dy, y1p = -sin * dx + cos * dy;
2570
+ const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
2571
+ if (lambda > 1) {
2572
+ rx *= Math.sqrt(lambda);
2573
+ ry *= Math.sqrt(lambda);
2574
+ }
2575
+ const sign = large === sweep ? -1 : 1;
2576
+ const numerator = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
2577
+ const denominator = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
2578
+ const factor = sign * Math.sqrt(Math.max(0, numerator / denominator));
2579
+ const cxp = factor * rx * y1p / ry, cyp = -factor * ry * x1p / rx;
2580
+ const cx = cos * cxp - sin * cyp + (x1 + x2) / 2, cy = sin * cxp + cos * cyp + (y1 + y2) / 2;
2581
+ const angle = (ux, uy, vx, vy) => Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);
2582
+ const theta = angle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
2583
+ let delta = angle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);
2584
+ if (!sweep && delta > 0) delta -= 2 * Math.PI;
2585
+ if (sweep && delta < 0) delta += 2 * Math.PI;
2586
+ const count = Math.max(1, Math.ceil(Math.abs(delta) / (Math.PI / 2) - 1e-9));
2587
+ const step = delta / count, k = 4 / 3 * Math.tan(step / 4);
2588
+ const out = [];
2589
+ for (let index = 0; index < count; index++) {
2590
+ const a1 = theta + index * step, a2 = a1 + step;
2591
+ const point = (a, scale) => {
2592
+ const px = rx * Math.cos(a), py = ry * Math.sin(a);
2593
+ const tx = -rx * Math.sin(a) * scale, ty = ry * Math.cos(a) * scale;
2594
+ return [
2595
+ cos * px - sin * py + cx,
2596
+ sin * px + cos * py + cy,
2597
+ cos * tx - sin * ty,
2598
+ sin * tx + cos * ty
2599
+ ];
2600
+ };
2601
+ const p1 = point(a1, k), p2 = point(a2, k);
2602
+ out.push([
2603
+ p1[0] + p1[2],
2604
+ p1[1] + p1[3],
2605
+ p2[0] - p2[2],
2606
+ p2[1] - p2[3],
2607
+ p2[0],
2608
+ p2[1]
2609
+ ]);
2610
+ }
2611
+ return out;
2612
+ }
2613
+ function parsePathData(data) {
2614
+ const source = String(data ?? "");
2615
+ const subpaths = [];
2616
+ let index = 0, command = "", current, x = 0, y = 0, startX = 0, startY = 0, lastControl, lastCommand = "";
2617
+ const skip = () => {
2618
+ while (index < source.length && /[\s,]/.test(source[index])) index++;
2619
+ };
2620
+ const readNumber = () => {
2621
+ skip();
2622
+ NUMBER.lastIndex = index;
2623
+ const match = NUMBER.exec(source);
2624
+ if (!match || match.index !== index) throw Error(`Malformed SVG path data near "${source.slice(index, index + 12)}"`);
2625
+ index = NUMBER.lastIndex;
2626
+ return Number(match[0]);
2627
+ };
2628
+ const readFlag = () => {
2629
+ skip();
2630
+ const ch = source[index];
2631
+ if (ch !== "0" && ch !== "1") throw Error("Malformed SVG arc flag in path data");
2632
+ index++;
2633
+ return ch === "1";
2634
+ };
2635
+ const begin = (px, py) => {
2636
+ current = {
2637
+ start: [px, py],
2638
+ curves: [],
2639
+ closed: false,
2640
+ straight: true
2641
+ };
2642
+ subpaths.push(current);
2643
+ };
2644
+ const line = (px, py) => {
2645
+ current.curves.push([
2646
+ x,
2647
+ y,
2648
+ px,
2649
+ py,
2650
+ px,
2651
+ py
2652
+ ]);
2653
+ x = px;
2654
+ y = py;
2655
+ };
2656
+ const cubic = (c1x, c1y, c2x, c2y, px, py) => {
2657
+ current.curves.push([
2658
+ c1x,
2659
+ c1y,
2660
+ c2x,
2661
+ c2y,
2662
+ px,
2663
+ py
2664
+ ]);
2665
+ current.straight = false;
2666
+ lastControl = [c2x, c2y];
2667
+ x = px;
2668
+ y = py;
2669
+ };
2670
+ for (;;) {
2671
+ skip();
2672
+ if (index >= source.length) break;
2673
+ if (/[MmLlHhVvCcSsQqTtAaZz]/.test(source[index])) command = source[index++];
2674
+ else if (!command) throw Error("SVG path data must start with a command");
2675
+ else if (command === "M") command = "L";
2676
+ else if (command === "m") command = "l";
2677
+ else if (command === "Z" || command === "z") throw Error("Unexpected number after Z in SVG path data");
2678
+ const relative = command === command.toLowerCase();
2679
+ const upper = command.toUpperCase();
2680
+ const ox = relative ? x : 0, oy = relative ? y : 0;
2681
+ if (upper === "M") {
2682
+ const px = readNumber() + ox, py = readNumber() + oy;
2683
+ x = startX = px;
2684
+ y = startY = py;
2685
+ begin(px, py);
2686
+ lastControl = void 0;
2687
+ } else if (upper === "Z") {
2688
+ if (current && !current.closed) {
2689
+ if (x !== startX || y !== startY) line(startX, startY);
2690
+ current.closed = true;
2691
+ }
2692
+ x = startX;
2693
+ y = startY;
2694
+ lastControl = void 0;
2695
+ current = void 0;
2696
+ } else {
2697
+ if (!current) {
2698
+ begin(x, y);
2699
+ startX = x;
2700
+ startY = y;
2701
+ }
2702
+ if (upper === "L") line(readNumber() + ox, readNumber() + oy);
2703
+ else if (upper === "H") line(readNumber() + ox, y);
2704
+ else if (upper === "V") line(x, readNumber() + oy);
2705
+ else if (upper === "C") cubic(readNumber() + ox, readNumber() + oy, readNumber() + ox, readNumber() + oy, readNumber() + ox, readNumber() + oy);
2706
+ else if (upper === "S") {
2707
+ const [rx, ry] = lastControl && lastCommand && "CScs".includes(lastCommand) ? [2 * x - lastControl[0], 2 * y - lastControl[1]] : [x, y];
2708
+ cubic(rx, ry, readNumber() + ox, readNumber() + oy, readNumber() + ox, readNumber() + oy);
2709
+ } else if (upper === "Q" || upper === "T") {
2710
+ let qx, qy;
2711
+ if (upper === "Q") {
2712
+ qx = readNumber() + ox;
2713
+ qy = readNumber() + oy;
2714
+ } else [qx, qy] = lastControl && lastCommand && "QTqt".includes(lastCommand) ? [2 * x - lastControl[0], 2 * y - lastControl[1]] : [x, y];
2715
+ const px = readNumber() + ox, py = readNumber() + oy;
2716
+ const from = [x, y];
2717
+ cubic(from[0] + 2 / 3 * (qx - from[0]), from[1] + 2 / 3 * (qy - from[1]), px + 2 / 3 * (qx - px), py + 2 / 3 * (qy - py), px, py);
2718
+ lastControl = [qx, qy];
2719
+ } else if (upper === "A") {
2720
+ const rx = readNumber(), ry = readNumber(), rotation = readNumber(), large = readFlag(), sweep = readFlag();
2721
+ const px = readNumber() + ox, py = readNumber() + oy;
2722
+ const pieces = arcToCubics(x, y, rx, ry, rotation, large, sweep, px, py);
2723
+ for (const piece of pieces) cubic(...piece);
2724
+ if (!pieces.length) {
2725
+ x = px;
2726
+ y = py;
2727
+ }
2728
+ lastControl = void 0;
2729
+ } else throw Error(`Unsupported SVG path command: ${command}`);
2730
+ }
2731
+ lastCommand = command;
2732
+ }
2733
+ return subpaths.filter((subpath) => subpath.curves.length > 0);
2734
+ }
2735
+ const ellipsePath = (cx, cy, rx, ry) => {
2736
+ const k = .5522847498;
2737
+ return {
2738
+ start: [cx + rx, cy],
2739
+ closed: true,
2740
+ straight: false,
2741
+ curves: [
2742
+ [
2743
+ cx + rx,
2744
+ cy + ry * k,
2745
+ cx + rx * k,
2746
+ cy + ry,
2747
+ cx,
2748
+ cy + ry
2749
+ ],
2750
+ [
2751
+ cx - rx * k,
2752
+ cy + ry,
2753
+ cx - rx,
2754
+ cy + ry * k,
2755
+ cx - rx,
2756
+ cy
2757
+ ],
2758
+ [
2759
+ cx - rx,
2760
+ cy - ry * k,
2761
+ cx - rx * k,
2762
+ cy - ry,
2763
+ cx,
2764
+ cy - ry
2765
+ ],
2766
+ [
2767
+ cx + rx * k,
2768
+ cy - ry,
2769
+ cx + rx,
2770
+ cy - ry * k,
2771
+ cx + rx,
2772
+ cy
2773
+ ]
2774
+ ]
2775
+ };
2776
+ };
2777
+ const polylinePath = (points, closed) => {
2778
+ const path = {
2779
+ start: points[0],
2780
+ curves: [],
2781
+ closed,
2782
+ straight: true
2783
+ };
2784
+ let [x, y] = points[0];
2785
+ for (const [px, py] of points.slice(1)) {
2786
+ path.curves.push([
2787
+ x,
2788
+ y,
2789
+ px,
2790
+ py,
2791
+ px,
2792
+ py
2793
+ ]);
2794
+ x = px;
2795
+ y = py;
2796
+ }
2797
+ if (closed && (x !== points[0][0] || y !== points[0][1])) path.curves.push([
2798
+ x,
2799
+ y,
2800
+ points[0][0],
2801
+ points[0][1],
2802
+ points[0][0],
2803
+ points[0][1]
2804
+ ]);
2805
+ return path;
2806
+ };
2807
+ const roundedRectPath = (x, y, w, h, rx, ry) => {
2808
+ rx = Math.min(rx, w / 2);
2809
+ ry = Math.min(ry, h / 2);
2810
+ const k = .5522847498;
2811
+ const curves = [];
2812
+ let cx = x + rx, cy = y;
2813
+ const go = (...piece) => {
2814
+ curves.push(piece);
2815
+ cx = piece[4];
2816
+ cy = piece[5];
2817
+ };
2818
+ go(cx, cy, x + w - rx, y, x + w - rx, y);
2819
+ go(x + w - rx + rx * k, y, x + w, y + ry - ry * k, x + w, y + ry);
2820
+ go(x + w, y + ry, x + w, y + h - ry, x + w, y + h - ry);
2821
+ go(x + w, y + h - ry + ry * k, x + w - rx + rx * k, y + h, x + w - rx, y + h);
2822
+ go(x + w - rx, y + h, x + rx, y + h, x + rx, y + h);
2823
+ go(x + rx - rx * k, y + h, x, y + h - ry + ry * k, x, y + h - ry);
2824
+ go(x, y + h - ry, x, y + ry, x, y + ry);
2825
+ go(x, y + ry - ry * k, x + rx - rx * k, y, x + rx, y);
2826
+ return {
2827
+ start: [x + rx, y],
2828
+ curves,
2829
+ closed: true,
2830
+ straight: false
2831
+ };
2832
+ };
2833
+ function svgToSketchCommands(text, { width, height, layer, existingIds = [] }) {
2834
+ if (typeof text !== "string" || !text.trim()) throw Error("svg must be a non-empty SVG document");
2835
+ if (text.length > 2e5) throw Error(`svg is too large: ${text.length} characters, limit ${MAX_SVG_CHARACTERS}. Split it across several svg commands.`);
2836
+ const root = parseXml(text).children.find((node) => node.name === "svg");
2837
+ if (!root) throw Error("svg must contain an <svg> element");
2838
+ const box = numbers(root.attrs.viewBox);
2839
+ const viewWidth = box.length === 4 ? box[2] : Number.parseFloat(root.attrs.width);
2840
+ const viewHeight = box.length === 4 ? box[3] : Number.parseFloat(root.attrs.height);
2841
+ const originX = box.length === 4 ? box[0] : 0, originY = box.length === 4 ? box[1] : 0;
2842
+ if (!(viewWidth > 0 && viewHeight > 0)) throw Error("<svg> needs a viewBox=\"0 0 W H\" (or width and height)");
2843
+ if (Math.abs(viewWidth / viewHeight - width / height) > .01 * (width / height)) throw Error(`SVG viewBox ${viewWidth}x${viewHeight} does not match the ${width}x${height} sketch ratio. Use viewBox="0 0 ${width} ${height}".`);
2844
+ const byId = /* @__PURE__ */ new Map();
2845
+ const index = (node) => {
2846
+ if (node.attrs.id) byId.set(node.attrs.id, node);
2847
+ node.children.forEach(index);
2848
+ };
2849
+ index(root);
2850
+ const warnings = /* @__PURE__ */ new Set();
2851
+ const used = new Set(existingIds);
2852
+ let counter = 0, clamped = 0;
2853
+ const nextId = (suffix) => {
2854
+ for (;;) {
2855
+ counter++;
2856
+ const id = `svg-${counter}${suffix}`;
2857
+ if (!used.has(id)) {
2858
+ used.add(id);
2859
+ return id;
2860
+ }
2861
+ }
2862
+ };
2863
+ const scale = width / viewWidth;
2864
+ const commands = [];
2865
+ const clamp = (value) => {
2866
+ if (value < 0 || value > 1) clamped++;
2867
+ return Math.max(0, Math.min(1, value));
2868
+ };
2869
+ const norm = (matrix, px, py) => {
2870
+ const [tx, ty] = apply$1(matrix, px, py);
2871
+ return {
2872
+ x: clamp((tx - originX) / viewWidth),
2873
+ y: clamp((ty - originY) / viewHeight)
2874
+ };
2875
+ };
2876
+ const gradientColor = (reference) => {
2877
+ const target = byId.get(/^url\(\s*['"]?#([^)'"]+)['"]?\s*\)/.exec(reference)?.[1] ?? "");
2878
+ if (!target || !/Gradient$/.test(target.name)) throw Error(`SVG paint ${reference} does not reference a gradient defined in the same SVG`);
2879
+ const stops = target.children.filter((child) => child.name === "stop");
2880
+ if (!stops.length) throw Error(`Gradient ${target.attrs.id} has no stops`);
2881
+ const channels = stops.map((stop) => parseColor(stop.attrs["stop-color"] ?? /stop-color\s*:\s*([^;]+)/.exec(stop.attrs.style ?? "")?.[1] ?? "#000000")).filter((color) => color !== "none").map((color) => [
2882
+ 1,
2883
+ 3,
2884
+ 5
2885
+ ].map((offset) => Number.parseInt(color.slice(offset, offset + 2), 16)));
2886
+ const mean = [
2887
+ 0,
2888
+ 1,
2889
+ 2
2890
+ ].map((channel) => Math.round(channels.reduce((sum, item) => sum + item[channel], 0) / channels.length));
2891
+ warnings.add(`Gradient ${target.attrs.id} was flattened to its average color; stack several bands for a real gradient.`);
2892
+ return `#${mean.map((value) => value.toString(16).padStart(2, "0")).join("")}`;
2893
+ };
2894
+ const paint = (value) => String(value).startsWith("url(") ? gradientColor(value) : parseColor(value);
2895
+ const emit = (subpath, matrix, style, id) => {
2896
+ [subpath.start, ...subpath.curves.flatMap((curve) => [
2897
+ [curve[0], curve[1]],
2898
+ [curve[2], curve[3]],
2899
+ [curve[4], curve[5]]
2900
+ ])];
2901
+ const fill = style.fill === "none" ? "none" : paint(style.fill);
2902
+ const stroke = style.stroke === "none" ? "none" : paint(style.stroke);
2903
+ const common = layer === void 0 ? {} : { layer };
2904
+ const strokeWidth = Math.max(1, Math.min(256, (style.strokeWidth || 1) * scale * Math.hypot(matrix[0], matrix[1])));
2905
+ const segments = subpath.curves.length;
2906
+ const closed = subpath.closed;
2907
+ const straightPoints = [subpath.start, ...subpath.curves.map((curve) => [curve[4], curve[5]])];
2908
+ const build = (color, opacity, filled, suffix) => {
2909
+ if (subpath.straight && straightPoints.length >= 2) {
2910
+ const vertices = closed ? straightPoints.slice(0, -1) : straightPoints;
2911
+ if (filled || closed) {
2912
+ if (vertices.length >= 3) return [{
2913
+ op: "stroke",
2914
+ ...common,
2915
+ id: nextId(suffix),
2916
+ shape: "polygon",
2917
+ color,
2918
+ opacity,
2919
+ fill: filled,
2920
+ width: strokeWidth,
2921
+ points: vertices.map(([px, py]) => norm(matrix, px, py))
2922
+ }];
2923
+ }
2924
+ if (vertices.length === 2 && !filled) return [{
2925
+ op: "stroke",
2926
+ ...common,
2927
+ id: nextId(suffix),
2928
+ shape: "line",
2929
+ color,
2930
+ opacity,
2931
+ fill: false,
2932
+ width: strokeWidth,
2933
+ points: vertices.map(([px, py]) => norm(matrix, px, py))
2934
+ }];
2935
+ if (!filled) {
2936
+ const pieces = [];
2937
+ for (let from = 0; from < vertices.length - 1; from += 1900) pieces.push({
2938
+ op: "stroke",
2939
+ ...common,
2940
+ id: nextId(suffix),
2941
+ shape: "pen",
2942
+ color,
2943
+ opacity,
2944
+ fill: false,
2945
+ width: strokeWidth,
2946
+ points: vertices.slice(from, from + 1901).map(([px, py]) => norm(matrix, px, py))
2947
+ });
2948
+ return pieces;
2949
+ }
2950
+ return [];
2951
+ }
2952
+ if (filled && segments > MAX_BEZIER_SEGMENTS) {
2953
+ warnings.add(`A filled path with ${segments} curve segments was flattened to a polygon (more than ${MAX_BEZIER_SEGMENTS} segments cannot stay a Bezier).`);
2954
+ const flat = [subpath.start];
2955
+ let [cx, cy] = subpath.start;
2956
+ for (const [a, b, c1, d, e, f] of subpath.curves) {
2957
+ for (let step = 1; step <= FLATTEN_STEPS; step++) {
2958
+ const t = step / FLATTEN_STEPS, u = 1 - t;
2959
+ flat.push([u * u * u * cx + 3 * u * u * t * a + 3 * u * t * t * c1 + t * t * t * e, u * u * u * cy + 3 * u * u * t * b + 3 * u * t * t * d + t * t * t * f]);
2960
+ }
2961
+ cx = e;
2962
+ cy = f;
2963
+ }
2964
+ if (flat.length > 2e3) throw Error("A filled path is too complex to import; simplify it or split it into several paths.");
2965
+ return [{
2966
+ op: "stroke",
2967
+ ...common,
2968
+ id: nextId(suffix),
2969
+ shape: "polygon",
2970
+ color,
2971
+ opacity,
2972
+ fill: true,
2973
+ width: strokeWidth,
2974
+ points: flat.map(([px, py]) => norm(matrix, px, py))
2975
+ }];
2976
+ }
2977
+ const pieces = [];
2978
+ for (let from = 0; from < segments; from += MAX_BEZIER_SEGMENTS) {
2979
+ const chunk = subpath.curves.slice(from, from + MAX_BEZIER_SEGMENTS);
2980
+ const chunkPoints = [from === 0 ? subpath.start : [subpath.curves[from - 1][4], subpath.curves[from - 1][5]], ...chunk.flatMap((curve) => [
2981
+ [curve[0], curve[1]],
2982
+ [curve[2], curve[3]],
2983
+ [curve[4], curve[5]]
2984
+ ])];
2985
+ pieces.push({
2986
+ op: "stroke",
2987
+ ...common,
2988
+ id: nextId(suffix),
2989
+ shape: "bezier",
2990
+ color,
2991
+ opacity,
2992
+ fill: filled,
2993
+ width: strokeWidth,
2994
+ points: chunkPoints.map(([px, py]) => norm(matrix, px, py))
2995
+ });
2996
+ }
2997
+ return pieces;
2998
+ };
2999
+ if (fill !== "none" && style.fillOpacity * style.opacity > 0) commands.push(...build(fill, style.fillOpacity * style.opacity, true, ""));
3000
+ if (stroke !== "none" && style.strokeOpacity * style.opacity > 0 && style.strokeWidth > 0) commands.push(...build(stroke, style.strokeOpacity * style.opacity, false, "-line"));
3001
+ };
3002
+ const walk = (node, matrix, parentStyle, depth) => {
3003
+ if (depth > 24) throw Error("SVG is nested too deeply");
3004
+ if (UNSUPPORTED.has(node.name)) throw Error(`Unsupported SVG element <${node.name}>. Draw with path, rect, circle, ellipse, line, polyline, polygon, g and use; add text with a native text command.`);
3005
+ if (IGNORED.has(node.name)) return;
3006
+ for (const name of [
3007
+ "clip-path",
3008
+ "mask",
3009
+ "filter"
3010
+ ]) if (node.attrs[name] && node.attrs[name] !== "none") throw Error(`Unsupported SVG attribute ${name}. Bake it into the shapes instead.`);
3011
+ const style = styleOf(node, parentStyle);
3012
+ if (style.display === "none") return;
3013
+ const local = multiply(matrix, parseTransform(node.attrs.transform));
3014
+ const n = (name) => Number.parseFloat(node.attrs[name] ?? 0);
3015
+ const finish = (subpaths) => subpaths.forEach((subpath) => emit(subpath, local, style, node.attrs.id));
3016
+ switch (node.name) {
3017
+ case "svg":
3018
+ case "g":
3019
+ case "a":
3020
+ for (const child of node.children) walk(child, local, style, depth + 1);
3021
+ return;
3022
+ case "use": {
3023
+ const href = node.attrs.href ?? node.attrs["xlink:href"];
3024
+ const target = href?.startsWith("#") ? byId.get(href.slice(1)) : void 0;
3025
+ if (!target) throw Error(`<use> must reference an element in the same SVG (${href ?? "missing href"})`);
3026
+ walk(target, multiply(local, [
3027
+ 1,
3028
+ 0,
3029
+ 0,
3030
+ 1,
3031
+ n("x"),
3032
+ n("y")
3033
+ ]), { ...style }, depth + 1);
3034
+ return;
3035
+ }
3036
+ case "path":
3037
+ finish(parsePathData(node.attrs.d));
3038
+ return;
3039
+ case "rect": {
3040
+ const w = n("width"), h = n("height");
3041
+ if (!(w > 0 && h > 0)) return;
3042
+ const rx = node.attrs.rx !== void 0 ? n("rx") : node.attrs.ry !== void 0 ? n("ry") : 0;
3043
+ const ry = node.attrs.ry !== void 0 ? n("ry") : rx;
3044
+ finish([rx > 0 || ry > 0 ? roundedRectPath(n("x"), n("y"), w, h, rx, ry) : polylinePath([
3045
+ [n("x"), n("y")],
3046
+ [n("x") + w, n("y")],
3047
+ [n("x") + w, n("y") + h],
3048
+ [n("x"), n("y") + h]
3049
+ ], true)]);
3050
+ return;
3051
+ }
3052
+ case "circle":
3053
+ if (n("r") > 0) finish([ellipsePath(n("cx"), n("cy"), n("r"), n("r"))]);
3054
+ return;
3055
+ case "ellipse":
3056
+ if (n("rx") > 0 && n("ry") > 0) finish([ellipsePath(n("cx"), n("cy"), n("rx"), n("ry"))]);
3057
+ return;
3058
+ case "line":
3059
+ finish([polylinePath([[n("x1"), n("y1")], [n("x2"), n("y2")]], false)]);
3060
+ return;
3061
+ case "polyline":
3062
+ case "polygon": {
3063
+ const values = numbers(node.attrs.points);
3064
+ if (values.length < 4 || values.length % 2) throw Error(`<${node.name}> needs an even number of coordinates, at least two points`);
3065
+ const pts = [];
3066
+ for (let at = 0; at < values.length; at += 2) pts.push([values[at], values[at + 1]]);
3067
+ finish([polylinePath(pts, node.name === "polygon")]);
3068
+ return;
3069
+ }
3070
+ default: throw Error(`Unsupported SVG element <${node.name}>`);
3071
+ }
3072
+ };
3073
+ walk(root, IDENTITY, {
3074
+ fill: "#000000",
3075
+ stroke: "none",
3076
+ strokeWidth: 1,
3077
+ fillOpacity: 1,
3078
+ strokeOpacity: 1,
3079
+ opacity: 1
3080
+ }, 0);
3081
+ if (!commands.length) throw Error("The SVG contained no drawable shapes");
3082
+ return {
3083
+ commands,
3084
+ warnings: [...warnings],
3085
+ clamped
3086
+ };
3087
+ }
3088
+ function expandSvgCommands(commands, doc, report) {
3089
+ if (!commands.some((command) => command?.op === "svg")) return commands;
3090
+ const width = doc.width ?? 1024, height = doc.height ?? 1024;
3091
+ const ids = new Set(doc.layers.flatMap((item) => item.strokes.map((stroke) => stroke.id).filter(Boolean)));
3092
+ const out = [];
3093
+ let clamped = 0;
3094
+ for (const command of commands) {
3095
+ if (command?.op !== "svg") {
3096
+ out.push(command);
3097
+ if (command?.id) ids.add(command.id);
3098
+ continue;
3099
+ }
3100
+ const result = svgToSketchCommands(command.svg, {
3101
+ width,
3102
+ height,
3103
+ layer: command.layer,
3104
+ existingIds: ids
3105
+ });
3106
+ result.commands.forEach((item) => ids.add(item.id));
3107
+ out.push(...result.commands);
3108
+ clamped += result.clamped;
3109
+ if (report) report.warnings = [.../* @__PURE__ */ new Set([...report.warnings ?? [], ...result.warnings])];
3110
+ }
3111
+ if (report && clamped) report.clampedPoints = (report.clampedPoints ?? 0) + clamped;
3112
+ return out;
3113
+ }
2324
3114
  const SKETCH_COMMAND_HELP = {
2325
3115
  coordinates: "Assign short meaningful stroke id values for later edits. Text uses two opposite box corners and text content; width is font size in pixels, automatic fitting within the box. Arrow uses two endpoints. Normalized x/y in [0,1]; width is canvas pixels. Read documentId and revision before editing.",
2326
3116
  shapes: "line: exactly two endpoints; rectangle/circle (ellipse alias accepted): exactly two opposite bounding-box corners (circle draws an ellipse within that box); polygon: three or more vertices, closed automatically; pen: ordered path points. bezier: start point, then groups of control1/control2/end; use 4 points for one cubic curve, max 64 segments. Prefer bezier for smooth designed curves instead of many pen samples. fill:true closes and fills the curve. fill:true fills rectangle/circle/polygon. Layers and strokes paint in list order, later ones on top. All commands needed for drawing are described here; no source-code search is required.",
@@ -2330,19 +3120,22 @@ window.__ModuleLoader__.load({
2330
3120
  layer: "Add: {op:\"layer\",action:\"add\",value:\"name\"}; optional id is the NEW unique integer ID, otherwise allocated automatically. after is the existing insertion anchor, defaults to active layer. Other actions: {op:\"layer\",action:\"select|rename|visible|duplicate|up|down|delete|clear\",id:1,value:\"name\"}; id targets an existing layer.",
2331
3121
  curve: "Prefer {op:\"stroke\",shape:\"bezier\",start:{x:0,y:0},segments:[{control1:{x:0.2,y:0},control2:{x:0.8,y:1},end:{x:1,y:1}}],color:\"#123456\"}. Each segment has exactly two controls and an endpoint; no point counting required. Legacy points arrays still accepted. Do not provide both forms.",
2332
3122
  object: "{op:\"object\",layer:1,id:\"title\",action:\"update|duplicate|delete\",patch:{color:\"#0088ff\",text:\"Title\"},transform:{dx:0.05,dy:0,scaleX:1,scaleY:1}}. All patch and transform fields optional. Inspect returns object IDs and bounds. Prefer targeted edits over redrawing layers.",
2333
- resize: "{op:\"resize\",ratio:\"1:1|4:3|3:4|16:9|9:16\"}"
3123
+ resize: "{op:\"resize\",ratio:\"1:1|4:3|3:4|16:9|9:16\"}",
3124
+ svg: "{op:\"svg\",svg:\"<svg viewBox=\\\"0 0 1024 768\\\">...</svg>\",layer:1}. Fastest way to draw: send a whole scene as SVG (path with M L H V C S Q T A Z, rect, circle, ellipse, line, polyline, polygon, g, use, transform, fill/stroke/opacity, style=\"...\"); it becomes native editable strokes. The viewBox must match the canvas size (use the width and height from inspect; 4:3 is 1024x768). Gradients are flattened to their average color, so build glows and skies from stacked bands; text, image, filter, clipPath, mask, pattern and CSS classes are refused. Coordinates outside the canvas are clamped. One svg command may hold up to 200000 characters."
2334
3125
  },
2335
3126
  limits: {
2336
3127
  strokes: MAX_SKETCH_STROKES,
2337
3128
  pointsPerStroke: MAX_STROKE_POINTS,
2338
3129
  pointsTotal: 2e5,
2339
- commandsPerBatch: 256
3130
+ commandsPerBatch: 256,
3131
+ svgCharacters: MAX_SVG_CHARACTERS
2340
3132
  }
2341
3133
  };
2342
3134
  const finite = (value, min, max) => typeof value === "number" && Number.isFinite(value) && value >= min && value <= max;
2343
- function applySketchCommands(source, commands) {
3135
+ function applySketchCommands(source, commands, report) {
2344
3136
  if (!Array.isArray(commands) || !commands.length || commands.length > 256) throw Error("Expected 1–256 commands");
2345
3137
  let doc = identifyObjects(source);
3138
+ commands = expandSvgCommands(commands, doc, report);
2346
3139
  for (let command of commands) {
2347
3140
  if (!command || typeof command !== "object") throw Error("Invalid command");
2348
3141
  if (command.op === "stroke") command = expandSketchPreset(command);
@@ -2544,11 +3337,12 @@ window.__ModuleLoader__.load({
2544
3337
  }
2545
3338
  if (request.revision !== current.revision || adapter.busy()) throw Error("Sketch changed or is being edited; inspect again");
2546
3339
  let changedObjects;
3340
+ const report = {};
2547
3341
  if (request.action === "apply") {
2548
3342
  const before = adapter.document();
2549
3343
  let next;
2550
3344
  try {
2551
- next = applySketchCommands(before, request.commands);
3345
+ next = applySketchCommands(before, request.commands, report);
2552
3346
  } catch (cause) {
2553
3347
  const error = new Error(`${cause.message} Correct the batch and retry with the same runId and revision; nothing was applied.`, { cause });
2554
3348
  error.code = "SKETCH_INVALID_BATCH";
@@ -2574,7 +3368,9 @@ window.__ModuleLoader__.load({
2574
3368
  ...changedObjects ? {
2575
3369
  changedObjects: changedObjects.slice(0, 100),
2576
3370
  changedObjectCount: changedObjects.length
2577
- } : {}
3371
+ } : {},
3372
+ ...report?.warnings?.length ? { warnings: report.warnings } : {},
3373
+ ...report?.clampedPoints ? { clampedPoints: report.clampedPoints } : {}
2578
3374
  };
2579
3375
  completed.set(key, {
2580
3376
  fingerprint,
@@ -4977,6 +5773,8 @@ window.__ModuleLoader__.load({
4977
5773
  quotaAlertsHint: "低于所选剩余阈值时提醒;自定义可分别设置短周期与长周期。仅使用新鲜数据,不弹窗打断。",
4978
5774
  quotaWarning: "{window}额度剩余 {value}%,请留意用量与重置时间。",
4979
5775
  speedFastAstraHint: "Astra 约 2 倍速度,消耗更多 Credits",
5776
+ speedUltrafast: "极速 Beta",
5777
+ speedUltrafastHint: "Ultrafast 档,仅账号目录提供时显示(目前为 Pro 500);速度最快,额度和 Credits 消耗更快",
4980
5778
  imageEditLocation: "位置",
4981
5779
  imageEditReferenceGuide: "本次编辑的干净源图为「{sourceName}」,编号定位参考图为「{referenceName}」。坐标以图片左上角为原点,x 向右、y 向下,百分比相对于整张图片。请查看这两张图片,将它们同时作为编辑工具的参考图,并在工具提示词中完整保留下方编号、位置和修改要求。只修改源图中对应位置的内容;定位参考图上的编号、圆点和引线仅用于定位,不得绘入最终结果。若无法读取两张图片或确定位置,请说明问题,不要猜测或忽略标注。",
4982
5780
  nav: "Codex 订阅",
@@ -5010,7 +5808,8 @@ window.__ModuleLoader__.load({
5010
5808
  diagnostics: "支持诊断",
5011
5809
  diagnosticsLoad: "生成诊断",
5012
5810
  diagnosticsLoading: "生成中…",
5013
- diagnosticsCopy: "复制诊断",
5811
+ diagnosticsCopy: "复制诊断(精简)",
5812
+ diagnosticsCopyFull: "复制完整诊断",
5014
5813
  diagnosticsCopied: "已复制",
5015
5814
  diagnosticsFailed: "服务端诊断不可用,已生成可复制的本地脱敏诊断。请检查 DSH 服务连接与插件版本。",
5016
5815
  feedbackOpen: "反馈问题",
@@ -5532,6 +6331,8 @@ window.__ModuleLoader__.load({
5532
6331
  quotaAlertsHint: "Warn at the selected remaining threshold. Custom sets short and long windows separately. Fresh data only; no interrupting popups.",
5533
6332
  quotaWarning: "{window}: {value}% remaining. Check usage and reset time.",
5534
6333
  speedFastAstraHint: "About 2x speed on Astra; higher Credits use",
6334
+ speedUltrafast: "Ultrafast Beta",
6335
+ speedUltrafastHint: "Ultrafast tier, shown only when your account catalog offers it (Pro 500 today); fastest, uses allowance and Credits faster",
5535
6336
  imageEditLocation: "Location",
5536
6337
  imageEditReferenceGuide: "The clean source for this edit is \"{sourceName}\"; \"{referenceName}\" is the numbered location reference. Coordinates start at the top-left, x increases rightward and y downward; percentages refer to the whole image. Inspect both images and pass both as references to the image-editing tool. Preserve every number, position and requested change below in the tool prompt. Edit the corresponding content in the clean source; numbers, dots and leader lines on the location reference are guidance only and must not appear in the final result. If either image cannot be read or a location is unclear, explain the problem instead of guessing or ignoring annotations.",
5537
6338
  nav: "Codex",
@@ -5565,7 +6366,8 @@ window.__ModuleLoader__.load({
5565
6366
  diagnostics: "Support diagnostics",
5566
6367
  diagnosticsLoad: "Create report",
5567
6368
  diagnosticsLoading: "Creating…",
5568
- diagnosticsCopy: "Copy report",
6369
+ diagnosticsCopy: "Copy report (short)",
6370
+ diagnosticsCopyFull: "Copy full report",
5569
6371
  diagnosticsCopied: "Copied",
5570
6372
  diagnosticsFailed: "Server diagnostics unavailable. A local, redacted report is available to copy. Check the DSH service and plugin version.",
5571
6373
  feedbackOpen: "Report a problem",
@@ -5841,6 +6643,10 @@ window.__ModuleLoader__.load({
5841
6643
  .codexSubscriptionRecover .codexSubscriptionError{flex:1}
5842
6644
  .codexSubscriptionRecover button{flex:0 0 auto}
5843
6645
  .codexSubscriptionDiagnostics{color:var(--dsw-alias-label-secondary)}
6646
+ .codexSubscriptionDiagnostics ul{margin:0;padding-left:18px;font-size:13px;line-height:20px}
6647
+ .codexSubscriptionDiagnostics li+li{margin-top:6px}
6648
+ .codexSubscriptionDiagnostics li strong{font-weight:600;color:var(--dsw-alias-label-primary)}
6649
+ .codexSubscriptionDiagnostics [role=status]>p{margin:0;font-size:13px}
5844
6650
  .codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}
5845
6651
  .codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}
5846
6652
  .codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}
@@ -7047,7 +7853,6 @@ window.__ModuleLoader__.load({
7047
7853
  const DEFAULT_SEARCH_PROVIDER = SEARCH_PROVIDER_AUTO;
7048
7854
  const SPEED_MODE_FIELD = "speedMode";
7049
7855
  const SPEED_MODE_STANDARD = "standard";
7050
- const SPEED_MODE_FAST = "fast";
7051
7856
  const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
7052
7857
  const OUTPUT_VERBOSITY_FIELD = "outputVerbosity";
7053
7858
  const OUTPUT_VERBOSITY_DEFAULT = "default";
@@ -7115,7 +7920,11 @@ window.__ModuleLoader__.load({
7115
7920
  ].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
7116
7921
  const normalizeInputImageDetail = (value) => INPUT_IMAGE_DETAILS.includes(value) ? value : DEFAULT_INPUT_IMAGE_DETAIL;
7117
7922
  const normalizeStreamIdleTimeoutMinutes = (value) => STREAM_IDLE_TIMEOUT_MINUTES.includes(value) ? value : 10;
7118
- const normalizeSpeedMode = (value) => ["standard", "fast"].includes(value) ? value : DEFAULT_SPEED_MODE;
7923
+ const normalizeSpeedMode = (value) => [
7924
+ "standard",
7925
+ "fast",
7926
+ "ultrafast"
7927
+ ].includes(value) ? value : DEFAULT_SPEED_MODE;
7119
7928
  const normalizeContextMode = (value) => [
7120
7929
  "standard",
7121
7930
  "extended",
@@ -7155,6 +7964,7 @@ window.__ModuleLoader__.load({
7155
7964
  let availableModels = [];
7156
7965
  let verbosityModels = [];
7157
7966
  let fastModels;
7967
+ let ultrafastModels = [];
7158
7968
  let catalogStatus;
7159
7969
  let modelsLoading = false;
7160
7970
  let modelError = false;
@@ -7199,6 +8009,7 @@ window.__ModuleLoader__.load({
7199
8009
  disabledModels: normalizeDisabledModels(value?.[DISABLED_MODELS_FIELD]),
7200
8010
  verbosityModels,
7201
8011
  fastModels,
8012
+ ultrafastModels,
7202
8013
  catalogStatus,
7203
8014
  modelsLoading,
7204
8015
  modelError,
@@ -7226,6 +8037,7 @@ window.__ModuleLoader__.load({
7226
8037
  availableModels = Array.isArray(value?.availableModels) ? value.availableModels : [];
7227
8038
  verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
7228
8039
  fastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
8040
+ ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
7229
8041
  catalogStatus = value?.catalogStatus;
7230
8042
  }
7231
8043
  fallbackStatus = "ready";
@@ -7270,6 +8082,8 @@ window.__ModuleLoader__.load({
7270
8082
  availableModels = Array.isArray(value?.availableModels) ? value.availableModels : [];
7271
8083
  verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
7272
8084
  fastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
8085
+ ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
8086
+ ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
7273
8087
  catalogStatus = value?.catalogStatus;
7274
8088
  }
7275
8089
  } else acceptFallback(value);
@@ -7293,13 +8107,15 @@ window.__ModuleLoader__.load({
7293
8107
  const nextAvailableModels = Array.isArray(value?.availableModels) ? value.availableModels : [];
7294
8108
  const nextVerbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
7295
8109
  const nextFastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
8110
+ const nextUltrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
7296
8111
  catalogStatus = value?.catalogStatus;
7297
- const changed = !sameModels(contextModels, nextContextModels) || !sameModels(availableModels, nextAvailableModels) || !sameModels(verbosityModels, nextVerbosityModels) || JSON.stringify(fastModels) !== JSON.stringify(nextFastModels);
8112
+ const changed = !sameModels(contextModels, nextContextModels) || !sameModels(availableModels, nextAvailableModels) || !sameModels(verbosityModels, nextVerbosityModels) || JSON.stringify(fastModels) !== JSON.stringify(nextFastModels) || JSON.stringify(ultrafastModels) !== JSON.stringify(nextUltrafastModels);
7298
8113
  if (changed) {
7299
8114
  contextModels = nextContextModels;
7300
8115
  availableModels = nextAvailableModels;
7301
8116
  verbosityModels = nextVerbosityModels;
7302
8117
  fastModels = nextFastModels;
8118
+ ultrafastModels = nextUltrafastModels;
7303
8119
  publish();
7304
8120
  }
7305
8121
  return changed;
@@ -7660,7 +8476,7 @@ window.__ModuleLoader__.load({
7660
8476
  }
7661
8477
  //#endregion
7662
8478
  //#region src/version.js
7663
- const PACKAGE_VERSION = "2.2.11";
8479
+ const PACKAGE_VERSION = "2.4.0";
7664
8480
  //#endregion
7665
8481
  //#region src/client-recovery.js
7666
8482
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -7950,7 +8766,10 @@ window.__ModuleLoader__.load({
7950
8766
  const modelLabel = currentChoice?.model.name ?? t("selectModel");
7951
8767
  const speedSupported = state.current?.provider === "openai-codex" && (preferenceSnapshot.fastModels?.includes(state.current?.model) ?? supportsCodexFastMode(state.current?.model));
7952
8768
  const speedWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
7953
- const fast = speedSupported && preferenceSnapshot.speedMode === "fast";
8769
+ const ultrafastSupported = state.current?.provider === "openai-codex" && (preferenceSnapshot.ultrafastModels ?? []).includes(state.current?.model);
8770
+ const ultrafast = ultrafastSupported && preferenceSnapshot.speedMode === "ultrafast";
8771
+ const fast = ultrafast || speedSupported && preferenceSnapshot.speedMode === "fast";
8772
+ const speedKey = ultrafast ? "speedUltrafast" : fast ? "speedFast" : "speedStandard";
7954
8773
  const verbositySupported = state.current?.provider === "openai-codex" && preferenceSnapshot.verbosityModels.includes(state.current?.model);
7955
8774
  const verbosityWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
7956
8775
  const verbosityItems = [
@@ -8158,21 +8977,32 @@ window.__ModuleLoader__.load({
8158
8977
  className: "codexModelSelectSubmenu",
8159
8978
  role: "menu",
8160
8979
  "aria-label": t("speedTitle"),
8161
- children: [option({
8162
- key: SPEED_MODE_STANDARD,
8163
- label: t("speedStandard"),
8164
- description: t("speedStandardHint"),
8165
- selected: !fast,
8166
- disabled: !speedWritable,
8167
- onClick: () => chooseSpeed(SPEED_MODE_STANDARD)
8168
- }), option({
8169
- key: SPEED_MODE_FAST,
8170
- label: t("speedFast"),
8171
- description: t(state.current?.model === "gpt-6-astra" ? "speedFastAstraHint" : "speedFastHint"),
8172
- selected: fast,
8173
- disabled: !speedWritable,
8174
- onClick: () => chooseSpeed(SPEED_MODE_FAST)
8175
- })]
8980
+ children: [
8981
+ option({
8982
+ key: SPEED_MODE_STANDARD,
8983
+ label: t("speedStandard"),
8984
+ description: t("speedStandardHint"),
8985
+ selected: !fast,
8986
+ disabled: !speedWritable,
8987
+ onClick: () => chooseSpeed(SPEED_MODE_STANDARD)
8988
+ }),
8989
+ speedSupported && option({
8990
+ key: "fast",
8991
+ label: t("speedFast"),
8992
+ description: t(state.current?.model === "gpt-6-astra" ? "speedFastAstraHint" : "speedFastHint"),
8993
+ selected: fast && !ultrafast,
8994
+ disabled: !speedWritable,
8995
+ onClick: () => chooseSpeed("fast")
8996
+ }),
8997
+ ultrafastSupported && option({
8998
+ key: "ultrafast",
8999
+ label: t("speedUltrafast"),
9000
+ description: t("speedUltrafastHint"),
9001
+ selected: ultrafast,
9002
+ disabled: !speedWritable,
9003
+ onClick: () => chooseSpeed("ultrafast")
9004
+ })
9005
+ ]
8176
9006
  });
8177
9007
  else if (pane === "verbosity") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8178
9008
  className: "codexModelSelectSubmenu",
@@ -8231,7 +9061,7 @@ window.__ModuleLoader__.load({
8231
9061
  children: [
8232
9062
  cell("model", t("modelLabel"), modelLabel),
8233
9063
  reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
8234
- speedSupported && cell("speed", t("speedTitle"), t(fast ? "speedFast" : "speedStandard")),
9064
+ (speedSupported || ultrafastSupported) && cell("speed", t("speedTitle"), t(speedKey)),
8235
9065
  verbositySupported && cell("verbosity", t("verbosityTitle"), verbosityLabel),
8236
9066
  submenu
8237
9067
  ]
@@ -9919,6 +10749,40 @@ window.__ModuleLoader__.load({
9919
10749
  };
9920
10750
  }
9921
10751
  //#endregion
10752
+ //#region src/diagnostic-compact.js
10753
+ function compactDiagnostic(report) {
10754
+ const summary = report.summary ?? { findings: [] };
10755
+ return {
10756
+ format: "compact-1",
10757
+ plugin: report.version,
10758
+ dsh: report.runtime?.dsh,
10759
+ ...report.client?.version && report.client.version !== report.version ? { pluginClient: report.client.version } : {},
10760
+ platform: report.runtime ? `${report.runtime.platform}-${report.runtime.arch}` : void 0,
10761
+ generatedAt: report.generatedAt,
10762
+ account: report.account?.status,
10763
+ catalog: report.catalog ? {
10764
+ source: report.catalog.source,
10765
+ refresh: report.catalog.refresh
10766
+ } : void 0,
10767
+ configuration: report.configuration,
10768
+ findings: summary.findings.map((item) => ({
10769
+ code: item.code,
10770
+ severity: item.severity,
10771
+ ...item.code === "recent-failure" ? { failures: item.evidence.map((event) => ({
10772
+ action: event.action,
10773
+ source: event.source,
10774
+ at: new Date(event.observedAt).toISOString()
10775
+ })) } : {}
10776
+ })),
10777
+ capabilities: (report.inspection?.capabilities ?? []).filter((item) => item.readiness !== "not-applicable").map((item) => ({
10778
+ id: item.id,
10779
+ reason: item.reason,
10780
+ ...item.latest ? { latest: `${item.latest.action} ${item.latest.status}` } : { latest: "not-verified" }
10781
+ })),
10782
+ ...report.client?.status === "unknown" ? { hostCollected: false } : {}
10783
+ };
10784
+ }
10785
+ //#endregion
9922
10786
  //#region src/client-diagnostics.jsx
9923
10787
  function DiagnosticsCard({ rpc, t, diagnostics }) {
9924
10788
  const [report, setReport] = (0, react.useState)();
@@ -9943,10 +10807,10 @@ window.__ModuleLoader__.load({
9943
10807
  });
9944
10808
  }).finally(() => setBusy(false));
9945
10809
  };
9946
- const copy = () => {
10810
+ const copy = (full = false) => {
9947
10811
  if (report === void 0) return;
9948
10812
  setCopyError(false);
9949
- Promise.resolve().then(() => navigator.clipboard.writeText(JSON.stringify(report, null, 2))).then(() => setCopied(true)).catch(() => setCopyError(true));
10813
+ Promise.resolve().then(() => navigator.clipboard.writeText(JSON.stringify(full ? report : compactDiagnostic(report), null, 2))).then(() => setCopied(true)).catch(() => setCopyError(true));
9950
10814
  };
9951
10815
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9952
10816
  className: "codexSubscriptionCard codexSubscriptionDiagnostics",
@@ -9972,7 +10836,7 @@ window.__ModuleLoader__.load({
9972
10836
  report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
9973
10837
  type: "button",
9974
10838
  variant: "outline",
9975
- onClick: copy,
10839
+ onClick: () => copy(),
9976
10840
  children: copied ? t("diagnosticsCopied") : t("diagnosticsCopy")
9977
10841
  }),
9978
10842
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
@@ -10038,7 +10902,16 @@ window.__ModuleLoader__.load({
10038
10902
  className: "codexSubscriptionHelp",
10039
10903
  children: report.client?.topology?.length ? t("diagnosticsHostCollected") : t("diagnosticsHostUnknown")
10040
10904
  }),
10041
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("diagnosticsDetails") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) })] })
10905
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [
10906
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("diagnosticsDetails") }),
10907
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
10908
+ type: "button",
10909
+ variant: "outline",
10910
+ onClick: () => copy(true),
10911
+ children: t("diagnosticsCopyFull")
10912
+ }),
10913
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) })
10914
+ ] })
10042
10915
  ] }),
10043
10916
  error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10044
10917
  className: "codexSubscriptionError",