@spotpatch/runtime 1.6.0 → 1.7.1

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.cjs CHANGED
@@ -1729,7 +1729,8 @@ var AGENT_PANEL_STYLES = `
1729
1729
  font-weight: 650;
1730
1730
  }
1731
1731
  .spotpatch-agent-setup { padding: 12px; }
1732
- .spotpatch-agent-selectors { display: grid; grid-template-columns: 1fr; gap: 10px; }
1732
+ .spotpatch-agent-selectors { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
1733
+ .spotpatch-agent-mode { grid-column: 1 / -1; }
1733
1734
  .spotpatch-agent-selectors label { min-width: 0; color: var(--spotpatch-text-secondary); font-size: 11.5px; font-weight: 580; }
1734
1735
  .spotpatch-agent select {
1735
1736
  box-sizing: border-box;
@@ -1767,19 +1768,21 @@ var AGENT_PANEL_STYLES = `
1767
1768
  width: anchor-size(width);
1768
1769
  max-height: min(280px, 40vh);
1769
1770
  margin: 0;
1770
- overflow: hidden;
1771
+ overflow: auto;
1771
1772
  border: 1px solid rgb(139 124 247 / 28%);
1772
1773
  border-radius: 12px;
1773
1774
  padding: 6px;
1774
1775
  background: #10151e;
1775
1776
  box-shadow: 0 18px 50px rgb(0 0 0 / 38%);
1776
- opacity: 0;
1777
- transform: translateY(-5px) scale(.985);
1777
+ opacity: 1;
1778
+ transform: translateY(0) scale(1);
1778
1779
  transition: opacity 150ms ease, transform 180ms cubic-bezier(.2, .8, .2, 1), overlay 180ms allow-discrete, display 180ms allow-discrete;
1779
1780
  }
1780
- ::picker(select):popover-open { opacity: 1; transform: translateY(0) scale(1); }
1781
1781
  @starting-style {
1782
- ::picker(select):popover-open { opacity: 0; transform: translateY(-5px) scale(.985); }
1782
+ .spotpatch-agent select::picker(select):popover-open {
1783
+ opacity: 0;
1784
+ transform: translateY(-5px) scale(.985);
1785
+ }
1783
1786
  }
