@spotpatch/runtime 1.11.0 → 1.13.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.
Files changed (45) hide show
  1. package/dist/{chunk-QY5T4DPA.js → chunk-2WA6XVA4.js} +13 -6
  2. package/dist/chunk-2WA6XVA4.js.map +1 -0
  3. package/dist/{chunk-BXRMVHNT.js → chunk-ASRUAKA5.js} +1 -1
  4. package/dist/chunk-ASRUAKA5.js.map +1 -0
  5. package/dist/{chunk-7ES63LA7.js → chunk-P6X75LO5.js} +11 -1
  6. package/dist/chunk-P6X75LO5.js.map +1 -0
  7. package/dist/chunk-P7W3F4UA.js +115 -0
  8. package/dist/chunk-P7W3F4UA.js.map +1 -0
  9. package/dist/chunk-RZDOL5BT.js +1 -0
  10. package/dist/chunk-RZDOL5BT.js.map +1 -0
  11. package/dist/data-flow-panel.cjs +171 -0
  12. package/dist/data-flow-panel.cjs.map +1 -1
  13. package/dist/data-flow-panel.d.cts +4 -2
  14. package/dist/data-flow-panel.d.ts +4 -2
  15. package/dist/data-flow-panel.js +27 -1
  16. package/dist/data-flow-panel.js.map +1 -1
  17. package/dist/{data-flow-runtime-B3itbieT.d.cts → data-flow-runtime-DMmV0d3E.d.cts} +7 -3
  18. package/dist/{data-flow-runtime-B3itbieT.d.ts → data-flow-runtime-DMmV0d3E.d.ts} +7 -3
  19. package/dist/data-flow.cjs +12 -5
  20. package/dist/data-flow.cjs.map +1 -1
  21. package/dist/data-flow.d.cts +1 -1
  22. package/dist/data-flow.d.ts +1 -1
  23. package/dist/data-flow.js +2 -1
  24. package/dist/external-handoff-panel.cjs +29 -9
  25. package/dist/external-handoff-panel.cjs.map +1 -1
  26. package/dist/external-handoff-panel.d.cts +3 -3
  27. package/dist/external-handoff-panel.d.ts +3 -3
  28. package/dist/external-handoff-panel.js +22 -11
  29. package/dist/external-handoff-panel.js.map +1 -1
  30. package/dist/index.cjs +1204 -279
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +1164 -355
  35. package/dist/index.js.map +1 -1
  36. package/dist/motion.cjs +1251 -0
  37. package/dist/motion.cjs.map +1 -0
  38. package/dist/motion.d.cts +79 -0
  39. package/dist/motion.d.ts +79 -0
  40. package/dist/motion.js +1092 -0
  41. package/dist/motion.js.map +1 -0
  42. package/package.json +19 -4
  43. package/dist/chunk-7ES63LA7.js.map +0 -1
  44. package/dist/chunk-BXRMVHNT.js.map +0 -1
  45. package/dist/chunk-QY5T4DPA.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,22 +1,27 @@
1
+ import {
2
+ getDataFlowExtension
3
+ } from "./chunk-NII5OBAN.js";
1
4
  import {
2
5
  createDataFlowRuntime,
3
6
  getDataFlowRuntime,
4
7
  installDataFlowPrelude,
5
8
  mergeComponentDataFlowReport,
6
9
  mergePageDataFlowReport
7
- } from "./chunk-QY5T4DPA.js";
8
- import {
9
- getDataFlowExtension
10
- } from "./chunk-NII5OBAN.js";
10
+ } from "./chunk-2WA6XVA4.js";
11
11
  import {
12
12
  getExternalHandoffExtension
13
- } from "./chunk-BXRMVHNT.js";
13
+ } from "./chunk-ASRUAKA5.js";
14
14
  import {
15
+ createBrandMark,
16
+ getFloatingSurfaceMotionExtension
17
+ } from "./chunk-P7W3F4UA.js";
18
+ import {
19
+ FLOATING_SURFACE_LAYOUT,
15
20
  UI_MARKER_ATTRIBUTE,
16
21
  UI_Z_INDEX,
17
22
  createButton,
18
23
  createMarkedElement
19
- } from "./chunk-7ES63LA7.js";
24
+ } from "./chunk-P6X75LO5.js";
20
25
 
21
26
  // src/controller/runtime-controller.ts
22
27
  import { createReact18Adapter } from "@spotpatch/react-adapter";
@@ -1978,6 +1983,7 @@ function createAgentPanel(document, ai, localizer) {
1978
1983
  root.hidden = !ai.enabled;
1979
1984
  const header = createMarkedElement(document, "div");
1980
1985
  header.className = "spotpatch-agent-head";
1986
+ header.setAttribute("data-spotpatch-agent-identity", "");
1981
1987
  const title = createMarkedElement(document, "span");
1982
1988
  title.className = "spotpatch-agent-title";
1983
1989
  const badge = createMarkedElement(document, "span");
@@ -2419,151 +2425,6 @@ function createAgentPanel(document, ai, localizer) {
2419
2425
  });
2420
2426
  }
2421
2427
 
2422
- // src/ui/brand-mark-content.ts
2423
- var BRAND_MARK_CONTENT = `
2424
- <defs>
2425
- <linearGradient id="locator-gradient" x1="76" y1="92" x2="436" y2="374" gradientUnits="userSpaceOnUse">
2426
- <stop offset="0" stop-color="#B61CFF" />
2427
- <stop offset="0.38" stop-color="#6D35FF" />
2428
- <stop offset="0.72" stop-color="#168EFF" />
2429
- <stop offset="1" stop-color="#00D9E9" />
2430
- </linearGradient>
2431
- <linearGradient id="left-code-gradient" x1="165" y1="166" x2="236" y2="258" gradientUnits="userSpaceOnUse">
2432
- <stop stop-color="#A51EFF" />
2433
- <stop offset="1" stop-color="#653BFF" />
2434
- </linearGradient>
2435
- <linearGradient id="right-code-gradient" x1="276" y1="166" x2="347" y2="258" gradientUnits="userSpaceOnUse">
2436
- <stop stop-color="#158DFF" />
2437
- <stop offset="1" stop-color="#00D8E9" />
2438
- </linearGradient>
2439
- <linearGradient id="bolt-gradient" x1="270" y1="111" x2="252" y2="365" gradientUnits="userSpaceOnUse">
2440
- <stop stop-color="#6840FF" />
2441
- <stop offset="0.48" stop-color="#257BFF" />
2442
- <stop offset="1" stop-color="#00CBEF" />
2443
- </linearGradient>
2444
- </defs>
2445
- <path
2446
- fill="url(#locator-gradient)"
2447
- fill-rule="evenodd"
2448
- clip-rule="evenodd"
2449
- d="M256 52C345.47 52 418 124.53 418 214C418 267.55 391.98 316.24 354.04 348.02L256 468L157.96 348.02C120.02 316.24 94 267.55 94 214C94 124.53 166.53 52 256 52ZM256 88C186.41 88 130 144.41 130 214C130 258.2 152.76 297.08 187.2 319.57L256 403.8L324.8 319.57C359.24 297.08 382 258.2 382 214C382 144.41 325.59 88 256 88Z"
2450
- />
2451
- <rect x="238" y="20" width="36" height="84" rx="4" fill="url(#locator-gradient)" />
2452
- <rect x="62" y="196" width="84" height="36" rx="4" fill="url(#locator-gradient)" />
2453
- <rect x="366" y="196" width="84" height="36" rx="4" fill="url(#locator-gradient)" />
2454
- <path
2455
- d="M213.5 160L158 211.5L213.5 263L238 236.5L211 211.5L238 186.5L213.5 160Z"
2456
- fill="url(#left-code-gradient)"
2457
- />
2458
- <path
2459
- d="M298.5 160L354 211.5L298.5 263L274 236.5L301 211.5L274 186.5L298.5 160Z"
2460
- fill="url(#right-code-gradient)"
2461
- />
2462
- <path
2463
- d="M283 108L232 212L266 253L238 369L302 237L267 198L283 108Z"
2464
- fill="url(#bolt-gradient)"
2465
- />
2466
- `;
2467
-
2468
- // src/ui/brand-mark.ts
2469
- var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
2470
- function resolveBrandMarkContent(override) {
2471
- if (override !== void 0) {
2472
- return { content: override, viewBox: "0 0 512 512" };
2473
- }
2474
- const injected = typeof __SPOTPATCH_BRAND_MARK_CONTENT__ === "string" ? __SPOTPATCH_BRAND_MARK_CONTENT__ : void 0;
2475
- if (typeof injected === "string") {
2476
- return { content: injected, viewBox: "0 0 512 512" };
2477
- }
2478
- return true ? { content: BRAND_MARK_CONTENT, viewBox: "0 0 512 512" } : { content: FALLBACK_BRAND_MARK_CONTENT, viewBox: "0 0 1 1" };
2479
- }
2480
- function svgElement(document, tagName, attributes) {
2481
- const element2 = document.createElementNS(SVG_NAMESPACE, tagName);
2482
- for (const [name, value] of Object.entries(attributes)) {
2483
- element2.setAttribute(name, value);
2484
- }
2485
- return element2;
2486
- }
2487
- function createBrandMark(document, content) {
2488
- const resolved = resolveBrandMarkContent(content);
2489
- const svg = svgElement(document, "svg", {
2490
- xmlns: SVG_NAMESPACE,
2491
- class: "spotpatch-brand-mark",
2492
- viewBox: resolved.viewBox,
2493
- "aria-hidden": "true",
2494
- focusable: "false"
2495
- });
2496
- svg.innerHTML = resolved.content;
2497
- return svg;
2498
- }
2499
-
2500
- // src/ui/dialog-placement.ts
2501
- var VIEWPORT_MARGIN = 16;
2502
- var TARGET_GAP = 14;
2503
- var TARGET_INSET = 24;
2504
- var ANCHOR_INSET = 22;
2505
- function clamp(value, minimum, maximum) {
2506
- return Math.min(Math.max(value, minimum), Math.max(minimum, maximum));
2507
- }
2508
- function calculateDialogPlacement({
2509
- dialogHeight,
2510
- dialogWidth,
2511
- target: target2,
2512
- viewportHeight,
2513
- viewportWidth
2514
- }) {
2515
- const maxLeft = viewportWidth - dialogWidth - VIEWPORT_MARGIN;
2516
- const maxTop = viewportHeight - dialogHeight - VIEWPORT_MARGIN;
2517
- const viewportLeft = clamp(
2518
- (viewportWidth - dialogWidth) / 2,
2519
- VIEWPORT_MARGIN,
2520
- maxLeft
2521
- );
2522
- const viewportTop = clamp(
2523
- (viewportHeight - dialogHeight) / 2,
2524
- VIEWPORT_MARGIN,
2525
- maxTop
2526
- );
2527
- if (target2 === void 0) {
2528
- return Object.freeze({
2529
- anchorX: clamp(dialogWidth / 2, ANCHOR_INSET, dialogWidth - ANCHOR_INSET),
2530
- anchorY: clamp(dialogHeight / 2, ANCHOR_INSET, dialogHeight - ANCHOR_INSET),
2531
- left: viewportLeft,
2532
- mode: "viewport",
2533
- top: viewportTop
2534
- });
2535
- }
2536
- const targetCenterX = target2.x + target2.width / 2;
2537
- const targetCenterY = target2.y + target2.height / 2;
2538
- const centeredLeft = clamp(targetCenterX - dialogWidth / 2, VIEWPORT_MARGIN, maxLeft);
2539
- const centeredTop = clamp(targetCenterY - dialogHeight / 2, VIEWPORT_MARGIN, maxTop);
2540
- let left = centeredLeft;
2541
- let top = centeredTop;
2542
- let mode = "viewport";
2543
- if (target2.width >= dialogWidth + TARGET_INSET * 2 && target2.height >= dialogHeight + TARGET_INSET * 2) {
2544
- mode = "center";
2545
- } else if (target2.y - dialogHeight - TARGET_GAP >= VIEWPORT_MARGIN) {
2546
- top = target2.y - dialogHeight - TARGET_GAP;
2547
- mode = "above";
2548
- } else if (target2.y + target2.height + TARGET_GAP + dialogHeight <= viewportHeight - VIEWPORT_MARGIN) {
2549
- top = target2.y + target2.height + TARGET_GAP;
2550
- mode = "below";
2551
- } else if (target2.x + target2.width + TARGET_GAP + dialogWidth <= viewportWidth - VIEWPORT_MARGIN) {
2552
- left = target2.x + target2.width + TARGET_GAP;
2553
- mode = "right";
2554
- } else if (target2.x - dialogWidth - TARGET_GAP >= VIEWPORT_MARGIN) {
2555
- left = target2.x - dialogWidth - TARGET_GAP;
2556
- mode = "left";
2557
- }
2558
- return Object.freeze({
2559
- anchorX: clamp(targetCenterX - left, ANCHOR_INSET, dialogWidth - ANCHOR_INSET),
2560
- anchorY: clamp(targetCenterY - top, ANCHOR_INSET, dialogHeight - ANCHOR_INSET),
2561
- left,
2562
- mode,
2563
- top
2564
- });
2565
- }
2566
-
2567
2428
  // src/ui/localization.ts
