@spotpatch/runtime 1.13.0 → 1.15.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 (40) hide show
  1. package/dist/{chunk-2WA6XVA4.js → chunk-DCN6OMLH.js} +13 -3
  2. package/dist/{chunk-2WA6XVA4.js.map → chunk-DCN6OMLH.js.map} +1 -1
  3. package/dist/chunk-PXJKFEUJ.js +14 -0
  4. package/dist/chunk-PXJKFEUJ.js.map +1 -0
  5. package/dist/contextual-ask-panel.cjs +1727 -0
  6. package/dist/contextual-ask-panel.cjs.map +1 -0
  7. package/dist/contextual-ask-panel.d.cts +165 -0
  8. package/dist/contextual-ask-panel.d.ts +165 -0
  9. package/dist/contextual-ask-panel.js +1684 -0
  10. package/dist/contextual-ask-panel.js.map +1 -0
  11. package/dist/data-flow-panel.cjs +12 -2
  12. package/dist/data-flow-panel.cjs.map +1 -1
  13. package/dist/data-flow-panel.d.cts +1 -1
  14. package/dist/data-flow-panel.d.ts +1 -1
  15. package/dist/data-flow-panel.js +7 -1
  16. package/dist/data-flow-panel.js.map +1 -1
  17. package/dist/{data-flow-runtime-DMmV0d3E.d.cts → data-flow-runtime-CacBbxN0.d.cts} +2 -1
  18. package/dist/{data-flow-runtime-DMmV0d3E.d.ts → data-flow-runtime-CacBbxN0.d.ts} +2 -1
  19. package/dist/data-flow.cjs +13 -2
  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 +3 -1
  24. package/dist/external-handoff-panel.cjs +22 -6
  25. package/dist/external-handoff-panel.cjs.map +1 -1
  26. package/dist/external-handoff-panel.d.cts +5 -2
  27. package/dist/external-handoff-panel.d.ts +5 -2
  28. package/dist/external-handoff-panel.js +21 -6
  29. package/dist/external-handoff-panel.js.map +1 -1
  30. package/dist/index.cjs +107 -10
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +5 -5
  33. package/dist/index.d.ts +5 -5
  34. package/dist/index.js +99 -9
  35. package/dist/index.js.map +1 -1
  36. package/dist/motion-extension-contract-B3m26CML.d.cts +72 -0
  37. package/dist/motion-extension-contract-B3m26CML.d.ts +72 -0
  38. package/dist/motion.d.cts +3 -71
  39. package/dist/motion.d.ts +3 -71
  40. package/package.json +15 -2
package/dist/index.cjs CHANGED
@@ -293,7 +293,7 @@ function readSuccessData(value) {
293
293
  return value.data;
294
294
  }
295
295
  function isCodeContext(value) {
296
- return isRecord2(value) && typeof value.relativePath === "string" && (value.language === "tsx" || value.language === "jsx") && typeof value.startLine === "number" && typeof value.endLine === "number" && typeof value.excerpt === "string" && (value.boundary === "component" || value.boundary === "nearby-lines");
296
+ return isRecord2(value) && typeof value.relativePath === "string" && (value.language === "tsx" || value.language === "jsx" || value.language === "astro") && typeof value.startLine === "number" && typeof value.endLine === "number" && typeof value.excerpt === "string" && (value.boundary === "component" || value.boundary === "nearby-lines");
297
297
  }