1784
1787
  .spotpatch-agent select option {
1785
1788
  min-height: 42px;
@@ -1914,12 +1917,17 @@ var AGENT_PANEL_STYLES = `
1914
1917
  white-space: pre;
1915
1918
  user-select: text;
1916
1919
  }
1920
+ @media (max-width: 520px) {
1921
+ .spotpatch-agent-selectors { grid-template-columns: 1fr; }
1922
+ .spotpatch-agent-mode { grid-column: auto; }
1923
+ }
1917
1924
  `;
1918
1925
  function addOption(document, select, value, label) {
1919
1926
  const option = document.createElement("option");
1920
1927
  option.value = value;
1921
1928
  option.textContent = label;
1922
1929
  select.append(option);
1930
+ return option;
1923
1931
  }
1924
1932
  function createAgentPanel(document, ai, localizer) {
1925
1933
  let messages = localizer.messages();
@@ -1937,6 +1945,11 @@ function createAgentPanel(document, ai, localizer) {
1937
1945
  setup.className = "spotpatch-agent-setup";
1938
1946
  const selectors = createMarkedElement(document, "div");
1939
1947
  selectors.className = "spotpatch-agent-selectors";
1948
+ const modeLabel = createMarkedElement(document, "label");
1949
+ modeLabel.className = "spotpatch-agent-mode";
1950
+ const modeText = createMarkedElement(document, "span");
1951
+ const modeSelect = createMarkedElement(document, "select");
1952
+ modeLabel.append(modeText, modeSelect);
1940
1953
  const providerLabel = createMarkedElement(document, "label");
1941
1954
  const providerText = createMarkedElement(document, "span");
1942
1955
  const providerSelect = createMarkedElement(document, "select");
@@ -1945,7 +1958,7 @@ function createAgentPanel(document, ai, localizer) {
1945
1958
  const modelText = createMarkedElement(document, "span");
1946
1959
  const modelSelect = createMarkedElement(document, "select");
1947
1960
  modelLabel.append(modelText, modelSelect);
1948
- selectors.append(providerLabel, modelLabel);
1961
+ selectors.append(modeLabel, providerLabel, modelLabel);
1949
1962
  const consent = createMarkedElement(document, "label");
1950
1963
  consent.className = "spotpatch-consent";
1951
1964
  const consentCheckbox = createMarkedElement(document, "input");
@@ -2012,8 +2025,8 @@ function createAgentPanel(document, ai, localizer) {
2012
2025
  const revertButton = createButton(document, messages.agent.revert);
2013
2026
  const resetButton = createButton(document, messages.agent.revise);
2014
2027
  const providers = ai.enabled ? ai.providers : [];
2015
- const trustedFastMode = ai.enabled && ai.applyMode === "trusted-auto";
2016
- consent.classList.toggle("spotpatch-trusted-consent", trustedFastMode);
2028
+ const trustedFastModeAvailable = ai.enabled && ai.applyMode === "trusted-auto";
2029
+ const configuredApplyMode = ai.enabled ? ai.applyMode : "review";
2017
2030
  const providerById = new Map(providers.map((provider) => [provider.id, provider]));
2018
2031
  let contextReady = false;
2019
2032
  let editingEnabled = true;
@@ -2037,14 +2050,42 @@ function createAgentPanel(document, ai, localizer) {
2037
2050
  if (ai.enabled) {
2038
2051
  providerSelect.value = ai.defaultProvider;
2039
2052
  }
2053
+ let reviewOption;
2054
+ let trustedOption;
2055
+ let autoOption;
2056
+ if (configuredApplyMode === "auto") {
2057
+ autoOption = addOption(document, modeSelect, "auto", messages.agent.autoGated);
2058
+ } else {
2059
+ reviewOption = addOption(document, modeSelect, "review", messages.agent.review);
2060
+ if (trustedFastModeAvailable) {
2061
+ trustedOption = addOption(
2062
+ document,
2063
+ modeSelect,
2064
+ "trusted-auto",
2065
+ messages.agent.trustedFast
2066
+ );
2067
+ }
2068
+ }
2069
+ const defaultApplyMode = trustedFastModeAvailable ? "review" : configuredApplyMode;
2070
+ modeSelect.value = defaultApplyMode;
2071
+ modeLabel.hidden = !trustedFastModeAvailable;
2072
+ const selectedApplyMode = () => modeSelect.value === "trusted-auto" ? "trusted-auto" : defaultApplyMode;
2073
+ const trustedFastMode = () => selectedApplyMode() === "trusted-auto";
2040
2074
  const selectedProvider = () => providerById.get(providerSelect.value);
2041
2075
  const consentMessage = (provider) => {
2042
2076
  if (provider === void 0) {
2043
2077
  return messages.agent.providerUnavailable;
2044
2078
  }
2045
- return trustedFastMode ? messages.agent.trustedFastConsent(provider.label) : messages.agent.consent(provider.label);
2079
+ return trustedFastMode() ? messages.agent.trustedFastConsent(provider.label) : messages.agent.consent(provider.label);
2080
+ };
2081
+ const localChangesConsentGranted = () => trustedFastMode() ? consentCheckbox.checked : workspaceConsentCheckbox.checked;
2082
+ const renderMode = () => {
2083
+ const trusted = trustedFastMode();
2084
+ consent.classList.toggle("spotpatch-trusted-consent", trusted);
2085
+ badge.textContent = trusted ? messages.agent.trustedFast : configuredApplyMode === "auto" ? messages.agent.autoGated : messages.agent.review;
2086
+ consentText.textContent = consentMessage(selectedProvider());
2087
+ workspaceConsent.hidden = trusted || latestWorkspaceState !== "consent-required";
2046
2088
  };
2047
- const localChangesConsentGranted = () => trustedFastMode ? consentCheckbox.checked : workspaceConsentCheckbox.checked;
2048
2089
  const populateModels = () => {
2049
2090
  const provider = selectedProvider();
2050
2091
  modelSelect.replaceChildren();
@@ -2111,7 +2152,14 @@ function createAgentPanel(document, ai, localizer) {
2111
2152
  capabilityReady = false;
2112
2153
  refreshActions();
2113
2154
  }
2155
+ function handleModeChange() {
2156
+ consentCheckbox.checked = false;
2157
+ workspaceConsentCheckbox.checked = false;
2158
+ renderMode();
2159
+ refreshActions();
2160
+ }
2114
2161
  populateModels();
2162
+ modeSelect.addEventListener("change", handleModeChange);
2115
2163
  providerSelect.addEventListener("change", handleProviderChange);
2116
2164
  modelSelect.addEventListener("change", handleModelChange);
2117
2165
  consentCheckbox.addEventListener("change", refreshActions);
@@ -2165,7 +2213,11 @@ function createAgentPanel(document, ai, localizer) {
2165
2213
  function applyMessages() {
2166
2214
  messages = localizer.messages();
2167
2215
  title.textContent = messages.agent.title;
2168
- badge.textContent = trustedFastMode ? messages.agent.trustedFast : ai.enabled && ai.applyMode === "auto" ? messages.agent.autoGated : messages.agent.review;
2216
+ modeText.textContent = messages.agent.mode;
2217
+ if (reviewOption !== void 0) reviewOption.textContent = messages.agent.review;
2218
+ if (trustedOption !== void 0)
2219
+ trustedOption.textContent = messages.agent.trustedFast;
2220
+ if (autoOption !== void 0) autoOption.textContent = messages.agent.autoGated;
2169
2221
  providerText.textContent = messages.agent.provider;
2170
2222
  modelText.textContent = messages.agent.model;
2171
2223
  providerSelect.setAttribute("aria-label", messages.agent.providerAriaLabel);
@@ -2177,8 +2229,7 @@ function createAgentPanel(document, ai, localizer) {
2177
2229
  applyButton.textContent = messages.agent.apply;
2178
2230
  revertButton.textContent = messages.agent.revert;
2179
2231
  resetButton.textContent = messages.agent.revise;
2180
- const provider = selectedProvider();
2181
- consentText.textContent = consentMessage(provider);
2232
+ renderMode();
2182
2233
  if (latestCapabilityState === "idle") {
2183
2234
  capability.textContent = messages.agent.connectionNotTested;
2184
2235
  } else if (latestCapabilityState === "probing") {
@@ -2200,6 +2251,7 @@ function createAgentPanel(document, ai, localizer) {
2200
2251
  applyMessages();
2201
2252
  return Object.freeze({
2202
2253
  root,
2254
+ modeSelect,
2203
2255
  providerSelect,
2204
2256
  modelSelect,
2205
2257
  consentCheckbox,
@@ -2222,6 +2274,7 @@ function createAgentPanel(document, ai, localizer) {
2222
2274
  (candidate) => candidate.id === modelSelect.value
2223
2275
  );
2224
2276
  return provider === void 0 || model === void 0 ? void 0 : Object.freeze({
2277
+ applyMode: selectedApplyMode(),
2225
2278
  providerProfileId: provider.id,
2226
2279
  modelProfileId: model.id
2227
2280
  });
@@ -2242,7 +2295,7 @@ function createAgentPanel(document, ai, localizer) {
2242
2295
  latestWorkspaceErrorCode = errorCode ?? snapshot?.errorCode;
2243
2296
  workspace.dataset.state = state;
2244
2297
  if (state !== "checking") {
2245
- workspaceConsent.hidden = trustedFastMode || state !== "consent-required";
2298
+ workspaceConsent.hidden = trustedFastMode() || state !== "consent-required";
2246
2299
  }
2247
2300
  if (state === "idle" || state === "ready" || state === "blocked") {
2248
2301
  workspaceConsentCheckbox.checked = false;
@@ -2256,6 +2309,7 @@ function createAgentPanel(document, ai, localizer) {
2256
2309
  job.hidden = false;
2257
2310
  providerSelect.disabled = true;
2258
2311
  modelSelect.disabled = true;
2312
+ modeSelect.disabled = true;
2259
2313
  consentCheckbox.disabled = true;
2260
2314
  workspaceConsentCheckbox.disabled = true;
2261
2315
  latestSnapshot = snapshot;
@@ -2274,6 +2328,7 @@ function createAgentPanel(document, ai, localizer) {
2274
2328
  job.hidden = true;
2275
2329
  providerSelect.disabled = false;
2276
2330
  modelSelect.disabled = false;
2331
+ modeSelect.disabled = false;
2277
2332
  consentCheckbox.disabled = false;
2278
2333
  workspaceConsentCheckbox.disabled = false;
2279
2334
  activity.replaceChildren();
@@ -2292,6 +2347,7 @@ function createAgentPanel(document, ai, localizer) {
2292
2347
  editingEnabled = enabled;
2293
2348
  providerSelect.disabled = !enabled || jobPresented;
2294
2349
  modelSelect.disabled = !enabled || jobPresented;
2350
+ modeSelect.disabled = !enabled || jobPresented;
2295
2351
  consentCheckbox.disabled = !enabled || jobPresented;
2296
2352
  workspaceConsentCheckbox.disabled = !enabled || jobPresented;
2297
2353
  refreshActions();
@@ -2314,6 +2370,7 @@ function createAgentPanel(document, ai, localizer) {
2314
2370
  unsubscribeLocale();
2315
2371
  providerSelect.removeEventListener("change", handleProviderChange);
2316
2372
  modelSelect.removeEventListener("change", handleModelChange);
2373
+ modeSelect.removeEventListener("change", handleModeChange);
2317
2374
  consentCheckbox.removeEventListener("change", refreshActions);
2318
2375
  workspaceConsentCheckbox.removeEventListener("change", refreshActions);
2319
2376
  }
@@ -2717,6 +2774,7 @@ var UI_MESSAGES = Object.freeze({
2717
2774
  }),
2718
2775
  agent: Object.freeze({
2719
2776
  title: "AI code agent",
2777
+ mode: "Execution mode",
2720
2778
  review: "Review",
2721
2779
  autoGated: "Auto gated",
2722
2780
  trustedFast: "Trusted fast",
@@ -2854,6 +2912,7 @@ var UI_MESSAGES = Object.freeze({
2854
2912
  }),
2855
2913
  agent: Object.freeze({
2856
2914
  title: "AI \u4EE3\u7801 Agent",
2915
+ mode: "\u6267\u884C\u65B9\u5F0F",
2857
2916
  review: "\u5BA1\u9605\u6A21\u5F0F",
2858
2917
  autoGated: "\u53D7\u63A7\u81EA\u52A8\u6A21\u5F0F",
2859
2918
  trustedFast: "\u53EF\u4FE1\u5FEB\u901F\u6A21\u5F0F",
@@ -4218,6 +4277,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4218
4277
  closeButton,
4219
4278
  agentProviderSelect: agentPanel.providerSelect,
4220
4279
  agentModelSelect: agentPanel.modelSelect,
4280
+ agentModeSelect: agentPanel.modeSelect,
4221
4281
  agentConsentCheckbox: agentPanel.consentCheckbox,
4222
4282
  agentWorkspaceConsentCheckbox: agentPanel.workspaceConsentCheckbox,
4223
4283
  agentTestButton: agentPanel.testButton,
@@ -4459,6 +4519,7 @@ function createAgentWorkflow(options) {
4459
4519
  let appliedDuringCurrentJob = false;
4460
4520
  let actionPending = false;
4461
4521
  const selectedProfiles = () => options.view.readAgentSelection();
4522
+ const consentKey = (selection) => `${selection.providerProfileId}:${selection.applyMode}`;
4462
4523
  const refreshWorkspaceHealth = async (workflowRevision) => {
4463
4524
  options.view.renderAgentWorkspaceHealth("checking");
4464
4525
  try {
@@ -4496,9 +4557,7 @@ function createAgentWorkflow(options) {
4496
4557
  );
4497
4558
  return;
4498
4559
  }
4499
- options.view.setAgentProviderConsent(
4500
- providerConsents.has(selection.providerProfileId)
4501
- );
4560
+ options.view.setAgentProviderConsent(providerConsents.has(consentKey(selection)));
4502
4561
  const cached = capabilities.get(
4503
4562
  capabilityKey(selection.providerProfileId, selection.modelProfileId)
4504
4563
  );
@@ -4666,9 +4725,9 @@ function createAgentWorkflow(options) {
4666
4725
  return;
4667
4726
  }
4668
4727
  if (options.view.agentConsentGranted()) {
4669
- providerConsents.add(selection.providerProfileId);
4728
+ providerConsents.add(consentKey(selection));
4670
4729
  } else {
4671
- providerConsents.delete(selection.providerProfileId);
4730
+ providerConsents.delete(consentKey(selection));
4672
4731
  }
4673
4732
  },
4674
4733
  disposeSelection() {
@@ -4708,7 +4767,6 @@ function createAgentWorkflow(options) {
4708
4767
  if (!options.ai.enabled || snapshot !== void 0) {
4709
4768
  return;
4710
4769
  }
4711
- const trustedFastMode = options.ai.applyMode === "trusted-auto";
4712
4770
  const selection = selectedProfiles();
4713
4771
  const annotation = options.getAnnotation();
4714
4772
  if (selection === void 0 || annotation === void 0) {
@@ -4721,7 +4779,7 @@ function createAgentWorkflow(options) {
4721
4779
  options.view.announce(options.view.messages().agent.consentRequired);
4722
4780
  return;
4723
4781
  }
4724
- providerConsents.add(selection.providerProfileId);
4782
+ providerConsents.add(consentKey(selection));
4725
4783
  const workflowRevision = ++revision;
4726
4784
  options.view.setAgentEditingEnabled(false);
4727
4785
  void refreshWorkspaceHealth(workflowRevision).then(async (health) => {
@@ -4738,10 +4796,11 @@ function createAgentWorkflow(options) {
4738
4796
  }
4739
4797
  const created = await options.api.createAgentJob({
4740
4798
  annotation,
4799
+ applyMode: selection.applyMode,
4741
4800
  providerProfileId: selection.providerProfileId,
4742
4801
  modelProfileId: selection.modelProfileId,
4743
4802
  providerDataConsent: true,
4744
- ...trustedFastMode ? { trustedFastModeConsent: true } : {},
4803
+ ...selection.applyMode === "trusted-auto" ? { trustedFastModeConsent: true } : {},
4745
4804
  workingTreeMode: health.state === "consent-required" ? "include-local-changes" : "require-clean"
4746
4805
  });
4747
4806
  if (workflowRevision !== revision) {
@@ -5638,6 +5697,10 @@ ${summary}`;
5638
5697
  "change",
5639
5698
  agentWorkflow.providerOrModelChanged
5640
5699
  );
5700
+ view.agentModeSelect.addEventListener(
5701
+ "change",
5702
+ agentWorkflow.providerOrModelChanged
5703
+ );
5641
5704
  view.agentConsentCheckbox.addEventListener("change", agentWorkflow.consentChanged);
5642
5705
  view.agentTestButton.addEventListener("click", agentWorkflow.testCapability);
5643
5706
  view.agentRunButton.addEventListener("click", agentWorkflow.run);
@@ -5704,6 +5767,10 @@ ${summary}`;
5704
5767
  "change",
5705
5768
  agentWorkflow.providerOrModelChanged
5706
5769
  );
5770
+ view.agentModeSelect.removeEventListener(
5771
+ "change",
5772
+ agentWorkflow.providerOrModelChanged
5773
+ );
5707
5774
  view.agentConsentCheckbox.removeEventListener(
5708
5775
  "change",
5709
5776
  agentWorkflow.consentChanged