2568
2429
  import {
2569
2430
  ERROR_CODES as ERROR_CODES2
@@ -2598,6 +2459,51 @@ var STATUS_ZH = Object.freeze({
2598
2459
  reverted: "\u5DF2\u64A4\u9500",
2599
2460
  failed: "\u5931\u8D25"
2600
2461
  });
2462
+ var EXECUTION_ACTIVITY_EN = Object.freeze({
2463
+ prepare: "Preparing context",
2464
+ dispatch: "Dispatching context",
2465
+ discover: "Discovering project files",
2466
+ search: "Searching source",
2467
+ read: "Reading",
2468
+ patch: "Generating a minimal patch",
2469
+ check: "Running",
2470
+ audit: "Auditing proposed changes",
2471
+ apply: "Applying verified changes",
2472
+ sync: "Returning results to SpotPatch",
2473
+ unknown: "Processing the current task"
2474
+ });
2475
+ var EXECUTION_ACTIVITY_ZH = Object.freeze({
2476
+ prepare: "\u6B63\u5728\u51C6\u5907\u4E0A\u4E0B\u6587",
2477
+ dispatch: "\u6B63\u5728\u6D3E\u53D1\u4E0A\u4E0B\u6587",
2478
+ discover: "\u6B63\u5728\u67E5\u627E\u9879\u76EE\u6587\u4EF6",
2479
+ search: "\u6B63\u5728\u641C\u7D22\u6E90\u7801",
2480
+ read: "\u6B63\u5728\u8BFB\u53D6",
2481
+ patch: "\u6B63\u5728\u751F\u6210\u6700\u5C0F\u4FEE\u6539\u8865\u4E01",
2482
+ check: "\u6B63\u5728\u8FD0\u884C",
2483
+ audit: "\u6B63\u5728\u5BA1\u8BA1\u5019\u9009\u4FEE\u6539",
2484
+ apply: "\u6B63\u5728\u5E94\u7528\u5DF2\u9A8C\u8BC1\u4FEE\u6539",
2485
+ sync: "\u6B63\u5728\u5C06\u7ED3\u679C\u56DE\u6D41 SpotPatch",
2486
+ unknown: "\u6B63\u5728\u5904\u7406\u5F53\u524D\u4EFB\u52A1"
2487
+ });
2488
+ var EXECUTION_LANE_LABELS = Object.freeze({
2489
+ prepare: "prepare",
2490
+ dispatch: "dispatch",
2491
+ discover: "list",
2492
+ search: "search",
2493
+ read: "read",
2494
+ patch: "patch",
2495
+ check: "check",
2496
+ audit: "audit",
2497
+ apply: "apply",
2498
+ sync: "sync",
2499
+ unknown: "agent"
2500
+ });
2501
+ function executionActivityAction(labels, kind, detail) {
2502
+ return detail === void 0 || detail.length === 0 ? labels[kind] : `${labels[kind]} ${detail}`;
2503
+ }
2504
+ function executionActivityLane(kind, detail) {
2505
+ return detail === void 0 || detail.length === 0 ? EXECUTION_LANE_LABELS[kind] : `${EXECUTION_LANE_LABELS[kind]} \xB7 ${detail}`;
2506
+ }
2601
2507
  var EXTERNAL_HANDOFF_ERROR_EN = "The external Agent handoff request failed.";
2602
2508
  var EXTERNAL_HANDOFF_ERROR_ZH = "\u5916\u90E8 Agent \u4EA4\u63A5\u8BF7\u6C42\u5931\u8D25\u3002";
2603
2509
  var ERROR_MESSAGES_EN = Object.freeze({
@@ -2815,6 +2721,11 @@ var UI_MESSAGES = Object.freeze({
2815
2721
  previewTitle: "Review the request",
2816
2722
  previewSubtitle: "Verify the complete context before it leaves the browser."
2817
2723
  }),
2724
+ floatingSurface: Object.freeze({
2725
+ dragHandle: "Drag to move the SpotPatch workbench",
2726
+ resetPosition: "Reset workbench position",
2727
+ positionReset: "SpotPatch position reset to the lower-right corner."
2728
+ }),
2818
2729
  context: Object.freeze({
2819
2730
  collecting: "Collecting context",
2820
2731
  ready: "Context ready",
@@ -2901,6 +2812,27 @@ var UI_MESSAGES = Object.freeze({
2901
2812
  noOutput: "No output.",
2902
2813
  status: (status) => STATUS_EN[status]
2903
2814
  }),
2815
+ execution: Object.freeze({
2816
+ claude: "Claude",
2817
+ codex: "Codex",
2818
+ receivingTitle: "Receiving context",
2819
+ dispatchingTitle: (identity) => `Handing off to ${identity}`,
2820
+ runningTitle: (target2) => `Modifying ${target2}`,
2821
+ expandedRunningTitle: (identity) => `${identity} is making changes`,
2822
+ completedTitle: "Change complete",
2823
+ expandedCompletedTitle: "Changes complete",
2824
+ failedTitle: "Execution failed",
2825
+ receivingStatus: "Receiving",
2826
+ dispatchingStatus: "Dispatching",
2827
+ runningStatus: "Running",
2828
+ checkingStatus: "Checking",
2829
+ completedStatus: "Done",
2830
+ failedStatus: "Failed",
2831
+ resultReturned: "The result is back in SpotPatch",
2832
+ resultSummary: (files) => `${String(files)} ${files === 1 ? "file" : "files"}`,
2833
+ activityAction: (kind, detail) => executionActivityAction(EXECUTION_ACTIVITY_EN, kind, detail),
2834
+ activityLane: executionActivityLane
2835
+ }),
2904
2836
  announcements: Object.freeze({
2905
2837
  adapterDisabled: "React inspection was disabled after an adapter failure.",
2906
2838
  selectionEnabled: "Element selection enabled.",
@@ -2953,6 +2885,11 @@ var UI_MESSAGES = Object.freeze({
2953
2885
  previewTitle: "\u5BA1\u9605\u4FEE\u6539\u8BF7\u6C42",
2954
2886
  previewSubtitle: "\u53D1\u9001\u7ED9 AI \u524D\uFF0C\u8BF7\u6838\u5BF9\u5B8C\u6574\u4E0A\u4E0B\u6587\u4E0E\u6BCF\u9879\u76EE\u6807\u8BF4\u660E\u3002"
2955
2887
  }),
2888
+ floatingSurface: Object.freeze({
2889
+ dragHandle: "\u62D6\u62FD\u4EE5\u79FB\u52A8 SpotPatch \u5DE5\u4F5C\u53F0",
2890
+ resetPosition: "\u91CD\u7F6E\u5DE5\u4F5C\u53F0\u4F4D\u7F6E",
2891
+ positionReset: "SpotPatch \u5DF2\u6062\u590D\u5230\u53F3\u4E0B\u89D2\u3002"
2892
+ }),
2956
2893
  context: Object.freeze({
2957
2894
  collecting: "\u6B63\u5728\u91C7\u96C6\u4E0A\u4E0B\u6587",
2958
2895
  ready: "\u4E0A\u4E0B\u6587\u5DF2\u5C31\u7EEA",
@@ -3039,6 +2976,27 @@ var UI_MESSAGES = Object.freeze({
3039
2976
  noOutput: "\u6CA1\u6709\u8F93\u51FA\u3002",
3040
2977
  status: (status) => STATUS_ZH[status]
3041
2978
  }),
2979
+ execution: Object.freeze({
2980
+ claude: "Claude",
2981
+ codex: "Codex",
2982
+ receivingTitle: "\u6B63\u5728\u63A5\u6536\u4E0A\u4E0B\u6587",
2983
+ dispatchingTitle: (identity) => `\u6B63\u5728\u4EA4\u63A5\u7ED9 ${identity}`,
2984
+ runningTitle: (target2) => `\u6B63\u5728\u4FEE\u6539 ${target2}`,
2985
+ expandedRunningTitle: (identity) => `${identity} \u6B63\u5728\u6267\u884C\u4FEE\u6539`,
2986
+ completedTitle: "\u4FEE\u6539\u5B8C\u6210",
2987
+ expandedCompletedTitle: "\u4FEE\u6539\u5DF2\u5B8C\u6210",
2988
+ failedTitle: "\u6267\u884C\u5931\u8D25",
2989
+ receivingStatus: "\u63A5\u6536\u4E2D",
2990
+ dispatchingStatus: "\u6D3E\u53D1\u4E2D",
2991
+ runningStatus: "\u6267\u884C\u4E2D",
2992
+ checkingStatus: "\u68C0\u67E5\u4E2D",
2993
+ completedStatus: "\u5B8C\u6210",
2994
+ failedStatus: "\u5931\u8D25",
2995
+ resultReturned: "\u7ED3\u679C\u5DF2\u56DE\u6D41 SpotPatch",
2996
+ resultSummary: (files) => `${String(files)} \u4E2A\u6587\u4EF6`,
2997
+ activityAction: (kind, detail) => executionActivityAction(EXECUTION_ACTIVITY_ZH, kind, detail),
2998
+ activityLane: executionActivityLane
2999
+ }),
3042
3000
  announcements: Object.freeze({
3043
3001
  adapterDisabled: "React \u9002\u914D\u5668\u5F02\u5E38\uFF0C\u672C\u6B21\u4F1A\u8BDD\u5DF2\u505C\u7528 React \u68C0\u67E5\u3002",
3044
3002
  selectionEnabled: "\u5143\u7D20\u9009\u62E9\u5DF2\u542F\u7528\u3002",
@@ -3112,13 +3070,500 @@ function createUiLocalizer(document, preference = "auto") {
3112
3070
  });
3113
3071
  }
3114
3072
 
3115
- // src/ui/runtime-view.ts
3116
- var DIALOG_MAX_WIDTH = 460;
3117
- var DIALOG_MAX_HEIGHT = 620;
3118
- var DIALOG_FALLBACK_HEIGHT = Object.freeze({
3119
- previewing: 560,
3120
- selected: DIALOG_MAX_HEIGHT
3073
+ // src/state/floating-surface-session.ts
3074
+ var STORAGE_PREFIX2 = "spotpatch:floating-surface:";
3075
+ var SNAPSHOT_VERSION2 = 1;
3076
+ var MAX_SNAPSHOT_CHARACTERS2 = 1024;
3077
+ function record2(value) {
3078
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
3079
+ }
3080
+ function finiteRatio(value) {
3081
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
3082
+ }
3083
+ function alignment(value) {
3084
+ return value === "start" || value === "end";
3085
+ }
3086
+ function parseSnapshot2(value) {
3087
+ const snapshot = record2(value);
3088
+ if (snapshot?.version !== SNAPSHOT_VERSION2 || !alignment(snapshot.horizontal) || !alignment(snapshot.vertical) || !finiteRatio(snapshot.xRatio) || !finiteRatio(snapshot.yRatio)) {
3089
+ return void 0;
3090
+ }
3091
+ return Object.freeze({
3092
+ horizontal: snapshot.horizontal,
3093
+ vertical: snapshot.vertical,
3094
+ xRatio: snapshot.xRatio,
3095
+ yRatio: snapshot.yRatio
3096
+ });
3097
+ }
3098
+ function createFloatingSurfaceSession(window, sessionId) {
3099
+ const key = `${STORAGE_PREFIX2}${sessionId}`;
3100
+ let storage;
3101
+ try {
3102
+ storage = window.sessionStorage;
3103
+ } catch {
3104
+ storage = void 0;
3105
+ }
3106
+ return Object.freeze({
3107
+ clear() {
3108
+ try {
3109
+ storage?.removeItem(key);
3110
+ } catch {
3111
+ }
3112
+ },
3113
+ load() {
3114
+ let serialized;
3115
+ try {
3116
+ serialized = storage?.getItem(key) ?? null;
3117
+ } catch {
3118
+ return void 0;
3119
+ }
3120
+ if (serialized === null || serialized.length > MAX_SNAPSHOT_CHARACTERS2) {
3121
+ return void 0;
3122
+ }
3123
+ try {
3124
+ return parseSnapshot2(JSON.parse(serialized));
3125
+ } catch {
3126
+ return void 0;
3127
+ }
3128
+ },
3129
+ save(position) {
3130
+ try {
3131
+ storage?.setItem(
3132
+ key,
3133
+ JSON.stringify({ version: SNAPSHOT_VERSION2, ...position })
3134
+ );
3135
+ } catch {
3136
+ }
3137
+ }
3138
+ });
3139
+ }
3140
+
3141
+ // src/ui/floating-surface-position.ts
3142
+ var DEFAULT_FLOATING_SURFACE_POSITION = Object.freeze({
3143
+ horizontal: "end",
3144
+ vertical: "end",
3145
+ xRatio: 1,
3146
+ yRatio: 1
3121
3147
  });
3148
+ function clamp(value, minimum, maximum) {
3149
+ return Math.min(Math.max(value, minimum), maximum);
3150
+ }
3151
+ function finiteNonNegative(value) {
3152
+ return Number.isFinite(value) ? Math.max(0, value) : 0;
3153
+ }
3154
+ function boundedRatio(value) {
3155
+ return Number.isFinite(value) ? clamp(value, 0, 1) : 0.5;
3156
+ }
3157
+ function normalizedViewport(viewport) {
3158
+ return Object.freeze({
3159
+ height: finiteNonNegative(viewport.height),
3160
+ left: Number.isFinite(viewport.left) ? viewport.left : 0,
3161
+ top: Number.isFinite(viewport.top) ? viewport.top : 0,
3162
+ width: finiteNonNegative(viewport.width)
3163
+ });
3164
+ }
3165
+ function horizontalAnchor(rect, alignment2) {
3166
+ return alignment2 === "end" ? rect.left + rect.width : rect.left;
3167
+ }
3168
+ function verticalAnchor(rect, alignment2) {
3169
+ return alignment2 === "end" ? rect.top + rect.height : rect.top;
3170
+ }
3171
+ function normalizedCoordinate(coordinate, origin, length) {
3172
+ if (length <= 0) {
3173
+ return 0.5;
3174
+ }
3175
+ return boundedRatio((coordinate - origin) / length);
3176
+ }
3177
+ function positionFromAnchor(anchor, viewport, horizontal, vertical) {
3178
+ return Object.freeze({
3179
+ horizontal,
3180
+ vertical,
3181
+ xRatio: normalizedCoordinate(anchor.x, viewport.left, viewport.width),
3182
+ yRatio: normalizedCoordinate(anchor.y, viewport.top, viewport.height)
3183
+ });
3184
+ }
3185
+ function resolveFloatingSurfaceRect(position, size, viewport) {
3186
+ const width = finiteNonNegative(size.width);
3187
+ const height = finiteNonNegative(size.height);
3188
+ const normalized = normalizedViewport(viewport);
3189
+ const viewportWidth = normalized.width;
3190
+ const viewportHeight = normalized.height;
3191
+ const leftBoundary = normalized.left;
3192
+ const topBoundary = normalized.top;
3193
+ const rightBoundary = leftBoundary + viewportWidth;
3194
+ const bottomBoundary = topBoundary + viewportHeight;
3195
+ const anchorX = leftBoundary + boundedRatio(position.xRatio) * viewportWidth;
3196
+ const anchorY = topBoundary + boundedRatio(position.yRatio) * viewportHeight;
3197
+ const requestedLeft = position.horizontal === "end" ? anchorX - width : anchorX;
3198
+ const requestedTop = position.vertical === "end" ? anchorY - height : anchorY;
3199
+ const maximumLeft = Math.max(leftBoundary, rightBoundary - width);
3200
+ const maximumTop = Math.max(topBoundary, bottomBoundary - height);
3201
+ return Object.freeze({
3202
+ height,
3203
+ left: clamp(requestedLeft, leftBoundary, maximumLeft),
3204
+ top: clamp(requestedTop, topBoundary, maximumTop),
3205
+ width
3206
+ });
3207
+ }
3208
+ function snapFloatingSurfaceRect(rect, viewport, snapDistance) {
3209
+ const distance = finiteNonNegative(snapDistance);
3210
+ const width = finiteNonNegative(rect.width);
3211
+ const height = finiteNonNegative(rect.height);
3212
+ const normalized = normalizedViewport(viewport);
3213
+ const viewportRight = normalized.left + normalized.width;
3214
+ const viewportBottom = normalized.top + normalized.height;
3215
+ const maximumLeft = Math.max(normalized.left, viewportRight - width);
3216
+ const maximumTop = Math.max(normalized.top, viewportBottom - height);
3217
+ const requestedLeft = clamp(rect.left, normalized.left, maximumLeft);
3218
+ const requestedTop = clamp(rect.top, normalized.top, maximumTop);
3219
+ const leftDistance = Math.abs(requestedLeft - normalized.left);
3220
+ const rightDistance = Math.abs(viewportRight - (requestedLeft + width));
3221
+ const topDistance = Math.abs(requestedTop - normalized.top);
3222
+ const bottomDistance = Math.abs(viewportBottom - (requestedTop + height));
3223
+ const left = Math.min(leftDistance, rightDistance) <= distance ? leftDistance <= rightDistance ? normalized.left : viewportRight - width : requestedLeft;
3224
+ const top = Math.min(topDistance, bottomDistance) <= distance ? topDistance <= bottomDistance ? normalized.top : viewportBottom - height : requestedTop;
3225
+ return Object.freeze({ height, left, top, width });
3226
+ }
3227
+ function positionFromFloatingSurfaceRect(rect, viewport, previous) {
3228
+ const bounded = snapFloatingSurfaceRect(rect, viewport, 0);
3229
+ const centerX = bounded.left + bounded.width / 2;
3230
+ const centerY = bounded.top + bounded.height / 2;
3231
+ const viewportCenterX = viewport.left + finiteNonNegative(viewport.width) / 2;
3232
+ const viewportCenterY = viewport.top + finiteNonNegative(viewport.height) / 2;
3233
+ const horizontal = centerX === viewportCenterX ? previous.horizontal : centerX < viewportCenterX ? "start" : "end";
3234
+ const vertical = centerY === viewportCenterY ? previous.vertical : centerY < viewportCenterY ? "start" : "end";
3235
+ return positionFromAnchor(
3236
+ {
3237
+ x: horizontalAnchor(bounded, horizontal),
3238
+ y: verticalAnchor(bounded, vertical)
3239
+ },
3240
+ viewport,
3241
+ horizontal,
3242
+ vertical
3243
+ );
3244
+ }
3245
+
3246
+ // src/ui/floating-surface-controller.ts
3247
+ function finite(value, fallback = 0) {
3248
+ return Number.isFinite(value) ? value : fallback;
3249
+ }
3250
+ function distanceBetween(first, second) {
3251
+ return Math.hypot(first.x - second.x, first.y - second.y);
3252
+ }
3253
+ function isPrimaryPointer(event) {
3254
+ return event.button === 0 && event.isPrimary;
3255
+ }
3256
+ function surfaceSize(surface) {
3257
+ const rect = surface.getBoundingClientRect();
3258
+ return Object.freeze({
3259
+ height: Math.max(0, finite(rect.height)),
3260
+ width: Math.max(0, finite(rect.width))
3261
+ });
3262
+ }
3263
+ function requestFrame(window, callback) {
3264
+ if (typeof window.requestAnimationFrame === "function") {
3265
+ return window.requestAnimationFrame(callback);
3266
+ }
3267
+ return window.setTimeout(() => {
3268
+ callback(Date.now());
3269
+ }, 0);
3270
+ }
3271
+ function cancelFrame(window, frame) {
3272
+ if (typeof window.cancelAnimationFrame === "function") {
3273
+ window.cancelAnimationFrame(frame);
3274
+ return;
3275
+ }
3276
+ window.clearTimeout(frame);
3277
+ }
3278
+ function createFloatingSurfaceController(window, session, layout) {
3279
+ let position = session.load() ?? DEFAULT_FLOATING_SURFACE_POSITION;
3280
+ let drag;
3281
+ let frame;
3282
+ let suppressClickFor;
3283
+ let suppressClickTimer;
3284
+ let disposed = false;
3285
+ const surfaces = /* @__PURE__ */ new Set();
3286
+ const cleanup = /* @__PURE__ */ new Set();
3287
+ function viewport() {
3288
+ const visualViewport = window.visualViewport;
3289
+ const width = Math.max(0, finite(visualViewport?.width ?? window.innerWidth));
3290
+ const height = Math.max(0, finite(visualViewport?.height ?? window.innerHeight));
3291
+ const inset = width <= layout.compactViewportWidth ? layout.compactInset : layout.desktopInset;
3292
+ return Object.freeze({
3293
+ height: Math.max(0, height - inset * 2),
3294
+ left: finite(visualViewport?.offsetLeft ?? 0) + inset,
3295
+ top: finite(visualViewport?.offsetTop ?? 0) + inset,
3296
+ width: Math.max(0, width - inset * 2)
3297
+ });
3298
+ }
3299
+ function isCompact() {
3300
+ return viewport().width + layout.compactInset * 2 <= layout.compactViewportWidth;
3301
+ }
3302
+ function apply(surface) {
3303
+ if (surface.hidden) {
3304
+ return void 0;
3305
+ }
3306
+ if (surface.dataset.motionMorphing === "true" && surface.dataset.floatingPositioned === "true") {
3307
+ return void 0;
3308
+ }
3309
+ const size = surfaceSize(surface);
3310
+ if (size.width === 0 || size.height === 0) {
3311
+ return void 0;
3312
+ }
3313
+ const rect = resolveFloatingSurfaceRect(position, size, viewport());
3314
+ surface.style.left = `${String(rect.left)}px`;
3315
+ surface.style.top = `${String(rect.top)}px`;
3316
+ surface.style.right = "auto";
3317
+ surface.style.bottom = "auto";
3318
+ surface.dataset.floatingPositioned = "true";
3319
+ return rect;
3320
+ }
3321
+ function reconcile() {
3322
+ if (disposed) {
3323
+ return;
3324
+ }
3325
+ if (frame !== void 0) {
3326
+ cancelFrame(window, frame);
3327
+ frame = void 0;
3328
+ }
3329
+ for (const surface of surfaces) {
3330
+ apply(surface);
3331
+ }
3332
+ }
3333
+ function requestReconcile() {
3334
+ if (disposed || frame !== void 0) {
3335
+ return;
3336
+ }
3337
+ frame = requestFrame(window, () => {
3338
+ frame = void 0;
3339
+ reconcile();
3340
+ });
3341
+ }
3342
+ function commit(nextPosition) {
3343
+ position = nextPosition;
3344
+ session.save(position);
3345
+ }
3346
+ function finishDrag(commitPosition) {
3347
+ const current = drag;
3348
+ if (current === void 0) {
3349
+ return;
3350
+ }
3351
+ drag = void 0;
3352
+ current.handle.dataset.dragging = "false";
3353
+ current.surface.dataset.dragging = "false";
3354
+ try {
3355
+ if (current.handle.hasPointerCapture(current.pointerId)) {
3356
+ current.handle.releasePointerCapture(current.pointerId);
3357
+ }
3358
+ } catch {
3359
+ }
3360
+ if (commitPosition) {
3361
+ const rect = apply(current.surface);
3362
+ if (rect !== void 0) {
3363
+ const snapped = snapFloatingSurfaceRect(
3364
+ rect,
3365
+ viewport(),
3366
+ layout.edgeSnapDistance
3367
+ );
3368
+ commit(positionFromFloatingSurfaceRect(snapped, viewport(), position));
3369
+ apply(current.surface);
3370
+ }
3371
+ } else {
3372
+ position = session.load() ?? DEFAULT_FLOATING_SURFACE_POSITION;
3373
+ reconcile();
3374
+ }
3375
+ }
3376
+ function updateDrag(event) {
3377
+ const current = drag;
3378
+ if (current === void 0) {
3379
+ return;
3380
+ }
3381
+ if (event.pointerId !== current.pointerId) {
3382
+ return;
3383
+ }
3384
+ const pointer = Object.freeze({ x: event.clientX, y: event.clientY });
3385
+ const start = Object.freeze({ x: current.startX, y: current.startY });
3386
+ if (current.handle.dataset.dragging !== "true" && distanceBetween(pointer, start) < layout.dragActivationDistance) {
3387
+ return;
3388
+ }
3389
+ if (current.handle.dataset.dragging !== "true") {
3390
+ current.onDragStart?.();
3391
+ }
3392
+ current.handle.dataset.dragging = "true";
3393
+ current.surface.dataset.dragging = "true";
3394
+ position = positionFromAnchor(
3395
+ {
3396
+ x: pointer.x + current.anchorOffsetX,
3397
+ y: pointer.y + current.anchorOffsetY
3398
+ },
3399
+ viewport(),
3400
+ position.horizontal,
3401
+ position.vertical
3402
+ );
3403
+ requestReconcile();
3404
+ event.preventDefault();
3405
+ }
3406
+ function addListener(target2, type, listener, options) {
3407
+ target2.addEventListener(type, listener, options);
3408
+ cleanup.add(() => {
3409
+ target2.removeEventListener(type, listener, options);
3410
+ });
3411
+ }
3412
+ function attachDraggable(handle, surface, options = {}) {
3413
+ const onPointerDown = (event) => {
3414
+ if (disposed || drag !== void 0 || !isPrimaryPointer(event) || options.canStartDrag?.(event) === false) {
3415
+ return;
3416
+ }
3417
+ const rect = apply(surface) ?? surface.getBoundingClientRect();
3418
+ const anchorX = position.horizontal === "end" ? rect.left + rect.width : rect.left;
3419
+ const anchorY = position.vertical === "end" ? rect.top + rect.height : rect.top;
3420
+ drag = Object.freeze({
3421
+ anchorOffsetX: anchorX - event.clientX,
3422
+ anchorOffsetY: anchorY - event.clientY,
3423
+ handle,
3424
+ ...options.onDragStart === void 0 ? {} : { onDragStart: options.onDragStart },
3425
+ pointerId: event.pointerId,
3426
+ startX: event.clientX,
3427
+ startY: event.clientY,
3428
+ suppressClickOnDrag: options.suppressClickOnDrag ?? false,
3429
+ surface
3430
+ });
3431
+ try {
3432
+ handle.setPointerCapture(event.pointerId);
3433
+ } catch {
3434
+ }
3435
+ };
3436
+ const onLostPointerCapture = (event) => {
3437
+ if (drag?.pointerId === event.pointerId) {
3438
+ finishDrag(handle.dataset.dragging === "true");
3439
+ }
3440
+ };
3441
+ const onClickCapture = (event) => {
3442
+ if (suppressClickFor !== handle) {
3443
+ return;
3444
+ }
3445
+ suppressClickFor = void 0;
3446
+ if (suppressClickTimer !== void 0) {
3447
+ window.clearTimeout(suppressClickTimer);
3448
+ suppressClickTimer = void 0;
3449
+ }
3450
+ event.preventDefault();
3451
+ event.stopImmediatePropagation();
3452
+ };
3453
+ addListener(handle, "pointerdown", (event) => {
3454
+ onPointerDown(event);
3455
+ });
3456
+ addListener(handle, "lostpointercapture", (event) => {
3457
+ onLostPointerCapture(event);
3458
+ });
3459
+ addListener(
3460
+ handle,
3461
+ "click",
3462
+ (event) => {
3463
+ onClickCapture(event);
3464
+ },
3465
+ true
3466
+ );
3467
+ }
3468
+ function reset() {
3469
+ finishDrag(false);
3470
+ position = DEFAULT_FLOATING_SURFACE_POSITION;
3471
+ session.clear();
3472
+ reconcile();
3473
+ }
3474
+ function cancelOnWindowBlur() {
3475
+ finishDrag(false);
3476
+ }
3477
+ function cancelOnEscape(event) {
3478
+ if (event.key !== "Escape" || drag === void 0) {
3479
+ return;
3480
+ }
3481
+ finishDrag(false);
3482
+ event.preventDefault();
3483
+ event.stopImmediatePropagation();
3484
+ }
3485
+ function endPointer(event) {
3486
+ if (drag?.pointerId !== event.pointerId) {
3487
+ return;
3488
+ }
3489
+ const current = drag;
3490
+ const moved = current.handle.dataset.dragging === "true";
3491
+ finishDrag(moved);
3492
+ if (moved && current.suppressClickOnDrag) {
3493
+ suppressClickFor = current.handle;
3494
+ suppressClickTimer = window.setTimeout(() => {
3495
+ suppressClickFor = void 0;
3496
+ suppressClickTimer = void 0;
3497
+ }, 0);
3498
+ }
3499
+ }
3500
+ function cancelPointer(event) {
3501
+ if (drag?.pointerId === event.pointerId) {
3502
+ finishDrag(false);
3503
+ }
3504
+ }
3505
+ addListener(window, "pointermove", (event) => {
3506
+ updateDrag(event);
3507
+ });
3508
+ addListener(window, "pointerup", (event) => {
3509
+ endPointer(event);
3510
+ });
3511
+ addListener(window, "pointercancel", (event) => {
3512
+ cancelPointer(event);
3513
+ });
3514
+ addListener(window, "resize", requestReconcile);
3515
+ addListener(window, "blur", cancelOnWindowBlur);
3516
+ addListener(
3517
+ window,
3518
+ "keydown",
3519
+ (event) => {
3520
+ cancelOnEscape(event);
3521
+ },
3522
+ true
3523
+ );
3524
+ window.visualViewport?.addEventListener("resize", requestReconcile);
3525
+ window.visualViewport?.addEventListener("scroll", requestReconcile);
3526
+ cleanup.add(
3527
+ () => window.visualViewport?.removeEventListener("resize", requestReconcile)
3528
+ );
3529
+ cleanup.add(
3530
+ () => window.visualViewport?.removeEventListener("scroll", requestReconcile)
3531
+ );
3532
+ return Object.freeze({
3533
+ attachDraggable,
3534
+ dispose() {
3535
+ if (disposed) {
3536
+ return;
3537
+ }
3538
+ disposed = true;
3539
+ finishDrag(false);
3540
+ if (frame !== void 0) {
3541
+ cancelFrame(window, frame);
3542
+ frame = void 0;
3543
+ }
3544
+ if (suppressClickTimer !== void 0) {
3545
+ window.clearTimeout(suppressClickTimer);
3546
+ suppressClickTimer = void 0;
3547
+ }
3548
+ suppressClickFor = void 0;
3549
+ for (const disposeListener of cleanup) {
3550
+ disposeListener();
3551
+ }
3552
+ cleanup.clear();
3553
+ surfaces.clear();
3554
+ },
3555
+ isCompact,
3556
+ reconcile,
3557
+ registerSurface(surface) {
3558
+ surfaces.add(surface);
3559
+ },
3560
+ requestReconcile,
3561
+ reset
3562
+ });
3563
+ }
3564
+
3565
+ // src/ui/runtime-view.ts
3566
+ var SUCCESS_SETTLE_MS = 1500;
3122
3567
  function resolveStyleNonce(document) {
3123
3568
  const nonces = new Set(
3124
3569
  [...document.querySelectorAll("script[nonce]")].map((script) => script.nonce?.trim() ?? "").filter(Boolean)
@@ -3149,53 +3594,20 @@ function createStyles(document) {
3149
3594
  --spotpatch-success: #34d399;
3150
3595
  --spotpatch-warning: #f59e0b;
3151
3596
  --spotpatch-text-on-accent: #0b0b12;
3152
- --spotpatch-radius-panel: 16px;
3153
3597
  --spotpatch-radius-card: 10px;
3154
- --spotpatch-shadow-panel: 0 30px 60px -20px rgb(0 0 0 / 70%);
3155
- color-scheme: dark;
3156
3598
  color: var(--spotpatch-text);
3157
3599
  font-family: Inter, "SF Pro Display", "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
3158
3600
  font-size: 14px;
3159
3601
  line-height: 1.5;
3160
- text-rendering: optimizeLegibility;
3161
- -webkit-font-smoothing: antialiased;
3162
3602
  }
3163
3603
  [hidden] { display: none !important; }
3164
3604
  button, textarea, select { font: inherit; }
3165
- button { -webkit-tap-highlight-color: transparent; }
3166
- .spotpatch-trigger {
3605
+ .spotpatch-floating-surface {
3167
3606
  position: fixed;
3168
- right: 24px;
3169
- bottom: 24px;
3607
+ right: ${String(FLOATING_SURFACE_LAYOUT.desktopInset)}px;
3608
+ bottom: ${String(FLOATING_SURFACE_LAYOUT.desktopInset)}px;
3170
3609
  z-index: ${String(UI_Z_INDEX.controls)};
3171
- display: inline-flex;
3172
- align-items: center;
3173
- gap: 10px;
3174
- min-height: 44px;
3175
- border: 1px solid rgb(255 255 255 / 12%);
3176
- border-radius: 999px;
3177
- padding: 10px 17px;
3178
- color: #f8fafc;
3179
- background: #171b23;
3180
- box-shadow: 0 12px 34px rgb(0 0 0 / 25%), inset 0 1px rgb(255 255 255 / 5%);
3181
- cursor: pointer;
3182
- font-size: 14px;
3183
- font-weight: 650;
3184
- transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
3185
- }
3186
- .spotpatch-trigger::before {
3187
- width: 9px;
3188
- height: 9px;
3189
- border-radius: 999px;
3190
- background: var(--spotpatch-accent);
3191
- box-shadow: 0 0 0 4px rgb(99 102 241 / 10%);
3192
- content: "";
3193
- }
3194
- .spotpatch-trigger:hover { transform: translateY(-1px); border-color: rgb(129 140 248 / 52%); }
3195
- .spotpatch-trigger[aria-pressed="true"] {
3196
- border-color: rgb(124 58 237 / 55%);
3197
- background: #24203b;
3198
- box-shadow: 0 14px 42px rgb(76 29 149 / 24%), inset 0 1px rgb(255 255 255 / 10%);
3610
+ isolation: isolate;
3199
3611
  }
3200
3612
  .spotpatch-highlight {
3201
3613
  position: fixed;
@@ -3264,82 +3676,28 @@ function createStyles(document) {
3264
3676
  background: #5546dc;
3265
3677
  }
3266
3678
  .spotpatch-dialog {
3267
- --spotpatch-anchor-x: 50%;
3268
- --spotpatch-anchor-y: 50%;
3269
- position: fixed;
3270
- top: 16px;
3271
- left: 16px;
3272
- z-index: ${String(UI_Z_INDEX.controls)};
3679
+ position: relative;
3273
3680
  box-sizing: border-box;
3274
- width: min(${String(DIALOG_MAX_WIDTH)}px, calc(100vw - 32px));
3275
- color: #edf0f7;
3681
+ width: min(${String(FLOATING_SURFACE_LAYOUT.workbenchMaxWidth)}px, calc(100vw - ${String(FLOATING_SURFACE_LAYOUT.desktopInset * 2)}px));
3276
3682
  outline: none;
3277
- filter: drop-shadow(var(--spotpatch-shadow-panel));
3278
3683
  }
3279
- .spotpatch-anchor {
3280
- position: absolute;
3281
- z-index: 0;
3282
- width: 14px;
3283
- height: 14px;
3284
- border: 1px solid rgb(255 255 255 / 12%);
3285
- background: var(--spotpatch-bg);
3286
- transform: rotate(45deg);
3287
- }
3288
- .spotpatch-dialog[data-placement="above"] .spotpatch-anchor {
3289
- bottom: -6px;
3290
- left: calc(var(--spotpatch-anchor-x) - 7px);
3291
- border-top: 0;
3292
- border-left: 0;
3293
- }
3294
- .spotpatch-dialog[data-placement="below"] .spotpatch-anchor {
3295
- top: -6px;
3296
- left: calc(var(--spotpatch-anchor-x) - 7px);
3297
- border-right: 0;
3298
- border-bottom: 0;
3299
- }
3300
- .spotpatch-dialog[data-placement="left"] .spotpatch-anchor {
3301
- top: calc(var(--spotpatch-anchor-y) - 7px);
3302
- right: -6px;
3303
- border-bottom: 0;
3304
- border-left: 0;
3305
- }
3306
- .spotpatch-dialog[data-placement="right"] .spotpatch-anchor {
3307
- top: calc(var(--spotpatch-anchor-y) - 7px);
3308
- left: -6px;
3309
- border-top: 0;
3310
- border-right: 0;
3311
- }
3312
- .spotpatch-dialog[data-placement="center"] .spotpatch-anchor,
3313
- .spotpatch-dialog[data-placement="viewport"] .spotpatch-anchor { display: none; }
3314
3684
  .spotpatch-shell {
3315
3685
  position: relative;
3316
3686
  z-index: 1;
3317
3687
  display: flex;
3318
3688
  box-sizing: border-box;
3319
- max-height: min(${String(DIALOG_MAX_HEIGHT)}px, calc(100vh - 32px));
3689
+ max-height: min(${String(FLOATING_SURFACE_LAYOUT.workbenchMaxHeight)}px, calc(100vh - ${String(FLOATING_SURFACE_LAYOUT.desktopInset * 2)}px));
3320
3690
  overflow: hidden;
3321
3691
  flex-direction: column;
3322
- border: 1px solid var(--spotpatch-border);
3323
- border-radius: var(--spotpatch-radius-panel);
3324
- background: var(--spotpatch-bg);
3325
- box-shadow: inset 0 1px rgb(255 255 255 / 5%), 0 0 60px -32px rgb(139 123 255 / 20%);
3326
- }
3327
- .spotpatch-shell::before {
3328
- position: absolute;
3329
- z-index: 2;
3330
- top: 0;
3331
- right: 20%;
3332
- left: 20%;
3333
- height: 1px;
3334
- background: linear-gradient(90deg, transparent, var(--spotpatch-accent), var(--spotpatch-accent-cyan), transparent);
3335
- content: "";
3336
- opacity: .65;
3337
- pointer-events: none;
3338
3692
  }
3339
3693
  .spotpatch-header {
3340
3694
  position: relative;
3341
3695
  padding: 0 18px 14px;
3342
3696
  }
3697
+ .spotpatch-header[data-spotpatch-drag-handle] { cursor: grab; touch-action: none; user-select: none; }
3698
+ .spotpatch-header[data-dragging="true"] { cursor: grabbing; }
3699
+ .spotpatch-header button,
3700
+ .spotpatch-header a { cursor: pointer; user-select: auto; }
3343
3701
  .spotpatch-brand-row {
3344
3702
  display: flex;
3345
3703
  align-items: center;
@@ -3363,18 +3721,6 @@ function createStyles(document) {
3363
3721
  filter: drop-shadow(0 6px 12px rgb(76 29 149 / 22%));
3364
3722
  }
3365
3723
  .spotpatch-brand-copy { display: grid; min-width: 0; gap: 1px; }
3366
- .spotpatch-brand-name {
3367
- color: #fff;
3368
- font-size: 13.5px;
3369
- font-weight: 680;
3370
- letter-spacing: -.01em;
3371
- }
3372
- .spotpatch-brand-context {
3373
- color: #8e98aa;
3374
- font-size: 10.5px;
3375
- font-weight: 560;
3376
- letter-spacing: .02em;
3377
- }
3378
3724
  .spotpatch-header-controls {
3379
3725
  display: inline-flex;
3380
3726
  align-items: center;
@@ -3383,6 +3729,7 @@ function createStyles(document) {
3383
3729
  }
3384
3730
  .spotpatch-repository,
3385
3731
  .spotpatch-locale,
3732
+ .spotpatch-reset-position,
3386
3733
  .spotpatch-close {
3387
3734
  height: 27px;
3388
3735
  border: 1px solid rgb(255 255 255 / 11%);
@@ -3406,6 +3753,16 @@ function createStyles(document) {
3406
3753
  font-size: 12px;
3407
3754
  font-weight: 650;
3408
3755
  }
3756
+ .spotpatch-reset-position {
3757
+ display: inline-grid;
3758
+ width: 27px;
3759
+ padding: 0;
3760
+ place-items: center;
3761
+ color: #c5cad5;
3762
+ cursor: pointer;
3763
+ font-size: 15px;
3764
+ line-height: 1;
3765
+ }
3409
3766
  .spotpatch-close {
3410
3767
  display: inline-grid;
3411
3768
  width: 27px;
@@ -3419,21 +3776,8 @@ function createStyles(document) {
3419
3776
  }
3420
3777
  .spotpatch-close:hover,
3421
3778
  .spotpatch-locale:hover,
3779
+ .spotpatch-reset-position:hover,
3422
3780
  .spotpatch-repository:hover { border-color: rgb(129 112 247 / 45%); color: #fff; background: rgb(109 93 246 / 10%); }
3423
- .spotpatch-title {
3424
- margin: 0;
3425
- color: #fff;
3426
- font-size: 18px;
3427
- font-weight: 680;
3428
- letter-spacing: -.015em;
3429
- }
3430
- .spotpatch-subtitle {
3431
- max-width: 390px;
3432
- margin: 4px 0 0;
3433
- color: var(--spotpatch-text-secondary);
3434
- font-size: 12.5px;
3435
- line-height: 1.5;
3436
- }
3437
3781
  .spotpatch-target-row {
3438
3782
  display: flex;
3439
3783
  align-items: center;
@@ -3797,6 +4141,7 @@ function createStyles(document) {
3797
4141
  .spotpatch-target-open:focus-visible,
3798
4142
  .spotpatch-target-remove:focus-visible,
3799
4143
  .spotpatch-close:focus-visible,
4144
+ .spotpatch-reset-position:focus-visible,
3800
4145
  .spotpatch-trigger:focus-visible,
3801
4146
  .spotpatch-target-select:focus-visible,
3802
4147
  .spotpatch-target-editor textarea:focus-visible,
@@ -3821,8 +4166,8 @@ function createStyles(document) {
3821
4166
  .spotpatch-diagnostics > summary::before { transition: none; }
3822
4167
  }
3823
4168
  @media (max-width: 520px) {
3824
- .spotpatch-dialog { top: 8px; left: 8px; width: calc(100vw - 16px); }
3825
- .spotpatch-shell { max-height: calc(100vh - 16px); border-radius: 14px; }
4169
+ .spotpatch-dialog { width: calc(100vw - 16px); }
4170
+ .spotpatch-shell { max-height: calc(100dvh - 16px); }
3826
4171
  .spotpatch-header, .spotpatch-body { padding-left: 14px; padding-right: 14px; }
3827
4172
  .spotpatch-brand-row { margin-right: -14px; margin-left: -14px; padding-right: 14px; padding-left: 14px; }
3828
4173
  .spotpatch-actions { padding-right: 14px; padding-left: 14px; }
@@ -3838,6 +4183,38 @@ function summaryLine(summary, prefix) {
3838
4183
  const line = summary.split("\n").find((candidate) => candidate.startsWith(`${prefix}: `));
3839
4184
  return line?.slice(prefix.length + 2).trim();
3840
4185
  }
4186
+ function startsOnInteractiveControl(event) {
4187
+ const target2 = event.target;
4188
+ return target2 instanceof Element && target2.closest(
4189
+ "a, button, input, select, textarea, summary, [contenteditable='true']"
4190
+ ) !== null;
4191
+ }
4192
+ function createFallbackExecutionIsland(document) {
4193
+ const root = createButton(document, "", "spotpatch-execution-island");
4194
+ root.hidden = true;
4195
+ root.setAttribute("aria-hidden", "true");
4196
+ const logo = createBrandMark(
4197
+ document,
4198
+ void 0,
4199
+ "spotpatch-fallback-execution-island"
4200
+ );
4201
+ logo.classList.add("spotpatch-execution-logo");
4202
+ const copy = createMarkedElement(document, "span");
4203
+ root.append(logo, copy);
4204
+ return Object.freeze({
4205
+ canExpand: () => false,
4206
+ isExpanded: () => false,
4207
+ root,
4208
+ setExpanded: () => void 0,
4209
+ render(projection) {
4210
+ const text2 = [projection.headline, projection.action, projection.meta].filter((value) => value.length > 0).join(" \xB7 ");
4211
+ copy.textContent = text2;
4212
+ root.setAttribute("aria-label", text2);
4213
+ },
4214
+ dispose() {
4215
+ }
4216
+ });
4217
+ }
3841
4218
  function createUnavailableDataFlowPanel(document, changesRoot, diagnosticsRoot) {
3842
4219
  changesRoot.append(diagnosticsRoot);
3843
4220
  return Object.freeze({
@@ -3851,10 +4228,33 @@ function createUnavailableDataFlowPanel(document, changesRoot, diagnosticsRoot)
3851
4228
  }
3852
4229
  function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto", dataFlowEnabled = false, externalAgentEnabled = false, framework = "vite", sessionId = "") {
3853
4230
  const localizer = createUiLocalizer(document, localePreference);
4231
+ const associatedWindow = document.defaultView;
4232
+ if (associatedWindow === null) {
4233
+ throw new Error("SpotPatch requires a document with an associated window.");
4234
+ }
4235
+ const runtimeWindow = associatedWindow;
4236
+ const floatingSurface = createFloatingSurfaceController(
4237
+ runtimeWindow,
4238
+ createFloatingSurfaceSession(runtimeWindow, sessionId),
4239
+ FLOATING_SURFACE_LAYOUT
4240
+ );
3854
4241
  let messages = localizer.messages();
4242
+ let currentStatus = "idle";
4243
+ let plannerVisible = false;
4244
+ let executionSuppressed = false;
4245
+ let executionProjection;
4246
+ let pendingAgentMotion;
4247
+ let successSettleKey;
4248
+ let settledSuccessKey;
4249
+ let successSettleTimer;
4250
+ let observedExecutionStartedAt;
3855
4251
  const host = document.createElement("spotpatch-root");
3856
4252
  host.setAttribute(UI_MARKER_ATTRIBUTE, "");
3857
4253
  const shadowRoot = host.attachShadow({ mode: "open" });
4254
+ const floatingSurfaceRoot = createMarkedElement(document, "div");
4255
+ floatingSurfaceRoot.className = "spotpatch-floating-surface";
4256
+ floatingSurfaceRoot.dataset.scene = "pill";
4257
+ floatingSurfaceRoot.dataset.tone = "neutral";
3858
4258
  const triggerButton = createButton(
3859
4259
  document,
3860
4260
  messages.trigger.select,
@@ -3862,6 +4262,10 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3862
4262
  );
3863
4263
  triggerButton.title = messages.trigger.title(shortcut);
3864
4264
  triggerButton.setAttribute("aria-pressed", "false");
4265
+ const motionExtension = getFloatingSurfaceMotionExtension();
4266
+ const motionExecutionIsland = motionExtension?.createExecutionIsland(document);
4267
+ const executionIslandView = motionExecutionIsland ?? createFallbackExecutionIsland(document);
4268
+ const executionIsland = executionIslandView.root;
3865
4269
  const highlight = createMarkedElement(document, "div");
3866
4270
  highlight.className = "spotpatch-highlight";
3867
4271
  highlight.hidden = true;
@@ -3875,16 +4279,13 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3875
4279
  dialog.className = "spotpatch-dialog";
3876
4280
  dialog.hidden = true;
3877
4281
  dialog.tabIndex = -1;
3878
- dialog.dataset.placement = "viewport";
3879
4282
  dialog.setAttribute("role", "dialog");
3880
4283
  dialog.setAttribute("aria-labelledby", "spotpatch-selection-title");
3881
- const anchor = createMarkedElement(document, "span");
3882
- anchor.className = "spotpatch-anchor";
3883
- anchor.setAttribute("aria-hidden", "true");
3884
4284
  const shell = createMarkedElement(document, "div");
3885
4285
  shell.className = "spotpatch-shell";
3886
4286
  const header = createMarkedElement(document, "header");
3887
4287
  header.className = "spotpatch-header";
4288
+ header.setAttribute("data-spotpatch-drag-handle", "");
3888
4289
  const brandRow = createMarkedElement(document, "div");
3889
4290
  brandRow.className = "spotpatch-brand-row";
3890
4291
  const brand = createMarkedElement(document, "div");
@@ -3905,8 +4306,9 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3905
4306
  repositoryLink.target = "_blank";
3906
4307
  repositoryLink.rel = "noopener noreferrer";
3907
4308
  const localeButton = createButton(document, "", "spotpatch-locale");
4309
+ const resetPositionButton = createButton(document, "\u2316", "spotpatch-reset-position");
3908
4310
  const closeButton = createButton(document, "\xD7", "spotpatch-close");
3909
- headerControls.append(repositoryLink, localeButton, closeButton);
4311
+ headerControls.append(repositoryLink, localeButton, resetPositionButton, closeButton);
3910
4312
  brandRow.append(brand, headerControls);
3911
4313
  const title = createMarkedElement(document, "h2");
3912
4314
  title.id = "spotpatch-selection-title";
@@ -3966,13 +4368,20 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3966
4368
  diagnostics.append(diagnosticsLabel, summary);
3967
4369
  const agentPanel = createAgentPanel(document, ai, localizer);
3968
4370
  const changesPanel = createMarkedElement(document, "div");
4371
+ function requestFloatingSurfaceLayout() {
4372
+ if (plannerVisible) {
4373
+ floatingSurface.requestReconcile();
4374
+ }
4375
+ }
3969
4376
  const externalHandoffPanel = externalAgentEnabled ? getExternalHandoffExtension()?.createPanel(
3970
4377
  document,
3971
4378
  framework,
3972
4379
  localizer.locale,
3973
4380
  sessionId,
3974
4381
  localizer.subscribe,
3975
- placeDialog
4382
+ requestFloatingSurfaceLayout,
4383
+ renderExternalDispatch,
4384
+ renderExternalControl
3976
4385
  ) : void 0;
3977
4386
  changesPanel.append(
3978
4387
  targetsPanel,
@@ -3985,7 +4394,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3985
4394
  localizer.locale,
3986
4395
  changesPanel,
3987
4396
  diagnostics,
3988
- placeDialog
4397
+ requestFloatingSurfaceLayout
3989
4398
  ) ?? createUnavailableDataFlowPanel(document, changesPanel, diagnostics);
3990
4399
  selectionPanel.append(dataFlowPanel.root);
3991
4400
  const previewPanel = createMarkedElement(document, "div");
@@ -4041,13 +4450,14 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4041
4450
  );
4042
4451
  actions.append(editorFeedback, secondaryActions, primaryActions);
4043
4452
  shell.append(header, body, actions);
4044
- dialog.append(anchor, shell);
4453
+ dialog.append(shell);
4045
4454
  const liveRegion = createMarkedElement(document, "div");
4046
4455
  liveRegion.className = "spotpatch-live";
4047
4456
  liveRegion.setAttribute("aria-live", "polite");
4048
4457
  liveRegion.setAttribute("aria-atomic", "true");
4049
4458
  const styles2 = [
4050
4459
  createStyles(document),
4460
+ ...motionExtension === void 0 ? [] : [motionExtension.createStyles(document)],
4051
4461
  dataFlowPanel.styles,
4052
4462
  ...externalHandoffPanel === void 0 ? [] : [externalHandoffPanel.styles]
4053
4463
  ];
@@ -4061,14 +4471,38 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4061
4471
  ...styles2,
4062
4472
  selectionHighlights,
4063
4473
  highlight,
4064
- dialog,
4065
- triggerButton,
4474
+ floatingSurfaceRoot,
4066
4475
  liveRegion
4067
4476
  );
4477
+ floatingSurfaceRoot.append(triggerButton, dialog, executionIsland);
4068
4478
  document.documentElement.append(host);
4069
- let currentRect;
4070
- let activeSelectionRect;
4071
- let currentStatus = "idle";
4479
+ floatingSurface.registerSurface(floatingSurfaceRoot);
4480
+ const motionController = motionExtension === void 0 || motionExecutionIsland === void 0 ? void 0 : motionExtension.createController(
4481
+ document,
4482
+ Object.freeze({
4483
+ execution: motionExecutionIsland.elements,
4484
+ pill: triggerButton,
4485
+ planner: dialog,
4486
+ surface: floatingSurfaceRoot
4487
+ }),
4488
+ floatingSurface.reconcile
4489
+ );
4490
+ const cancelMotionOnDrag = () => {
4491
+ motionController?.cancel();
4492
+ };
4493
+ floatingSurface.attachDraggable(triggerButton, floatingSurfaceRoot, {
4494
+ onDragStart: cancelMotionOnDrag,
4495
+ suppressClickOnDrag: true
4496
+ });
4497
+ floatingSurface.attachDraggable(header, floatingSurfaceRoot, {
4498
+ canStartDrag: (event) => !floatingSurface.isCompact() && !startsOnInteractiveControl(event),
4499
+ onDragStart: cancelMotionOnDrag
4500
+ });
4501
+ floatingSurface.attachDraggable(executionIsland, floatingSurfaceRoot, {
4502
+ onDragStart: cancelMotionOnDrag,
4503
+ suppressClickOnDrag: true
4504
+ });
4505
+ floatingSurface.reconcile();
4072
4506
  let currentCanOpenEditor = false;
4073
4507
  let currentCanPreview = false;
4074
4508
  let currentSummaryText = "";
@@ -4083,12 +4517,274 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4083
4517
  page: Object.freeze({ status: dataFlowEnabled ? "idle" : "disabled" }),
4084
4518
  observationCount: 0
4085
4519
  });
4520
+ function currentTargetSummary() {
4521
+ const target2 = currentTargets.find((candidate) => candidate.active);
4522
+ return target2 === void 0 ? Object.freeze({
4523
+ label: messages.context.selectedElement,
4524
+ source: ""
4525
+ }) : Object.freeze({ label: target2.label, source: target2.source });
4526
+ }
4527
+ function currentTargetContext() {
4528
+ const target2 = currentTargetSummary();
4529
+ return target2.source.length === 0 ? target2.label : `${target2.label} \xB7 ${target2.source}`;
4530
+ }
4531
+ function beginObservedExecution() {
4532
+ observedExecutionStartedAt = (/* @__PURE__ */ new Date()).toISOString();
4533
+ return observedExecutionStartedAt;
4534
+ }
4535
+ function observedExecutionStart() {
4536
+ return observedExecutionStartedAt ?? beginObservedExecution();
4537
+ }
4538
+ function clearSuccessSettle(resetKeys) {
4539
+ if (successSettleTimer !== void 0) {
4540
+ runtimeWindow.clearTimeout(successSettleTimer);
4541
+ successSettleTimer = void 0;
4542
+ }
4543
+ if (resetKeys) {
4544
+ successSettleKey = void 0;
4545
+ settledSuccessKey = void 0;
4546
+ }
4547
+ }
4548
+ function showSuccessUntilSettled(key) {
4549
+ if (settledSuccessKey === key) return false;
4550
+ if (successSettleKey === key) return true;
4551
+ clearSuccessSettle(false);
4552
+ successSettleKey = key;
4553
+ successSettleTimer = runtimeWindow.setTimeout(() => {
4554
+ successSettleTimer = void 0;
4555
+ if (!host.isConnected) return;
4556
+ settledSuccessKey = key;
4557
+ executionProjection = void 0;
4558
+ observedExecutionStartedAt = void 0;
4559
+ executionSuppressed = false;
4560
+ plannerVisible = false;
4561
+ renderFloatingSurfaceMotion();
4562
+ }, SUCCESS_SETTLE_MS);
4563
+ return true;
4564
+ }
4565
+ function externalAgentIdentity(kind) {
4566
+ return kind.startsWith("claude") ? messages.execution.claude : kind.startsWith("codex") ? messages.execution.codex : kind;
4567
+ }
4568
+ function projectAgentActivity(item) {
4569
+ return Object.freeze({
4570
+ ...item.detail === void 0 ? {} : { detail: item.detail },
4571
+ key: item.key,
4572
+ kind: item.kind,
4573
+ label: messages.execution.activityLane(item.kind, item.detail),
4574
+ state: item.state
4575
+ });
4576
+ }
4577
+ function motionActivity(key, kind, detail, state = "active") {
4578
+ return Object.freeze({
4579
+ ...detail === void 0 ? {} : { detail },
4580
+ key,
4581
+ kind,
4582
+ label: messages.execution.activityLane(kind, detail),
4583
+ state
4584
+ });
4585
+ }
4586
+ function renderFloatingSurfaceMotion() {
4587
+ const capturing = currentStatus === "inspecting";
4588
+ const pillActive = !plannerVisible || capturing;
4589
+ const projection = pillActive ? {
4590
+ scene: capturing ? "capturing" : "pill",
4591
+ tone: capturing ? "capturing" : "neutral",
4592
+ headline: triggerButton.textContent,
4593
+ action: "",
4594
+ meta: "",
4595
+ recentActivities: Object.freeze([])
4596
+ } : !executionSuppressed && executionProjection !== void 0 ? executionProjection : {
4597
+ scene: "planner",
4598
+ tone: "ready",
4599
+ headline: messages.dialog.editTitle,
4600
+ action: messages.dialog.editSubtitle,
4601
+ meta: messages.context.ready,
4602
+ recentActivities: Object.freeze([])
4603
+ };
4604
+ if (motionController !== void 0) {
4605
+ motionController.render(projection, () => {
4606
+ executionIslandView.render(projection);
4607
+ });
4608
+ return;
4609
+ }
4610
+ executionIslandView.render(projection);
4611
+ floatingSurfaceRoot.dataset.scene = projection.scene;
4612
+ floatingSurfaceRoot.dataset.tone = projection.tone;
4613
+ const plannerActive = projection.scene === "planner";
4614
+ triggerButton.hidden = !pillActive;
4615
+ triggerButton.inert = !pillActive;
4616
+ dialog.hidden = !plannerActive;
4617
+ dialog.inert = !plannerActive;
4618
+ dialog.setAttribute("aria-hidden", String(!plannerActive));
4619
+ executionIsland.hidden = pillActive || plannerActive;
4620
+ executionIsland.inert = pillActive || plannerActive;
4621
+ executionIsland.setAttribute("aria-hidden", String(pillActive || plannerActive));
4622
+ floatingSurface.reconcile();
4623
+ }
4624
+ function renderExternalDispatch(dispatch) {
4625
+ if (dispatch === null) {
4626
+ pendingAgentMotion = void 0;
4627
+ observedExecutionStartedAt = void 0;
4628
+ } else if (pendingAgentMotion !== void 0 && dispatch.phase !== "failed" && dispatch.phase !== "delivery-unknown") {
4629
+ startStagedAgentRequest();
4630
+ } else if (dispatch.phase === "failed" || dispatch.phase === "delivery-unknown") {
4631
+ pendingAgentMotion = void 0;
4632
+ }
4633
+ if (dispatch !== null && !executionSuppressed) {
4634
+ const failed = dispatch.phase === "failed" || dispatch.phase === "delivery-unknown";
4635
+ const completed = dispatch.phase === "completed";
4636
+ const startedAt = failed || completed ? void 0 : observedExecutionStart();
4637
+ if (failed || completed) observedExecutionStartedAt = void 0;
4638
+ const successKey = `dispatch:${String(dispatch.revision)}`;
4639
+ if (completed && !showSuccessUntilSettled(successKey)) {
4640
+ executionProjection = void 0;
4641
+ renderFloatingSurfaceMotion();
4642
+ return;
4643
+ }
4644
+ const identity = externalAgentIdentity(dispatch.adapterKind);
4645
+ const target2 = currentTargetSummary();
4646
+ const activityKind = dispatch.phase === "queued" || dispatch.phase === "dispatching" || dispatch.phase === "dispatched" ? "dispatch" : completed ? "sync" : "unknown";
4647
+ const activity = motionActivity(
4648
+ `dispatch:${String(dispatch.revision)}:${dispatch.phase}`,
4649
+ activityKind,
4650
+ dispatch.phase,
4651
+ failed ? "failure" : completed ? "success" : "active"
4652
+ );
4653
+ const scene = failed ? "failed" : completed ? "success" : dispatch.phase === "working" ? "running" : "handoff";
4654
+ executionProjection = {
4655
+ scene,
4656
+ tone: failed ? "danger" : completed ? "success" : "running",
4657
+ headline: completed ? messages.execution.completedTitle : failed ? messages.execution.failedTitle : scene === "running" ? messages.execution.runningTitle(target2.label) : messages.execution.dispatchingTitle(identity),
4658
+ action: completed ? messages.execution.resultReturned : target2.source,
4659
+ expandedHeadline: completed ? messages.execution.expandedCompletedTitle : failed ? messages.execution.failedTitle : scene === "running" ? messages.execution.expandedRunningTitle(identity) : messages.execution.dispatchingTitle(identity),
4660
+ expandedAction: completed ? messages.execution.resultReturned : currentTargetContext(),
4661
+ meta: failed ? messages.execution.failedStatus : completed ? messages.execution.completedStatus : scene === "running" ? messages.execution.runningStatus : messages.execution.dispatchingStatus,
4662
+ activity,
4663
+ recentActivities: Object.freeze([activity]),
4664
+ ...startedAt === void 0 ? {} : { startedAt }
4665
+ };
4666
+ } else if (dispatch === null) {
4667
+ executionProjection = void 0;
4668
+ }
4669
+ renderFloatingSurfaceMotion();
4670
+ }
4671
+ function renderExternalControl(status) {
4672
+ const task = status?.task;
4673
+ if (status === void 0 || task === void 0 || executionSuppressed) return;
4674
+ const phase = task.managedPhase;
4675
+ const failed = phase === "failed" || phase === "cleanup-warning";
4676
+ const completed = phase === "completed" || phase === "review-required";
4677
+ const cancelled = phase === "cancelled";
4678
+ if (failed || cancelled) {
4679
+ pendingAgentMotion = void 0;
4680
+ } else if (pendingAgentMotion !== void 0) {
4681
+ startStagedAgentRequest();
4682
+ }
4683
+ if (cancelled) {
4684
+ executionProjection = void 0;
4685
+ observedExecutionStartedAt = void 0;
4686
+ renderFloatingSurfaceMotion();
4687
+ return;
4688
+ }
4689
+ const startedAt = failed || completed ? void 0 : observedExecutionStart();
4690
+ if (failed || completed) observedExecutionStartedAt = void 0;
4691
+ if (phase === "completed" && !showSuccessUntilSettled(`managed:${String(task.revision)}`)) {
4692
+ executionProjection = void 0;
4693
+ renderFloatingSurfaceMotion();
4694
+ return;
4695
+ }
4696
+ const scene = failed ? "failed" : completed ? "success" : phase === "preparing" ? "handoff" : "running";
4697
+ const tone = failed ? "danger" : completed ? "success" : "running";
4698
+ const identity = messages.execution.codex;
4699
+ const target2 = currentTargetSummary();
4700
+ const activityKind = phase === "preparing" ? "prepare" : phase === "auditing" ? "audit" : phase === "validating" ? "check" : phase === "applying" ? "apply" : completed ? "sync" : "unknown";
4701
+ const latestCheck = task.checks.at(-1);
4702
+ const latestFile = task.files.at(-1);
4703
+ const activityDetail = phase === "validating" ? latestCheck?.id : phase === "auditing" || phase === "applying" ? latestFile?.path : void 0;
4704
+ const activity = motionActivity(
4705
+ `managed:${String(task.revision)}:${phase}:${activityDetail ?? ""}`,
4706
+ activityKind,
4707
+ activityDetail,
4708
+ failed ? "failure" : completed ? "success" : "active"
4709
+ );
4710
+ const recentActivities = Object.freeze([
4711
+ ...task.files.slice(-2).map(
4712
+ (file) => motionActivity(
4713
+ `managed-file:${String(task.revision)}:${file.path}`,
4714
+ "patch",
4715
+ file.path,
4716
+ "success"
4717
+ )
4718
+ ),
4719
+ ...task.checks.slice(-2).map(
4720
+ (check) => motionActivity(
4721
+ `managed-check:${String(task.revision)}:${check.id}`,
4722
+ "check",
4723
+ check.id,
4724
+ check.outcome === "passed" ? "success" : "failure"
4725
+ )
4726
+ ),
4727
+ activity
4728
+ ]);
4729
+ executionProjection = {
4730
+ scene,
4731
+ tone,
4732
+ headline: completed ? messages.execution.completedTitle : failed ? messages.execution.failedTitle : scene === "handoff" ? messages.execution.dispatchingTitle(identity) : phase === "validating" ? messages.execution.activityAction("check", activityDetail) : messages.execution.runningTitle(target2.label),
4733
+ action: completed ? task.files.length === 0 ? messages.execution.resultReturned : messages.execution.resultSummary(task.files.length) : target2.source,
4734
+ expandedHeadline: completed ? messages.execution.expandedCompletedTitle : failed ? messages.execution.failedTitle : scene === "handoff" ? messages.execution.dispatchingTitle(identity) : messages.execution.expandedRunningTitle(identity),
4735
+ expandedAction: completed ? messages.execution.resultReturned : currentTargetContext(),
4736
+ meta: failed ? messages.execution.failedStatus : completed ? messages.execution.completedStatus : phase === "validating" ? messages.execution.checkingStatus : scene === "handoff" ? messages.execution.dispatchingStatus : messages.execution.runningStatus,
4737
+ activity,
4738
+ recentActivities,
4739
+ ...startedAt === void 0 ? {} : { startedAt }
4740
+ };
4741
+ renderFloatingSurfaceMotion();
4742
+ }
4743
+ function beginAgentRequest(target2, agentCard) {
4744
+ if (!plannerVisible) {
4745
+ return;
4746
+ }
4747
+ clearSuccessSettle(true);
4748
+ const startedAt = beginObservedExecution();
4749
+ executionSuppressed = false;
4750
+ const activity = motionActivity(
4751
+ `dispatch-start:${currentTargetContext()}`,
4752
+ "dispatch",
4753
+ currentTargetContext()
4754
+ );
4755
+ executionProjection = {
4756
+ scene: "agent-charging",
4757
+ tone: "running",
4758
+ headline: messages.execution.receivingTitle,
4759
+ action: currentTargetContext(),
4760
+ expandedHeadline: messages.execution.receivingTitle,
4761
+ expandedAction: currentTargetContext(),
4762
+ meta: messages.execution.receivingStatus,
4763
+ activity,
4764
+ recentActivities: Object.freeze([activity]),
4765
+ startedAt
4766
+ };
4767
+ renderFloatingSurfaceMotion();
4768
+ motionController?.dispatch(target2, agentCard);
4769
+ }
4770
+ function stageAgentRequest(source2, target2) {
4771
+ if (!plannerVisible || source2.disabled) return;
4772
+ pendingAgentMotion = Object.freeze({ source: source2, target: target2 });
4773
+ }
4774
+ function startStagedAgentRequest() {
4775
+ const pending = pendingAgentMotion;
4776
+ pendingAgentMotion = void 0;
4777
+ if (pending === void 0 || !pending.source.isConnected || !pending.target.isConnected) {
4778
+ return;
4779
+ }
4780
+ beginAgentRequest(pending.source, pending.target);
4781
+ }
4086
4782
  function renderEditorStatus(state) {
4087
4783
  currentEditorFeedbackState = state;
4088
4784
  editorFeedback.dataset.state = state;
4089
4785
  editorFeedback.hidden = state === "idle";
4090
4786
  editorFeedback.textContent = state === "opening" ? messages.announcements.editorOpening : state === "success" ? messages.announcements.editorOpened : state === "error" ? messages.announcements.editorFailed : "";
4091
- placeDialog();
4787
+ requestFloatingSurfaceLayout();
4092
4788
  }
4093
4789
  function statusText(target2) {
4094
4790
  if (target2.status === "ready") {
@@ -4223,6 +4919,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4223
4919
  replacement?.setSelectionRange(selectionStart, selectionEnd);
4224
4920
  }
4225
4921
  }
4922
+ requestFloatingSurfaceLayout();
4226
4923
  }
4227
4924
  function updateTargetInstruction(targetId, instruction) {
4228
4925
  currentTargets = currentTargets.map(
@@ -4271,8 +4968,6 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4271
4968
  }
4272
4969
  function showSelectionHighlights(targets) {
4273
4970
  selectionHighlights.replaceChildren();
4274
- activeSelectionRect = targets.find((target2) => target2.active)?.rect;
4275
- currentRect = activeSelectionRect;
4276
4971
  for (const [index, target2] of targets.entries()) {
4277
4972
  const box = createMarkedElement(document, "div");
4278
4973
  box.className = "spotpatch-selection-highlight";
@@ -4286,31 +4981,6 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4286
4981
  box.append(label);
4287
4982
  selectionHighlights.append(box);
4288
4983
  }
4289
- placeDialog();
4290
- }
4291
- function placeDialog() {
4292
- if (dialog.hidden) {
4293
- return;
4294
- }
4295
- const view = document.defaultView;
4296
- const viewportWidth = view?.innerWidth ?? document.documentElement.clientWidth;
4297
- const viewportHeight = view?.innerHeight ?? document.documentElement.clientHeight;
4298
- const measured = dialog.getBoundingClientRect();
4299
- const status = currentStatus === "previewing" ? "previewing" : "selected";
4300
- const dialogWidth = measured.width > 0 ? measured.width : Math.min(DIALOG_MAX_WIDTH, viewportWidth - 32);
4301
- const dialogHeight = measured.height > 0 ? measured.height : Math.min(DIALOG_FALLBACK_HEIGHT[status], viewportHeight - 32);
4302
- const placement = calculateDialogPlacement({
4303
- dialogWidth,
4304
- dialogHeight,
4305
- viewportWidth,
4306
- viewportHeight,
4307
- ...currentRect === void 0 ? {} : { target: currentRect }
4308
- });
4309
- dialog.style.left = `${String(placement.left)}px`;
4310
- dialog.style.top = `${String(placement.top)}px`;
4311
- dialog.style.setProperty("--spotpatch-anchor-x", `${String(placement.anchorX)}px`);
4312
- dialog.style.setProperty("--spotpatch-anchor-y", `${String(placement.anchorY)}px`);
4313
- dialog.dataset.placement = placement.mode;
4314
4984
  }
4315
4985
  function updateContextOverview(summaryText) {
4316
4986
  const summaryMessages = messages.summary;
@@ -4342,13 +5012,12 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4342
5012
  agentPanel.setContextReady(canPreview);
4343
5013
  externalHandoffPanel?.setContextReady(canPreview);
4344
5014
  updateContextOverview(summaryText);
4345
- placeDialog();
5015
+ requestFloatingSurfaceLayout();
4346
5016
  }
4347
5017
  function renderPanelStatus(status) {
4348
5018
  currentStatus = status;
4349
5019
  const selected = status === "selected";
4350
5020
  const previewing = status === "previewing";
4351
- triggerButton.hidden = selected || previewing;
4352
5021
  selectionPanel.hidden = !selected;
4353
5022
  previewPanel.hidden = !previewing;
4354
5023
  reselectButton.hidden = !selected;
@@ -4362,7 +5031,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4362
5031
  backButton.hidden = !previewing;
4363
5032
  title.textContent = previewing ? messages.dialog.previewTitle : messages.dialog.editTitle;
4364
5033
  subtitle.textContent = previewing ? messages.dialog.previewSubtitle : messages.dialog.editSubtitle;
4365
- placeDialog();
5034
+ renderFloatingSurfaceMotion();
4366
5035
  }
4367
5036
  function applyMessages() {
4368
5037
  messages = localizer.messages();
@@ -4374,8 +5043,14 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4374
5043
  localeButton.textContent = messages.alternateLocaleName;
4375
5044
  localeButton.title = messages.switchLocale;
4376
5045
  localeButton.setAttribute("aria-label", messages.switchLocale);
5046
+ resetPositionButton.title = messages.floatingSurface.resetPosition;
5047
+ resetPositionButton.setAttribute(
5048
+ "aria-label",
5049
+ messages.floatingSurface.resetPosition
5050
+ );
4377
5051
  closeButton.setAttribute("aria-label", messages.dialog.close);
4378
5052
  closeButton.title = messages.dialog.close;
5053
+ header.title = messages.floatingSurface.dragHandle;
4379
5054
  targetsPanel.setAttribute("aria-label", messages.targets.ariaLabel);
4380
5055
  targetsTitle.textContent = messages.targets.title;
4381
5056
  diagnosticsTitle.textContent = messages.diagnostics.title;
@@ -4411,8 +5086,58 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4411
5086
  contextState.textContent = messages.context.collecting;
4412
5087
  }
4413
5088
  }
4414
- diagnostics.addEventListener("toggle", placeDialog);
5089
+ function announce(message) {
5090
+ liveRegion.textContent = "";
5091
+ liveRegion.textContent = message;
5092
+ }
5093
+ function resetFloatingSurfacePosition() {
5094
+ floatingSurface.reset();
5095
+ announce(messages.floatingSurface.positionReset);
5096
+ }
5097
+ diagnostics.addEventListener("toggle", requestFloatingSurfaceLayout);
4415
5098
  localeButton.addEventListener("click", localizer.toggle);
5099
+ resetPositionButton.addEventListener("click", resetFloatingSurfacePosition);
5100
+ const onAgentRun = () => {
5101
+ stageAgentRequest(agentPanel.runButton, agentPanel.root);
5102
+ };
5103
+ const onExternalSend = () => {
5104
+ if (externalHandoffPanel !== void 0) {
5105
+ stageAgentRequest(externalHandoffPanel.sendButton, externalHandoffPanel.root);
5106
+ }
5107
+ };
5108
+ const onExecutionOpen = () => {
5109
+ if (executionIslandView.canExpand() && !executionIslandView.isExpanded()) {
5110
+ if (motionController === void 0) {
5111
+ executionIslandView.setExpanded(true);
5112
+ floatingSurface.reconcile();
5113
+ } else {
5114
+ motionController.updateLayout(() => {
5115
+ executionIslandView.setExpanded(true);
5116
+ });
5117
+ }
5118
+ return;
5119
+ }
5120
+ clearSuccessSettle(false);
5121
+ executionSuppressed = true;
5122
+ renderFloatingSurfaceMotion();
5123
+ };
5124
+ const onExecutionKeyDown = (event) => {
5125
+ if (event.key !== "Escape" || !executionIslandView.isExpanded()) return;
5126
+ event.preventDefault();
5127
+ event.stopPropagation();
5128
+ if (motionController === void 0) {
5129
+ executionIslandView.setExpanded(false);
5130
+ floatingSurface.reconcile();
5131
+ } else {
5132
+ motionController.updateLayout(() => {
5133
+ executionIslandView.setExpanded(false);
5134
+ });
5135
+ }
5136
+ };
5137
+ agentPanel.runButton.addEventListener("click", onAgentRun);
5138
+ externalHandoffPanel?.sendButton.addEventListener("click", onExternalSend);
5139
+ executionIsland.addEventListener("click", onExecutionOpen);
5140
+ executionIsland.addEventListener("keydown", onExecutionKeyDown);
4416
5141
  const unsubscribeLocale = localizer.subscribe(applyMessages);
4417
5142
  applyMessages();
4418
5143
  return Object.freeze({
@@ -4442,6 +5167,11 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4442
5167
  ...externalHandoffPanel === void 0 ? {} : { externalHandoffPanel },
4443
5168
  renderStatus(status) {
4444
5169
  const inspecting = status === "inspecting";
5170
+ if (status === "idle" || inspecting) {
5171
+ plannerVisible = false;
5172
+ } else {
5173
+ plannerVisible = true;
5174
+ }
4445
5175
  triggerButton.setAttribute("aria-pressed", String(inspecting));
4446
5176
  triggerButton.textContent = inspecting ? messages.trigger.stop : messages.trigger.select;
4447
5177
  renderPanelStatus(status);
@@ -4450,36 +5180,28 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4450
5180
  renderDataFlow(state) {
4451
5181
  currentDataFlowState = state;
4452
5182
  dataFlowPanel.render(state);
4453
- placeDialog();
5183
+ requestFloatingSurfaceLayout();
4454
5184
  },
4455
5185
  showHighlight(rect, label) {
4456
- currentRect = rect;
4457
5186
  highlight.hidden = false;
4458
5187
  highlight.style.transform = `translate(${String(rect.x)}px, ${String(rect.y)}px)`;
4459
5188
  highlight.style.width = `${String(rect.width)}px`;
4460
5189
  highlight.style.height = `${String(rect.height)}px`;
4461
5190
  highlightLabel.textContent = label;
4462
5191
  targetLabel.textContent = label;
4463
- placeDialog();
4464
5192
  },
4465
5193
  hideHighlight() {
4466
- currentRect = activeSelectionRect;
4467
5194
  highlight.hidden = true;
4468
5195
  highlightLabel.textContent = "";
4469
- placeDialog();
4470
5196
  },
4471
5197
  showSelectionHighlights,
4472
5198
  hideSelectionHighlights() {
4473
5199
  selectionHighlights.replaceChildren();
4474
- activeSelectionRect = void 0;
4475
- currentRect = void 0;
4476
- placeDialog();
4477
5200
  },
4478
5201
  showSelection(summaryText, canOpenEditor, canPreview) {
4479
5202
  updateSelection(summaryText, canOpenEditor, canPreview);
4480
- triggerButton.hidden = true;
4481
- dialog.hidden = false;
4482
- placeDialog();
5203
+ plannerVisible = true;
5204
+ renderPanelStatus(currentStatus === "previewing" ? "previewing" : "selected");
4483
5205
  },
4484
5206
  updateSelection,
4485
5207
  renderTargets,
@@ -4491,8 +5213,9 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4491
5213
  externalHandoffPanel?.setContextReady(enabled);
4492
5214
  },
4493
5215
  hideSelection() {
4494
- dialog.hidden = true;
4495
- triggerButton.hidden = false;
5216
+ plannerVisible = false;
5217
+ executionSuppressed = false;
5218
+ executionProjection = void 0;
4496
5219
  targetList.replaceChildren();
4497
5220
  currentTargets = [];
4498
5221
  currentMaximum = 0;
@@ -4518,14 +5241,17 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4518
5241
  agentPanel.setEditingEnabled(true);
4519
5242
  agentPanel.resetJob();
4520
5243
  dataFlowPanel.resetView();
5244
+ renderFloatingSurfaceMotion();
4521
5245
  },
4522
5246
  hideSelectionTemporarily() {
4523
- dialog.hidden = true;
4524
- triggerButton.hidden = false;
5247
+ plannerVisible = false;
5248
+ executionSuppressed = false;
5249
+ executionProjection = void 0;
5250
+ renderFloatingSurfaceMotion();
4525
5251
  },
4526
5252
  showPreview(prompt) {
4527
5253
  promptOutput.textContent = prompt;
4528
- placeDialog();
5254
+ requestFloatingSurfaceLayout();
4529
5255
  },
4530
5256
  readAgentSelection() {
4531
5257
  return agentPanel.readSelection();
@@ -4549,25 +5275,86 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4549
5275
  previewButton.disabled = !enabled || !currentCanPreview;
4550
5276
  externalHandoffPanel?.setContextReady(enabled && currentCanPreview);
4551
5277
  agentPanel.setEditingEnabled(enabled);
4552
- placeDialog();
5278
+ requestFloatingSurfaceLayout();
4553
5279
  },
4554
5280
  renderAgentCapability(state, message, capabilitySnapshot, errorCode) {
4555
5281
  agentPanel.renderCapability(state, message, capabilitySnapshot, errorCode);
5282
+ if (state === "error") {
5283
+ pendingAgentMotion = void 0;
5284
+ renderFloatingSurfaceMotion();
5285
+ }
4556
5286
  const agentReady = state === "ready" && capabilitySnapshot?.state === "agent-ready";
4557
5287
  previewButton.classList.toggle("spotpatch-primary", !agentReady);
4558
- placeDialog();
5288
+ requestFloatingSurfaceLayout();
4559
5289
  },
4560
5290
  renderAgentWorkspaceHealth(state, snapshot, errorCode) {
4561
5291
  agentPanel.renderWorkspaceHealth(state, snapshot, errorCode);
4562
- placeDialog();
5292
+ if (state === "blocked") {
5293
+ pendingAgentMotion = void 0;
5294
+ renderFloatingSurfaceMotion();
5295
+ }
5296
+ requestFloatingSurfaceLayout();
4563
5297
  },
4564
5298
  renderAgentJob(snapshot, result, activities, errorCode) {
4565
5299
  agentPanel.renderJob(snapshot, result, activities, errorCode);
4566
- placeDialog();
5300
+ if (pendingAgentMotion !== void 0 && snapshot.status !== "failed" && snapshot.status !== "cancelled") {
5301
+ startStagedAgentRequest();
5302
+ }
5303
+ if (snapshot.status === "failed" || snapshot.status === "cancelled") {
5304
+ pendingAgentMotion = void 0;
5305
+ }
5306
+ const successful = snapshot.status === "awaiting-review" || snapshot.status === "applied" || snapshot.status === "completed" || snapshot.status === "reverted";
5307
+ const failed = snapshot.status === "failed";
5308
+ const cancelled = snapshot.status === "cancelled";
5309
+ const terminalSuccess = snapshot.status === "applied" || snapshot.status === "completed" || snapshot.status === "reverted";
5310
+ const scene = successful ? "success" : failed ? "failed" : snapshot.status === "queued" || snapshot.status === "preparing" ? "handoff" : "running";
5311
+ if (!executionSuppressed) {
5312
+ if (terminalSuccess && !showSuccessUntilSettled(`job:${snapshot.jobId}:${snapshot.status}`)) {
5313
+ executionProjection = void 0;
5314
+ renderFloatingSurfaceMotion();
5315
+ requestFloatingSurfaceLayout();
5316
+ return;
5317
+ }
5318
+ const identity = snapshot.providerLabel;
5319
+ const target2 = currentTargetSummary();
5320
+ const projectedActivities = Object.freeze(activities.map(projectAgentActivity));
5321
+ const latestActivity = activities.at(-1);
5322
+ const phaseKind = snapshot.status === "queued" || snapshot.status === "preparing" ? "prepare" : snapshot.status === "validating" ? "check" : snapshot.status === "applying" || snapshot.status === "reverting" ? "apply" : snapshot.status === "awaiting-review" || successful ? "sync" : "unknown";
5323
+ const phaseActivity = motionActivity(
5324
+ `job-phase:${snapshot.jobId}:${snapshot.status}:${snapshot.updatedAt}`,
5325
+ phaseKind,
5326
+ void 0,
5327
+ successful ? "success" : failed ? "failure" : "active"
5328
+ );
5329
+ const activity = snapshot.status === "running" && latestActivity !== void 0 ? projectAgentActivity(latestActivity) : phaseActivity;
5330
+ executionProjection = cancelled ? void 0 : {
5331
+ scene,
5332
+ tone: successful ? "success" : failed ? "danger" : "running",
5333
+ headline: successful ? messages.execution.completedTitle : failed ? messages.execution.failedTitle : scene === "handoff" ? messages.execution.dispatchingTitle(identity) : snapshot.status === "validating" ? messages.execution.activityAction(
5334
+ "check",
5335
+ latestActivity?.detail
5336
+ ) : snapshot.status === "applying" || snapshot.status === "reverting" ? messages.execution.activityAction(phaseKind) : messages.execution.runningTitle(target2.label),
5337
+ action: successful ? result === void 0 || result.files.length === 0 ? messages.execution.resultReturned : messages.execution.resultSummary(result.files.length) : latestActivity?.detail ?? target2.source,
5338
+ expandedHeadline: successful ? messages.execution.expandedCompletedTitle : failed ? messages.execution.failedTitle : scene === "handoff" ? messages.execution.dispatchingTitle(identity) : messages.execution.expandedRunningTitle(identity),
5339
+ expandedAction: successful ? result === void 0 || result.files.length === 0 ? messages.execution.resultReturned : messages.execution.resultSummary(result.files.length) : currentTargetContext(),
5340
+ meta: successful ? messages.execution.completedStatus : failed ? messages.execution.failedStatus : snapshot.status === "validating" ? messages.execution.checkingStatus : scene === "handoff" ? messages.execution.dispatchingStatus : messages.execution.runningStatus,
5341
+ activity,
5342
+ recentActivities: projectedActivities.length === 0 ? Object.freeze([phaseActivity]) : projectedActivities,
5343
+ startedAt: snapshot.createdAt
5344
+ };
5345
+ }
5346
+ renderFloatingSurfaceMotion();
5347
+ requestFloatingSurfaceLayout();
4567
5348
  },
4568
5349
  resetAgentJob() {
4569
5350
  agentPanel.resetJob();
4570
- placeDialog();
5351
+ observedExecutionStartedAt = void 0;
5352
+ if (executionProjection !== void 0) {
5353
+ executionProjection = void 0;
5354
+ executionSuppressed = false;
5355
+ renderFloatingSurfaceMotion();
5356
+ }
5357
+ requestFloatingSurfaceLayout();
4571
5358
  },
4572
5359
  focusTargetInstruction(targetId) {
4573
5360
  instructionInput(targetId)?.focus({ preventScroll: true });
@@ -4575,21 +5362,27 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4575
5362
  focusPrompt() {
4576
5363
  promptOutput.focus({ preventScroll: true });
4577
5364
  },
4578
- announce(message) {
4579
- liveRegion.textContent = "";
4580
- liveRegion.textContent = message;
4581
- },
5365
+ announce,
4582
5366
  locale: localizer.locale,
4583
5367
  messages: localizer.messages,
4584
5368
  agentWorkspaceConsentGranted: agentPanel.workspaceConsentGranted,
4585
5369
  subscribeLocale: localizer.subscribe,
4586
5370
  dispose() {
4587
- diagnostics.removeEventListener("toggle", placeDialog);
5371
+ diagnostics.removeEventListener("toggle", requestFloatingSurfaceLayout);
4588
5372
  localeButton.removeEventListener("click", localizer.toggle);
5373
+ resetPositionButton.removeEventListener("click", resetFloatingSurfacePosition);
5374
+ agentPanel.runButton.removeEventListener("click", onAgentRun);
5375
+ externalHandoffPanel?.sendButton.removeEventListener("click", onExternalSend);
5376
+ executionIsland.removeEventListener("click", onExecutionOpen);
5377
+ executionIsland.removeEventListener("keydown", onExecutionKeyDown);
4589
5378
  unsubscribeLocale();
4590
5379
  dataFlowPanel.dispose();
4591
5380
  externalHandoffPanel?.dispose();
4592
5381
  agentPanel.dispose();
5382
+ motionController?.dispose();
5383
+ executionIslandView.dispose();
5384
+ clearSuccessSettle(true);
5385
+ floatingSurface.dispose();
4593
5386
  host.remove();
4594
5387
  }
4595
5388
  });
@@ -4658,17 +5451,33 @@ import {
4658
5451
  function capabilityKey(providerProfileId, modelProfileId) {
4659
5452
  return `${providerProfileId}:${modelProfileId}`;
4660
5453
  }
5454
+ var TOOL_ACTIVITY_KIND = Object.freeze({
5455
+ list_files: "discover",
5456
+ search_text: "search",
5457
+ read_file: "read",
5458
+ replace_text: "patch",
5459
+ apply_patch: "patch",
5460
+ run_check: "check"
5461
+ });
5462
+ function toolActivityKind(toolName) {
5463
+ return TOOL_ACTIVITY_KIND[toolName] ?? "unknown";
5464
+ }
4661
5465
  function activityFromEvent(event) {
4662
5466
  if (event.type === "tool") {
5467
+ const detail = event.data.relativePath ?? event.data.checkLabel;
4663
5468
  return Object.freeze({
4664
5469
  key: `tool:${String(event.data.turn)}:${event.data.toolCallId}`,
4665
- label: `${event.data.toolName} \xB7 ${event.data.state}`,
5470
+ kind: toolActivityKind(event.data.toolName),
5471
+ ...detail === void 0 ? {} : { detail },
5472
+ label: `${event.data.toolName}${detail === void 0 ? "" : ` \xB7 ${detail}`} \xB7 ${event.data.state}`,
4666
5473
  state: event.data.state === "started" ? "active" : event.data.state === "succeeded" ? "success" : "failure"
4667
5474
  });
4668
5475
  }
4669
5476
  if (event.type === "check") {
4670
5477
  return Object.freeze({
4671
5478
  key: `check:${event.data.result.checkId}:${String(event.sequence)}`,
5479
+ kind: "check",
5480
+ detail: event.data.result.label,
4672
5481
  label: `${event.data.result.label} \xB7 ${event.data.result.status}`,
4673
5482
  state: event.data.result.status === "passed" ? "success" : event.data.result.status === "failed" || event.data.result.status === "timed-out" ? "failure" : "info"
4674
5483
  });