298
298
  function deepFreezeUnknown(value) {
299
299
  if (!isRecord2(value) && !Array.isArray(value)) {
@@ -424,7 +424,7 @@ function omitBrowserCodeContext(request) {
424
424
  };
425
425
  }
426
426
  function runtimeApiErrorCode(error) {
427
- return error instanceof RuntimeApiError ? error.code : void 0;
427
+ return error instanceof RuntimeApiError && isAgentErrorCode(error.code) ? error.code : void 0;
428
428
  }
429
429
  function createRuntimeApi(options) {
430
430
  const pendingRequests = /* @__PURE__ */ new Set();
@@ -1721,7 +1721,11 @@ function createSourceResolver(options) {
1721
1721
  if (marker !== void 0) {
1722
1722
  return Object.freeze({
1723
1723
  react: react2,
1724
- source: markerSource(marker, "jsx-host", "exact")
1724
+ source: markerSource(
1725
+ marker,
1726
+ marker.kind === "astro" ? "astro-host" : "jsx-host",
1727
+ "exact"
1728
+ )
1725
1729
  });
1726
1730
  }
1727
1731
  if (react2.source !== void 0) {
@@ -2548,6 +2552,12 @@ function getExternalHandoffExtension() {
2548
2552
  return globalThis[EXTERNAL_HANDOFF_EXTENSION_KEY];
2549
2553
  }
2550
2554
 
2555
+ // src/ui/contextual-ask-contract.ts
2556
+ var CONTEXTUAL_ASK_EXTENSION_KEY = /* @__PURE__ */ Symbol.for("spotpatch.contextual-ask.v1");
2557
+ function getContextualAskExtension() {
2558
+ return globalThis[CONTEXTUAL_ASK_EXTENSION_KEY];
2559
+ }
2560
+
2551
2561
  // src/ui/motion-extension-contract.ts
2552
2562
  var MOTION_EXTENSION_KEY = /* @__PURE__ */ Symbol.for("spotpatch.motion.v1");
2553
2563
  function getFloatingSurfaceMotionExtension() {
@@ -4353,7 +4363,7 @@ function createUnavailableDataFlowPanel(document, changesRoot, diagnosticsRoot)
4353
4363
  resetView: () => void 0
4354
4364
  });
4355
4365
  }
4356
- function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto", dataFlowEnabled = false, externalAgentEnabled = false, framework = "vite", sessionId = "") {
4366
+ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: false }), localePreference = "auto", dataFlowEnabled = false, externalAgentEnabled = false, framework = "vite", sessionId = "", contextualAskEnabled = false) {
4357
4367
  const localizer = createUiLocalizer(document, localePreference);
4358
4368
  const associatedWindow = document.defaultView;
4359
4369
  if (associatedWindow === null) {
@@ -4367,6 +4377,9 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4367
4377
  );
4368
4378
  let messages = localizer.messages();
4369
4379
  let currentStatus = "idle";
4380
+ let contextualAskMode = "change";
4381
+ let contextualAskTitle = "";
4382
+ let contextualAskSubtitle = "";
4370
4383
  let plannerVisible = false;
4371
4384
  let executionSuppressed = false;
4372
4385
  let executionProjection;
@@ -4576,6 +4589,29 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4576
4589
  backButton
4577
4590
  );
4578
4591
  actions.append(editorFeedback, secondaryActions, primaryActions);
4592
+ const contextualAskPanel = contextualAskEnabled ? getContextualAskExtension()?.createPanel({
4593
+ document,
4594
+ locale: localizer.locale,
4595
+ subscribeLocale: localizer.subscribe,
4596
+ changeRoot: dataFlowPanel.root,
4597
+ changeActions: actions,
4598
+ announce,
4599
+ onModeChange(mode, askTitle, askSubtitle) {
4600
+ contextualAskMode = mode;
4601
+ contextualAskTitle = askTitle;
4602
+ contextualAskSubtitle = askSubtitle;
4603
+ if (host.isConnected) renderPanelStatus(currentStatus);
4604
+ },
4605
+ onExecutionChange(projection) {
4606
+ executionProjection = projection;
4607
+ executionSuppressed = false;
4608
+ renderFloatingSurfaceMotion();
4609
+ },
4610
+ onViewChange: requestFloatingSurfaceLayout
4611
+ }) : void 0;
4612
+ if (contextualAskPanel !== void 0) {
4613
+ selectionPanel.prepend(contextualAskPanel.root);
4614
+ }
4579
4615
  shell.append(header, body, actions);
4580
4616
  dialog.append(shell);
4581
4617
  const liveRegion = createMarkedElement(document, "div");
@@ -4586,6 +4622,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4586
4622
  createStyles(document),
4587
4623
  ...motionExtension === void 0 ? [] : [motionExtension.createStyles(document)],
4588
4624
  dataFlowPanel.styles,
4625
+ ...contextualAskPanel === void 0 ? [] : [contextualAskPanel.styles],
4589
4626
  ...externalHandoffPanel === void 0 ? [] : [externalHandoffPanel.styles]
4590
4627
  ];
4591
4628
  const styleNonce = resolveStyleNonce(document);
@@ -5138,6 +5175,11 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5138
5175
  previewButton.disabled = !canPreview;
5139
5176
  agentPanel.setContextReady(canPreview);
5140
5177
  externalHandoffPanel?.setContextReady(canPreview);
5178
+ contextualAskPanel?.setSelectionPreview({
5179
+ contextReady: currentTargets.every((target2) => target2.status !== "loading"),
5180
+ targetCount: currentTargets.length,
5181
+ sourceCount: currentTargets.filter((target2) => target2.canOpenEditor).length
5182
+ });
5141
5183
  updateContextOverview(summaryText);
