@spotpatch/runtime 1.6.0 → 1.7.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.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;
@@ -1914,12 +1915,17 @@ var AGENT_PANEL_STYLES = `
1914
1915
  white-space: pre;
1915
1916
  user-select: text;
1916
1917
  }
1918
+ @media (max-width: 520px) {
1919
+ .spotpatch-agent-selectors { grid-template-columns: 1fr; }
1920
+ .spotpatch-agent-mode { grid-column: auto; }
1921
+ }
1917
1922
  `;
1918
1923
  function addOption(document, select, value, label) {
1919
1924
  const option = document.createElement("option");
1920
1925
  option.value = value;
1921
1926
  option.textContent = label;
1922
1927
  select.append(option);
1928
+ return option;
1923
1929
  }
1924
1930
  function createAgentPanel(document, ai, localizer) {
1925
1931
  let messages = localizer.messages();
@@ -1937,6 +1943,11 @@ function createAgentPanel(document, ai, localizer) {
1937
1943
  setup.className = "spotpatch-agent-setup";
1938
1944
  const selectors = createMarkedElement(document, "div");
1939
1945
  selectors.className = "spotpatch-agent-selectors";
1946
+ const modeLabel = createMarkedElement(document, "label");
1947
+ modeLabel.className = "spotpatch-agent-mode";
1948
+ const modeText = createMarkedElement(document, "span");
1949
+ const modeSelect = createMarkedElement(document, "select");
1950
+ modeLabel.append(modeText, modeSelect);
1940
1951
  const providerLabel = createMarkedElement(document, "label");
1941
1952
  const providerText = createMarkedElement(document, "span");
1942
1953
  const providerSelect = createMarkedElement(document, "select");
@@ -1945,7 +1956,7 @@ function createAgentPanel(document, ai, localizer) {
1945
1956
  const modelText = createMarkedElement(document, "span");
1946
1957
  const modelSelect = createMarkedElement(document, "select");
1947
1958
  modelLabel.append(modelText, modelSelect);
1948
- selectors.append(providerLabel, modelLabel);
1959
+ selectors.append(modeLabel, providerLabel, modelLabel);
1949
1960
  const consent = createMarkedElement(document, "label");
1950
1961
  consent.className = "spotpatch-consent";
1951
1962
  const consentCheckbox = createMarkedElement(document, "input");
@@ -2012,8 +2023,8 @@ function createAgentPanel(document, ai, localizer) {
2012
2023
  const revertButton = createButton(document, messages.agent.revert);
2013
2024
  const resetButton = createButton(document, messages.agent.revise);
2014
2025
  const providers = ai.enabled ? ai.providers : [];
2015
- const trustedFastMode = ai.enabled && ai.applyMode === "trusted-auto";
2016
- consent.classList.toggle("spotpatch-trusted-consent", trustedFastMode);
2026
+ const trustedFastModeAvailable = ai.enabled && ai.applyMode === "trusted-auto";
2027
+ const configuredApplyMode = ai.enabled ? ai.applyMode : "review";
2017
2028
  const providerById = new Map(providers.map((provider) => [provider.id, provider]));
2018
2029
  let contextReady = false;
2019
2030
  let editingEnabled = true;
@@ -2037,14 +2048,42 @@ function createAgentPanel(document, ai, localizer) {
2037
2048
  if (ai.enabled) {
2038
2049
  providerSelect.value = ai.defaultProvider;
2039
2050
  }
2051
+ let reviewOption;
2052
+ let trustedOption;
2053
+ let autoOption;
2054
+ if (configuredApplyMode === "auto") {
2055
+ autoOption = addOption(document, modeSelect, "auto", messages.agent.autoGated);
2056
+ } else {
2057
+ reviewOption = addOption(document, modeSelect, "review", messages.agent.review);
2058
+ if (trustedFastModeAvailable) {
2059
+ trustedOption = addOption(
2060
+ document,
2061
+ modeSelect,
2062
+ "trusted-auto",
2063
+ messages.agent.trustedFast
2064
+ );
2065
+ }
2066
+ }
2067
+ const defaultApplyMode = trustedFastModeAvailable ? "review" : configuredApplyMode;
2068
+ modeSelect.value = defaultApplyMode;
2069
+ modeLabel.hidden = !trustedFastModeAvailable;
2070
+ const selectedApplyMode = () => modeSelect.value === "trusted-auto" ? "trusted-auto" : defaultApplyMode;
2071
+ const trustedFastMode = () => selectedApplyMode() === "trusted-auto";
2040
2072
  const selectedProvider = () => providerById.get(providerSelect.value);
2041
2073
  const consentMessage = (provider) => {
2042
2074
  if (provider === void 0) {
2043
2075
  return messages.agent.providerUnavailable;
2044
2076
  }
2045
- return trustedFastMode ? messages.agent.trustedFastConsent(provider.label) : messages.agent.consent(provider.label);
2077
+ return trustedFastMode() ? messages.agent.trustedFastConsent(provider.label) : messages.agent.consent(provider.label);
2078
+ };
2079
+ const localChangesConsentGranted = () => trustedFastMode() ? consentCheckbox.checked : workspaceConsentCheckbox.checked;
2080
+ const renderMode = () => {
2081
+ const trusted = trustedFastMode();
2082
+ consent.classList.toggle("spotpatch-trusted-consent", trusted);
2083
+ badge.textContent = trusted ? messages.agent.trustedFast : configuredApplyMode === "auto" ? messages.agent.autoGated : messages.agent.review;
2084
+ consentText.textContent = consentMessage(selectedProvider());
2085
+ workspaceConsent.hidden = trusted || latestWorkspaceState !== "consent-required";
2046
2086
  };
2047
- const localChangesConsentGranted = () => trustedFastMode ? consentCheckbox.checked : workspaceConsentCheckbox.checked;
2048
2087
  const populateModels = () => {
2049
2088
  const provider = selectedProvider();
2050
2089
  modelSelect.replaceChildren();
@@ -2111,7 +2150,14 @@ function createAgentPanel(document, ai, localizer) {
2111
2150
  capabilityReady = false;
2112
2151
  refreshActions();
2113
2152
  }
2153
+ function handleModeChange() {
2154
+ consentCheckbox.checked = false;
2155
+ workspaceConsentCheckbox.checked = false;
2156
+ renderMode();
2157
+ refreshActions();
2158
+ }
2114
2159
  populateModels();
2160
+ modeSelect.addEventListener("change", handleModeChange);
2115
2161
  providerSelect.addEventListener("change", handleProviderChange);
2116
2162
  modelSelect.addEventListener("change", handleModelChange);
2117
2163
  consentCheckbox.addEventListener("change", refreshActions);
@@ -2165,7 +2211,11 @@ function createAgentPanel(document, ai, localizer) {
2165
2211
  function applyMessages() {
2166
2212
  messages = localizer.messages();
2167
2213
  title.textContent = messages.agent.title;
2168
- badge.textContent = trustedFastMode ? messages.agent.trustedFast : ai.enabled && ai.applyMode === "auto" ? messages.agent.autoGated : messages.agent.review;
2214
+ modeText.textContent = messages.agent.mode;
2215
+ if (reviewOption !== void 0) reviewOption.textContent = messages.agent.review;
2216
+ if (trustedOption !== void 0)
2217
+ trustedOption.textContent = messages.agent.trustedFast;
2218
+ if (autoOption !== void 0) autoOption.textContent = messages.agent.autoGated;
2169
2219
  providerText.textContent = messages.agent.provider;
2170
2220
  modelText.textContent = messages.agent.model;
2171
2221
  providerSelect.setAttribute("aria-label", messages.agent.providerAriaLabel);
@@ -2177,8 +2227,7 @@ function createAgentPanel(document, ai, localizer) {
2177
2227
  applyButton.textContent = messages.agent.apply;
2178
2228
  revertButton.textContent = messages.agent.revert;
2179
2229
  resetButton.textContent = messages.agent.revise;
2180
- const provider = selectedProvider();
2181
- consentText.textContent = consentMessage(provider);
2230
+ renderMode();
2182
2231
  if (latestCapabilityState === "idle") {
2183
2232
  capability.textContent = messages.agent.connectionNotTested;
2184
2233
  } else if (latestCapabilityState === "probing") {
@@ -2200,6 +2249,7 @@ function createAgentPanel(document, ai, localizer) {
2200
2249
  applyMessages();
2201
2250
  return Object.freeze({
2202
2251
  root,
2252
+ modeSelect,
2203
2253
  providerSelect,
2204
2254
  modelSelect,
2205
2255
  consentCheckbox,
@@ -2222,6 +2272,7 @@ function createAgentPanel(document, ai, localizer) {
2222
2272
  (candidate) => candidate.id === modelSelect.value
2223
2273
  );
2224
2274
  return provider === void 0 || model === void 0 ? void 0 : Object.freeze({
2275
+ applyMode: selectedApplyMode(),
2225
2276
  providerProfileId: provider.id,
2226
2277
  modelProfileId: model.id
2227
2278
  });
@@ -2242,7 +2293,7 @@ function createAgentPanel(document, ai, localizer) {
2242
2293
  latestWorkspaceErrorCode = errorCode ?? snapshot?.errorCode;
2243
2294
  workspace.dataset.state = state;
2244
2295
  if (state !== "checking") {
2245
- workspaceConsent.hidden = trustedFastMode || state !== "consent-required";
2296
+ workspaceConsent.hidden = trustedFastMode() || state !== "consent-required";
2246
2297
  }
2247
2298
  if (state === "idle" || state === "ready" || state === "blocked") {
2248
2299
  workspaceConsentCheckbox.checked = false;
@@ -2256,6 +2307,7 @@ function createAgentPanel(document, ai, localizer) {
2256
2307
  job.hidden = false;
2257
2308
  providerSelect.disabled = true;
2258
2309
  modelSelect.disabled = true;
2310
+ modeSelect.disabled = true;
2259
2311
  consentCheckbox.disabled = true;
2260
2312
  workspaceConsentCheckbox.disabled = true;
2261
2313
  latestSnapshot = snapshot;
@@ -2274,6 +2326,7 @@ function createAgentPanel(document, ai, localizer) {
2274
2326
  job.hidden = true;
2275
2327
  providerSelect.disabled = false;
2276
2328
  modelSelect.disabled = false;
2329
+ modeSelect.disabled = false;
2277
2330
  consentCheckbox.disabled = false;
2278
2331
  workspaceConsentCheckbox.disabled = false;
2279
2332
  activity.replaceChildren();
@@ -2292,6 +2345,7 @@ function createAgentPanel(document, ai, localizer) {
2292
2345
  editingEnabled = enabled;
2293
2346
  providerSelect.disabled = !enabled || jobPresented;
2294
2347
  modelSelect.disabled = !enabled || jobPresented;
2348
+ modeSelect.disabled = !enabled || jobPresented;
2295
2349
  consentCheckbox.disabled = !enabled || jobPresented;
2296
2350
  workspaceConsentCheckbox.disabled = !enabled || jobPresented;
2297
2351
  refreshActions();
@@ -2314,6 +2368,7 @@ function createAgentPanel(document, ai, localizer) {
2314
2368
  unsubscribeLocale();
2315
2369
  providerSelect.removeEventListener("change", handleProviderChange);
2316
2370
  modelSelect.removeEventListener("change", handleModelChange);
2371
+ modeSelect.removeEventListener("change", handleModeChange);
2317
2372
  consentCheckbox.removeEventListener("change", refreshActions);
2318
2373
  workspaceConsentCheckbox.removeEventListener("change", refreshActions);
2319
2374
  }
@@ -2717,6 +2772,7 @@ var UI_MESSAGES = Object.freeze({
2717
2772
  }),
2718
2773
  agent: Object.freeze({
2719
2774
  title: "AI code agent",
2775
+ mode: "Execution mode",
2720
2776
  review: "Review",
2721
2777
  autoGated: "Auto gated",
2722
2778
  trustedFast: "Trusted fast",
@@ -2854,6 +2910,7 @@ var UI_MESSAGES = Object.freeze({
2854
2910
  }),
2855
2911
  agent: Object.freeze({
2856
2912
  title: "AI \u4EE3\u7801 Agent",
2913
+ mode: "\u6267\u884C\u65B9\u5F0F",
2857
2914
  review: "\u5BA1\u9605\u6A21\u5F0F",
2858
2915
  autoGated: "\u53D7\u63A7\u81EA\u52A8\u6A21\u5F0F",
2859
2916
  trustedFast: "\u53EF\u4FE1\u5FEB\u901F\u6A21\u5F0F",
@@ -4218,6 +4275,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4218
4275
  closeButton,
4219
4276
  agentProviderSelect: agentPanel.providerSelect,
4220
4277
  agentModelSelect: agentPanel.modelSelect,
4278
+ agentModeSelect: agentPanel.modeSelect,
4221
4279
  agentConsentCheckbox: agentPanel.consentCheckbox,
4222
4280
  agentWorkspaceConsentCheckbox: agentPanel.workspaceConsentCheckbox,
4223
4281
  agentTestButton: agentPanel.testButton,
@@ -4459,6 +4517,7 @@ function createAgentWorkflow(options) {
4459
4517
  let appliedDuringCurrentJob = false;
4460
4518
  let actionPending = false;
4461
4519
  const selectedProfiles = () => options.view.readAgentSelection();
4520
+ const consentKey = (selection) => `${selection.providerProfileId}:${selection.applyMode}`;
4462
4521
  const refreshWorkspaceHealth = async (workflowRevision) => {
4463
4522
  options.view.renderAgentWorkspaceHealth("checking");
4464
4523
  try {
@@ -4496,9 +4555,7 @@ function createAgentWorkflow(options) {
4496
4555
  );
4497
4556
  return;
4498
4557
  }
4499
- options.view.setAgentProviderConsent(
4500
- providerConsents.has(selection.providerProfileId)
4501
- );
4558
+ options.view.setAgentProviderConsent(providerConsents.has(consentKey(selection)));
4502
4559
  const cached = capabilities.get(
4503
4560
  capabilityKey(selection.providerProfileId, selection.modelProfileId)
4504
4561
  );
@@ -4666,9 +4723,9 @@ function createAgentWorkflow(options) {
4666
4723
  return;
4667
4724
  }
4668
4725
  if (options.view.agentConsentGranted()) {
4669
- providerConsents.add(selection.providerProfileId);
4726
+ providerConsents.add(consentKey(selection));
4670
4727
  } else {
4671
- providerConsents.delete(selection.providerProfileId);
4728
+ providerConsents.delete(consentKey(selection));
4672
4729
  }
4673
4730
  },
4674
4731
  disposeSelection() {
@@ -4708,7 +4765,6 @@ function createAgentWorkflow(options) {
4708
4765
  if (!options.ai.enabled || snapshot !== void 0) {
4709
4766
  return;
4710
4767
  }
4711
- const trustedFastMode = options.ai.applyMode === "trusted-auto";
4712
4768
  const selection = selectedProfiles();
4713
4769
  const annotation = options.getAnnotation();
4714
4770
  if (selection === void 0 || annotation === void 0) {
@@ -4721,7 +4777,7 @@ function createAgentWorkflow(options) {
4721
4777
  options.view.announce(options.view.messages().agent.consentRequired);
4722
4778
  return;
4723
4779
  }
4724
- providerConsents.add(selection.providerProfileId);
4780
+ providerConsents.add(consentKey(selection));
4725
4781
  const workflowRevision = ++revision;
4726
4782
  options.view.setAgentEditingEnabled(false);
4727
4783
  void refreshWorkspaceHealth(workflowRevision).then(async (health) => {
@@ -4738,10 +4794,11 @@ function createAgentWorkflow(options) {
4738
4794
  }
4739
4795
  const created = await options.api.createAgentJob({
4740
4796
  annotation,
4797
+ applyMode: selection.applyMode,
4741
4798
  providerProfileId: selection.providerProfileId,
4742
4799
  modelProfileId: selection.modelProfileId,
4743
4800
  providerDataConsent: true,
4744
- ...trustedFastMode ? { trustedFastModeConsent: true } : {},
4801
+ ...selection.applyMode === "trusted-auto" ? { trustedFastModeConsent: true } : {},
4745
4802
  workingTreeMode: health.state === "consent-required" ? "include-local-changes" : "require-clean"
4746
4803
  });
4747
4804
  if (workflowRevision !== revision) {
@@ -5638,6 +5695,10 @@ ${summary}`;
5638
5695
  "change",
5639
5696
  agentWorkflow.providerOrModelChanged
5640
5697
  );
5698
+ view.agentModeSelect.addEventListener(
5699
+ "change",
5700
+ agentWorkflow.providerOrModelChanged
5701
+ );
5641
5702
  view.agentConsentCheckbox.addEventListener("change", agentWorkflow.consentChanged);
5642
5703
  view.agentTestButton.addEventListener("click", agentWorkflow.testCapability);
5643
5704
  view.agentRunButton.addEventListener("click", agentWorkflow.run);
@@ -5704,6 +5765,10 @@ ${summary}`;
5704
5765
  "change",
5705
5766
  agentWorkflow.providerOrModelChanged
5706
5767
  );
5768
+ view.agentModeSelect.removeEventListener(
5769
+ "change",
5770
+ agentWorkflow.providerOrModelChanged
5771
+ );
5707
5772
  view.agentConsentCheckbox.removeEventListener(
5708
5773
  "change",
5709
5774
  agentWorkflow.consentChanged