@spotpatch/runtime 1.9.0 → 1.10.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/dist/index.js CHANGED
@@ -5,13 +5,18 @@ import {
5
5
  mergeComponentDataFlowReport,
6
6
  mergePageDataFlowReport
7
7
  } from "./chunk-QY5T4DPA.js";
8
+ import {
9
+ getDataFlowExtension
10
+ } from "./chunk-NII5OBAN.js";
11
+ import {
12
+ getExternalHandoffExtension
13
+ } from "./chunk-XBD55BCF.js";
8
14
  import {
9
15
  UI_MARKER_ATTRIBUTE,
10
16
  UI_Z_INDEX,
11
17
  createButton,
12
- createMarkedElement,
13
- getDataFlowExtension
14
- } from "./chunk-AXKYJRAM.js";
18
+ createMarkedElement
19
+ } from "./chunk-7ES63LA7.js";
15
20
 
16
21
  // src/controller/runtime-controller.ts
17
22
  import { createReact18Adapter } from "@spotpatch/react-adapter";
@@ -2593,6 +2598,8 @@ var STATUS_ZH = Object.freeze({
2593
2598
  reverted: "\u5DF2\u64A4\u9500",
2594
2599
  failed: "\u5931\u8D25"
2595
2600
  });
2601
+ var EXTERNAL_HANDOFF_ERROR_EN = "The external Agent handoff request failed.";
2602
+ var EXTERNAL_HANDOFF_ERROR_ZH = "\u5916\u90E8 Agent \u4EA4\u63A5\u8BF7\u6C42\u5931\u8D25\u3002";
2596
2603
  var ERROR_MESSAGES_EN = Object.freeze({
2597
2604
  [ERROR_CODES2.INVALID_REQUEST]: "The Agent request was rejected as invalid.",
2598
2605
  [ERROR_CODES2.INVALID_TOKEN]: "The local SpotPatch session expired.",
@@ -2614,6 +2621,24 @@ var ERROR_MESSAGES_EN = Object.freeze({
2614
2621
  [ERROR_CODES2.AGENT_BUSY]: "Another write Agent job is still active.",
2615
2622
  [ERROR_CODES2.AGENT_LIMIT_EXCEEDED]: "The Agent stopped at a configured time, turn, output, or size limit.",
2616
2623
  [ERROR_CODES2.AGENT_CANCELLED]: "The Agent job was cancelled.",
2624
+ [ERROR_CODES2.EXTERNAL_HANDOFF_DISABLED]: EXTERNAL_HANDOFF_ERROR_EN,
2625
+ [ERROR_CODES2.EXTERNAL_HANDOFF_UNAVAILABLE]: EXTERNAL_HANDOFF_ERROR_EN,
2626
+ [ERROR_CODES2.HANDOFF_VALIDATION_FAILED]: EXTERNAL_HANDOFF_ERROR_EN,
2627
+ [ERROR_CODES2.HANDOFF_SOURCE_STALE]: EXTERNAL_HANDOFF_ERROR_EN,
2628
+ [ERROR_CODES2.HANDOFF_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_EN,
2629
+ [ERROR_CODES2.HANDOFF_EXPIRED]: EXTERNAL_HANDOFF_ERROR_EN,
2630
+ [ERROR_CODES2.HANDOFF_CURSOR_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2631
+ [ERROR_CODES2.HANDOFF_RESPONSE_TOO_LARGE]: EXTERNAL_HANDOFF_ERROR_EN,
2632
+ [ERROR_CODES2.BRIDGE_UNAUTHORIZED]: EXTERNAL_HANDOFF_ERROR_EN,
2633
+ [ERROR_CODES2.BRIDGE_PROTOCOL_MISMATCH]: EXTERNAL_HANDOFF_ERROR_EN,
2634
+ [ERROR_CODES2.BRIDGE_BUSY]: EXTERNAL_HANDOFF_ERROR_EN,
2635
+ [ERROR_CODES2.EXTERNAL_AGENT_BUSY]: EXTERNAL_HANDOFF_ERROR_EN,
2636
+ [ERROR_CODES2.ACTIVE_ADAPTER_CONFLICT]: EXTERNAL_HANDOFF_ERROR_EN,
2637
+ [ERROR_CODES2.ACTIVE_ADAPTER_LEASE_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2638
+ [ERROR_CODES2.ACTIVE_DISPATCH_INVALID]: EXTERNAL_HANDOFF_ERROR_EN,
2639
+ [ERROR_CODES2.SESSION_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_EN,
2640
+ [ERROR_CODES2.SESSION_AMBIGUOUS]: EXTERNAL_HANDOFF_ERROR_EN,
2641
+ [ERROR_CODES2.SESSION_CLOSED]: EXTERNAL_HANDOFF_ERROR_EN,
2617
2642
  [ERROR_CODES2.WORKTREE_DIRTY]: "Confirm inclusion of local changes before running AI.",
2618
2643
  [ERROR_CODES2.WORKTREE_NOT_REPOSITORY]: "Vite root must be an initialized Git repository root.",
2619
2644
  [ERROR_CODES2.WORKTREE_OPERATION_IN_PROGRESS]: "Finish the active merge, rebase, cherry-pick, or revert.",
@@ -2652,6 +2677,24 @@ var ERROR_MESSAGES_ZH = Object.freeze({
2652
2677
  [ERROR_CODES2.AGENT_BUSY]: "\u5F53\u524D\u9879\u76EE\u5DF2\u6709\u4E00\u4E2A\u5199\u5165\u4EFB\u52A1\u6B63\u5728\u8FD0\u884C\u3002",
2653
2678
  [ERROR_CODES2.AGENT_LIMIT_EXCEEDED]: "Agent \u8FBE\u5230\u65F6\u95F4\u3001\u8F6E\u6B21\u3001\u8F93\u51FA\u6216\u53D8\u66F4\u89C4\u6A21\u9650\u5236\u3002",
2654
2679
  [ERROR_CODES2.AGENT_CANCELLED]: "Agent \u4EFB\u52A1\u5DF2\u53D6\u6D88\u3002",
2680
+ [ERROR_CODES2.EXTERNAL_HANDOFF_DISABLED]: EXTERNAL_HANDOFF_ERROR_ZH,
2681
+ [ERROR_CODES2.EXTERNAL_HANDOFF_UNAVAILABLE]: EXTERNAL_HANDOFF_ERROR_ZH,
2682
+ [ERROR_CODES2.HANDOFF_VALIDATION_FAILED]: EXTERNAL_HANDOFF_ERROR_ZH,
2683
+ [ERROR_CODES2.HANDOFF_SOURCE_STALE]: EXTERNAL_HANDOFF_ERROR_ZH,
2684
+ [ERROR_CODES2.HANDOFF_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_ZH,
2685
+ [ERROR_CODES2.HANDOFF_EXPIRED]: EXTERNAL_HANDOFF_ERROR_ZH,
2686
+ [ERROR_CODES2.HANDOFF_CURSOR_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2687
+ [ERROR_CODES2.HANDOFF_RESPONSE_TOO_LARGE]: EXTERNAL_HANDOFF_ERROR_ZH,
2688
+ [ERROR_CODES2.BRIDGE_UNAUTHORIZED]: EXTERNAL_HANDOFF_ERROR_ZH,
2689
+ [ERROR_CODES2.BRIDGE_PROTOCOL_MISMATCH]: EXTERNAL_HANDOFF_ERROR_ZH,
2690
+ [ERROR_CODES2.BRIDGE_BUSY]: EXTERNAL_HANDOFF_ERROR_ZH,
2691
+ [ERROR_CODES2.EXTERNAL_AGENT_BUSY]: EXTERNAL_HANDOFF_ERROR_ZH,
2692
+ [ERROR_CODES2.ACTIVE_ADAPTER_CONFLICT]: EXTERNAL_HANDOFF_ERROR_ZH,
2693
+ [ERROR_CODES2.ACTIVE_ADAPTER_LEASE_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2694
+ [ERROR_CODES2.ACTIVE_DISPATCH_INVALID]: EXTERNAL_HANDOFF_ERROR_ZH,
2695
+ [ERROR_CODES2.SESSION_NOT_FOUND]: EXTERNAL_HANDOFF_ERROR_ZH,
2696
+ [ERROR_CODES2.SESSION_AMBIGUOUS]: EXTERNAL_HANDOFF_ERROR_ZH,
2697
+ [ERROR_CODES2.SESSION_CLOSED]: EXTERNAL_HANDOFF_ERROR_ZH,
2655
2698
  [ERROR_CODES2.WORKTREE_DIRTY]: "\u8FD0\u884C AI \u524D\uFF0C\u8BF7\u660E\u786E\u540C\u610F\u5C06\u5F53\u524D\u672C\u5730\u4FEE\u6539\u7EB3\u5165\u9694\u79BB\u57FA\u7EBF\u3002",
2656
2699
  [ERROR_CODES2.WORKTREE_NOT_REPOSITORY]: "Vite \u6839\u76EE\u5F55\u4E0D\u662F\u5DF2\u521D\u59CB\u5316 Git \u4ED3\u5E93\u7684\u9876\u5C42\u76EE\u5F55\u3002",
2657
2700
  [ERROR_CODES2.WORKTREE_OPERATION_IN_PROGRESS]: "\u8BF7\u5148\u5B8C\u6210\u5F53\u524D merge\u3001rebase\u3001cherry-pick \u6216 revert\uFF0C\u518D\u8FD0\u884C AI\u3002",
@@ -3076,6 +3119,15 @@ var DIALOG_FALLBACK_HEIGHT = Object.freeze({
3076
3119
  previewing: 560,
3077
3120
  selected: DIALOG_MAX_HEIGHT
3078
3121
  });
3122
+ function resolveStyleNonce(document) {
3123
+ const nonces = new Set(
3124
+ [...document.querySelectorAll("script[nonce]")].map((script) => script.nonce?.trim() ?? "").filter(Boolean)
3125
+ );
3126
+ if (nonces.size !== 1) {
3127
+ return void 0;
3128
+ }
3129
+ return nonces.values().next().value;
3130
+ }
3079
3131
  function createStyles(document) {
3080
3132
  const style = document.createElement("style");
3081
3133
  style.textContent = `
@@ -3797,7 +3849,7 @@ function createUnavailableDataFlowPanel(document, changesRoot, diagnosticsRoot)
3797
3849
  resetView: () => void 0
3798
3850
  });
3799
3851
  }
3800
- function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto", dataFlowEnabled = false) {
3852
+ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto", dataFlowEnabled = false, externalAgentEnabled = false, framework = "vite", sessionId = "") {
3801
3853
  const localizer = createUiLocalizer(document, localePreference);
3802
3854
  let messages = localizer.messages();
3803
3855
  const host = document.createElement("spotpatch-root");
@@ -3914,7 +3966,19 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3914
3966
  diagnostics.append(diagnosticsLabel, summary);
3915
3967
  const agentPanel = createAgentPanel(document, ai, localizer);
3916
3968
  const changesPanel = createMarkedElement(document, "div");
3917
- changesPanel.append(targetsPanel, agentPanel.root);
3969
+ const externalHandoffPanel = externalAgentEnabled ? getExternalHandoffExtension()?.createPanel(
3970
+ document,
3971
+ framework,
3972
+ localizer.locale,
3973
+ sessionId,
3974
+ localizer.subscribe,
3975
+ placeDialog
3976
+ ) : void 0;
3977
+ changesPanel.append(
3978
+ targetsPanel,
3979
+ agentPanel.root,
3980
+ ...externalHandoffPanel === void 0 ? [] : [externalHandoffPanel.root]
3981
+ );
3918
3982
  const dataFlowPanel = getDataFlowExtension()?.createPanel(
3919
3983
  document,
3920
3984
  dataFlowEnabled,
@@ -3966,6 +4030,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3966
4030
  agentPanel.testButton,
3967
4031
  addTargetButton,
3968
4032
  agentPanel.runButton,
4033
+ ...externalHandoffPanel === void 0 ? [] : [externalHandoffPanel.sendButton],
3969
4034
  previewButton,
3970
4035
  agentPanel.cancelButton,
3971
4036
  agentPanel.applyButton,
@@ -3981,9 +4046,19 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
3981
4046
  liveRegion.className = "spotpatch-live";
3982
4047
  liveRegion.setAttribute("aria-live", "polite");
3983
4048
  liveRegion.setAttribute("aria-atomic", "true");
3984
- shadowRoot.append(
4049
+ const styles2 = [
3985
4050
  createStyles(document),
3986
4051
  dataFlowPanel.styles,
4052
+ ...externalHandoffPanel === void 0 ? [] : [externalHandoffPanel.styles]
4053
+ ];
4054
+ const styleNonce = resolveStyleNonce(document);
4055
+ if (styleNonce !== void 0) {
4056
+ for (const style of styles2) {
4057
+ style.nonce = styleNonce;
4058
+ }
4059
+ }
4060
+ shadowRoot.append(
4061
+ ...styles2,
3987
4062
  selectionHighlights,
3988
4063
  highlight,
3989
4064
  dialog,
@@ -4265,6 +4340,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4265
4340
  openEditorButton.disabled = !canOpenEditor;
4266
4341
  previewButton.disabled = !canPreview;
4267
4342
  agentPanel.setContextReady(canPreview);
4343
+ externalHandoffPanel?.setContextReady(canPreview);
4268
4344
  updateContextOverview(summaryText);
4269
4345
  placeDialog();
4270
4346
  }
@@ -4281,6 +4357,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4281
4357
  previewButton.hidden = !selected;
4282
4358
  secondaryActions.hidden = !selected;
4283
4359
  agentPanel.setSelectionVisible(selected);
4360
+ externalHandoffPanel?.setSelectionVisible(selected);
4284
4361
  copyButton.hidden = !previewing;
4285
4362
  backButton.hidden = !previewing;
4286
4363
  title.textContent = previewing ? messages.dialog.previewTitle : messages.dialog.editTitle;
@@ -4362,6 +4439,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4362
4439
  agentApplyButton: agentPanel.applyButton,
4363
4440
  agentRevertButton: agentPanel.revertButton,
4364
4441
  agentResetButton: agentPanel.resetButton,
4442
+ ...externalHandoffPanel === void 0 ? {} : { externalHandoffPanel },
4365
4443
  renderStatus(status) {
4366
4444
  const inspecting = status === "inspecting";
4367
4445
  triggerButton.setAttribute("aria-pressed", String(inspecting));
@@ -4410,6 +4488,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4410
4488
  currentCanPreview = enabled;
4411
4489
  previewButton.disabled = !enabled;
4412
4490
  agentPanel.setContextReady(enabled);
4491
+ externalHandoffPanel?.setContextReady(enabled);
4413
4492
  },
4414
4493
  hideSelection() {
4415
4494
  dialog.hidden = true;
@@ -4434,6 +4513,8 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4434
4513
  currentCanPreview = false;
4435
4514
  agentPanel.setContextReady(false);
4436
4515
  agentPanel.setSelectionVisible(false);
4516
+ externalHandoffPanel?.setContextReady(false);
4517
+ externalHandoffPanel?.setSelectionVisible(false);
4437
4518
  agentPanel.setEditingEnabled(true);
4438
4519
  agentPanel.resetJob();
4439
4520
  dataFlowPanel.resetView();
@@ -4466,6 +4547,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4466
4547
  });
4467
4548
  openEditorButton.disabled = !currentCanOpenEditor;
4468
4549
  previewButton.disabled = !enabled || !currentCanPreview;
4550
+ externalHandoffPanel?.setContextReady(enabled && currentCanPreview);
4469
4551
  agentPanel.setEditingEnabled(enabled);
4470
4552
  placeDialog();
4471
4553
  },
@@ -4506,6 +4588,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4506
4588
  localeButton.removeEventListener("click", localizer.toggle);
4507
4589
  unsubscribeLocale();
4508
4590
  dataFlowPanel.dispose();
4591
+ externalHandoffPanel?.dispose();
4509
4592
  agentPanel.dispose();
4510
4593
  host.remove();
4511
4594
  }
@@ -5003,7 +5086,10 @@ function createController(config, dependencies = {}) {
5003
5086
  config.shortcut,
5004
5087
  config.ai,
5005
5088
  config.locale,
5006
- config.dataFlow.enabled
5089
+ config.dataFlow.enabled,
5090
+ config.externalAgent.enabled,
5091
+ config.framework,
5092
+ config.sessionId
5007
5093
  );
5008
5094
  const api = dependencies.api ?? createRuntimeApi({
5009
5095
  apiBase: config.apiBase,
@@ -5326,6 +5412,7 @@ ${summary}`;
5326
5412
  sessionRevision += 1;
5327
5413
  api.cancelPending();
5328
5414
  agentWorkflow.disposeSelection();
5415
+ externalHandoffWorkflow?.cancelPending();
5329
5416
  clearCollectionTimers();
5330
5417
  resizeObserver?.disconnect();
5331
5418
  targets = [];
@@ -5444,6 +5531,13 @@ ${summary}`;
5444
5531
  },
5445
5532
  view
5446
5533
  });
5534
+ const externalHandoffWorkflow = config.externalAgent.enabled && view.externalHandoffPanel !== void 0 ? getExternalHandoffExtension()?.createWorkflow(
5535
+ browser.window.fetch.bind(browser.window),
5536
+ view.externalHandoffPanel,
5537
+ selectedAnnotation,
5538
+ config.sessionToken,
5539
+ browser.window
5540
+ ) : void 0;
5447
5541
  async function loadSourceContext(target2, revision) {
5448
5542
  const marker = target2.marker;
5449
5543
  if (marker === void 0) {
@@ -5872,6 +5966,7 @@ ${summary}`;
5872
5966
  return;
5873
5967
  }
5874
5968
  mounted = true;
5969
+ externalHandoffWorkflow?.mount();
5875
5970
  view.renderStatus(state.status);
5876
5971
  browser.document.addEventListener("pointermove", handlePointerMove, true);
5877
5972
  browser.document.addEventListener("click", handleClick, true);
@@ -5938,6 +6033,7 @@ ${summary}`;
5938
6033
  api.cancelPending();
5939
6034
  api.dispose();
5940
6035
  agentWorkflow.disposeSelection();
6036
+ externalHandoffWorkflow?.dispose();
5941
6037
  sourceResolver.dispose();
5942
6038
  return;
5943
6039
  }
@@ -6001,6 +6097,7 @@ ${summary}`;
6001
6097
  api.cancelPending();
6002
6098
  api.dispose();
6003
6099
  agentWorkflow.disposeSelection();
6100
+ externalHandoffWorkflow?.dispose();
6004
6101
  sourceResolver.dispose();
6005
6102
  view.dispose();
6006
6103
  state = INITIAL_RUNTIME_STATE;