5142
5184
  requestFloatingSurfaceLayout();
5143
5185
  }
@@ -5154,10 +5196,11 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5154
5196
  secondaryActions.hidden = !selected;
5155
5197
  agentPanel.setSelectionVisible(selected);
5156
5198
  externalHandoffPanel?.setSelectionVisible(selected);
5199
+ contextualAskPanel?.setSelectionVisible(selected);
5157
5200
  copyButton.hidden = !previewing;
5158
5201
  backButton.hidden = !previewing;
5159
- title.textContent = previewing ? messages.dialog.previewTitle : messages.dialog.editTitle;
5160
- subtitle.textContent = previewing ? messages.dialog.previewSubtitle : messages.dialog.editSubtitle;
5202
+ title.textContent = previewing ? messages.dialog.previewTitle : contextualAskMode === "ask" && contextualAskTitle.length > 0 ? contextualAskTitle : messages.dialog.editTitle;
5203
+ subtitle.textContent = previewing ? messages.dialog.previewSubtitle : contextualAskMode === "ask" && contextualAskSubtitle.length > 0 ? contextualAskSubtitle : messages.dialog.editSubtitle;
5161
5204
  renderFloatingSurfaceMotion();
5162
5205
  }
5163
5206
  function applyMessages() {
@@ -5292,6 +5335,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5292
5335
  agentRevertButton: agentPanel.revertButton,
5293
5336
  agentResetButton: agentPanel.resetButton,
5294
5337
  ...externalHandoffPanel === void 0 ? {} : { externalHandoffPanel },
5338
+ ...contextualAskPanel === void 0 ? {} : { contextualAskPanel },
5295
5339
  renderStatus(status) {
5296
5340
  const inspecting = status === "inspecting";
5297
5341
  if (status === "idle" || inspecting) {
@@ -5365,6 +5409,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5365
5409
  agentPanel.setSelectionVisible(false);
5366
5410
  externalHandoffPanel?.setContextReady(false);
5367
5411
  externalHandoffPanel?.setSelectionVisible(false);
5412
+ contextualAskPanel?.setSelectionVisible(false);
5368
5413
  agentPanel.setEditingEnabled(true);
5369
5414
  agentPanel.resetJob();
5370
5415
  dataFlowPanel.resetView();
@@ -5505,6 +5550,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
5505
5550
  unsubscribeLocale();
5506
5551
  dataFlowPanel.dispose();
5507
5552
  externalHandoffPanel?.dispose();
5553
+ contextualAskPanel?.dispose();
5508
5554
  agentPanel.dispose();
5509
5555
  motionController?.dispose();
5510
5556
  executionIslandView.dispose();
@@ -5534,7 +5580,7 @@ function sourceLocation2(resolution, context, messages) {
5534
5580
  function createSelectionSummary(input, messages) {
5535
5581
  const lines = [
5536
5582
  `SpotPatch: ${input.spotPatchVersion}`,
5537
- `${input.framework === "next" ? "Next.js" : "Vite"}: ${input.frameworkVersion}`,
5583
+ `${{ next: "Next.js", vite: "Vite", astro: "Astro" }[input.framework]}: ${input.frameworkVersion}`,
5538
5584
  `${messages.source}: ${sourceLocation2(input.resolution, input.code, messages)}`,
5539
5585
  `${messages.confidence}: ${input.resolution.source.confidence} (${messages.confidenceLabels[input.resolution.source.confidence]})`,
5540
5586
  `${messages.origin}: ${input.resolution.source.origin}`
@@ -6023,7 +6069,8 @@ function createController(config, dependencies = {}) {
6023
6069
  config.dataFlow.enabled,
6024
6070
  config.externalAgent.enabled,
6025
6071
  config.framework,
6026
- config.sessionId
6072
+ config.sessionId,
6073
+ config.contextualAsk.enabled
6027
6074
  );
6028
6075
  const api = dependencies.api ?? createRuntimeApi({
6029
6076
  apiBase: config.apiBase,
@@ -6226,6 +6273,19 @@ function createController(config, dependencies = {}) {
6226
6273
  (target2) => target2.instruction.trim().length > 0 && target2.elementContext !== void 0 && target2.styles !== void 0 && target2.apiStatus !== "loading"
6227
6274
  );
6228
6275
  }
6276
+ function selectedAskSelection() {
6277
+ const snapshots = targets.flatMap((target2) => {
6278
+ const snapshot = snapshotTarget(target2);
6279
+ return snapshot === void 0 ? [] : [snapshot];
6280
+ });
6281
+ if (snapshots.length === 0 || snapshots.length !== targets.length) {
6282
+ return void 0;
6283
+ }
6284
+ return Object.freeze({
6285
+ locale: view.locale(),
6286
+ targets: snapshots
6287
+ });
6288
+ }
6229
6289
  function selectionSummary() {
6230
6290
  const messages = view.messages().summary;
6231
6291
  return targets.map((target2, index) => {
@@ -6347,6 +6407,7 @@ ${summary}`;
6347
6407
  api.cancelPending();
6348
6408
  agentWorkflow.disposeSelection();
6349
6409
  externalHandoffWorkflow?.cancelPending();
6410
+ contextualAskWorkflow?.cancelPending();
6350
6411
  clearCollectionTimers();
6351
6412
  resizeObserver?.disconnect();
6352
6413
  targets = [];
@@ -6472,6 +6533,27 @@ ${summary}`;
6472
6533
  config.sessionToken,
6473
6534
  browser.window
6474
6535
  ) : void 0;
6536
+ const contextualAskWorkflow = config.contextualAsk.enabled && view.contextualAskPanel !== void 0 ? getContextualAskExtension()?.createWorkflow({
6537
+ ...clipboard === void 0 ? {} : { clipboard },
6538
+ createId,
6539
+ fetch: browser.window.fetch.bind(browser.window),
6540
+ getSelection: selectedAskSelection,
6541
+ onBusyChange(busy) {
6542
+ view.setAgentEditingEnabled(!busy);
6543
+ },
6544
+ onConvert() {
6545
+ view.focusTargetInstruction(activeTargetId);
6546
+ },
6547
+ async onOpenSource(source2) {
6548
+ await api.openEditor({
6549
+ fileId: source2.fileId,
6550
+ line: source2.startLine,
6551
+ column: 1
6552
+ });
6553
+ },
6554
+ panel: view.contextualAskPanel,
6555
+ sessionToken: config.sessionToken
6556
+ }) : void 0;
6475
6557
  async function loadSourceContext(target2, revision) {
6476
6558
  const marker = target2.marker;
6477
6559
  if (marker === void 0) {
@@ -6585,6 +6667,7 @@ ${summary}`;
6585
6667
  previewPrompt = "";
6586
6668
  agentWorkflow.beginSelection();
6587
6669
  workflowSelectionActive = true;
6670
+ contextualAskWorkflow?.beginSelection();
6588
6671
  }
6589
6672
  targetSequence += 1;
6590
6673
  const target2 = {
@@ -6603,6 +6686,9 @@ ${summary}`;
6603
6686
  dataFlowStatus: "idle"
6604
6687
  };
6605
6688
  targets.push(target2);
6689
+ if (!initialSelection) {
6690
+ contextualAskWorkflow?.selectionChanged();
6691
+ }
6606
6692
  activeTargetId = target2.id;
6607
6693
  addingTarget = false;
6608
6694
  const revision = sessionRevision;
@@ -6719,10 +6805,12 @@ ${summary}`;
6719
6805
  pageDataFlowStatus = "idle";
6720
6806
  renderDataFlowView();
6721
6807
  selectionSession.clear();
6808
+ contextualAskWorkflow?.selectionChanged();
6722
6809
  view.announce(view.messages().announcements.allTargetsRemoved);
6723
6810
  return;
6724
6811
  }
6725
6812
  refreshSelectionView();
6813
+ contextualAskWorkflow?.selectionChanged();
6726
6814
  void loadDataFlowReports();
6727
6815
  persistSelection();
6728
6816
  view.announce(view.messages().announcements.targetRemoved);
@@ -6901,6 +6989,7 @@ ${summary}`;
6901
6989
  }
6902
6990
  mounted = true;
6903
6991
  externalHandoffWorkflow?.mount();
6992
+ contextualAskWorkflow?.mount();
6904
6993
  view.renderStatus(state.status);
6905
6994
  browser.document.addEventListener("pointermove", handlePointerMove, true);
6906
6995
  browser.document.addEventListener("click", handleClick, true);
@@ -6952,6 +7041,7 @@ ${summary}`;
6952
7041
  if (selectionOpen && targets.length > 0) {
6953
7042
  transition({ type: "RESTORE" });
6954
7043
  agentWorkflow.beginSelection();
7044
+ contextualAskWorkflow?.beginSelection();
6955
7045
  workflowSelectionActive = true;
6956
7046
  refreshSelectionView(true);
6957
7047
  }
@@ -6968,6 +7058,7 @@ ${summary}`;
6968
7058
  api.dispose();
6969
7059
  agentWorkflow.disposeSelection();
6970
7060
  externalHandoffWorkflow?.dispose();
7061
+ contextualAskWorkflow?.dispose();
6971
7062
  sourceResolver.dispose();
6972
7063
  return;
6973
7064
  }
@@ -7032,6 +7123,7 @@ ${summary}`;
7032
7123
  api.dispose();
7033
7124
  agentWorkflow.disposeSelection();
7034
7125
  externalHandoffWorkflow?.dispose();
7126
+ contextualAskWorkflow?.dispose();
7035
7127
  sourceResolver.dispose();
7036
7128
  view.dispose();
7037
7129
  state = INITIAL_RUNTIME_STATE;
@@ -7047,6 +7139,7 @@ function bootstrapSpotPatch(config) {
7047
7139
  const controller = createController(config);
7048
7140
  target2[RUNTIME_INSTANCE_KEY] = controller;
7049
7141
  controller.mount();
7142
+ return controller;
7050
7143
  }
7051
7144
 
7052
7145
  // src/data-flow/data-flow-runtime.ts
@@ -7466,7 +7559,7 @@ var import_shared10 = require("@spotpatch/shared");
7466
7559
  function observationMatchesDependency(observation, dependency) {
7467
7560
  const origin = dependency.origin;
7468
7561
  const transportMatches = dependency.kind === "rpc" ? observation.transport === "trpc" && dependency.operation !== void 0 && observation.operation === dependency.operation : dependency.kind === "http" ? observation.transport === "fetch" || observation.transport === "xhr" : false;
7469
- if (!transportMatches || observation.freshness !== "current" || origin === void 0 || observation.requestCallsiteId !== origin.requestCallsiteId || observation.sourceVersion !== origin.sourceVersion || dependency.method !== void 0 && observation.method.toUpperCase() !== dependency.method.toUpperCase() || dependency.url !== void 0 && observation.url.pathname !== dependency.url.pathname || dependency.url?.origin !== void 0 && observation.url.origin !== dependency.url.origin || origin.componentSourceId !== void 0 && observation.componentSourceId !== void 0 && observation.componentSourceId !== origin.componentSourceId || origin.triggerCallsiteId !== void 0 && observation.triggerCallsiteId !== void 0 && observation.triggerCallsiteId !== origin.triggerCallsiteId) {
7562
+ if (dependency.environment === "server" || !transportMatches || observation.freshness !== "current" || origin === void 0 || observation.requestCallsiteId !== origin.requestCallsiteId || observation.sourceVersion !== origin.sourceVersion || dependency.method !== void 0 && observation.method.toUpperCase() !== dependency.method.toUpperCase() || dependency.url !== void 0 && observation.url.pathname !== dependency.url.pathname || dependency.url?.origin !== void 0 && observation.url.origin !== dependency.url.origin || origin.componentSourceId !== void 0 && observation.componentSourceId !== void 0 && observation.componentSourceId !== origin.componentSourceId || origin.triggerCallsiteId !== void 0 && observation.triggerCallsiteId !== void 0 && observation.triggerCallsiteId !== origin.triggerCallsiteId) {
7470
7563
  return false;
7471
7564
  }
7472
7565
  return dependency.association !== "transitive" || observation.componentSourceId === origin.componentSourceId && observation.triggerCallsiteId === origin.triggerCallsiteId;
@@ -7524,8 +7617,12 @@ function appendRuntimeEvidence(evidence, observations, matchedIds) {
7524
7617
  ]);
7525
7618
  }
7526
7619
  function mergeComponentDataFlowReport(report, observations) {
7620
+ const owners = /* @__PURE__ */ new Set([
7621
+ report.component.componentSourceId,
7622
+ ...report.dependencies.filter((dependency) => dependency.environment !== "server").map((dependency) => dependency.origin?.componentSourceId)
7623
+ ]);
7527
7624
  const componentObservations = observations.filter(
7528
- (observation) => observation.componentSourceId === void 0 || observation.componentSourceId === report.component.componentSourceId
7625
+ (observation) => observation.componentSourceId === void 0 || owners.has(observation.componentSourceId)
7529
7626
  );
7530
7627
  const merged = mergeDependencies(report.dependencies, componentObservations);
7531
7628
  return (0, import_shared10.limitDataFlowReportCollections)(