@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.js CHANGED
@@ -1725,7 +1725,8 @@ var AGENT_PANEL_STYLES = `
1725
1725
  font-weight: 650;
1726
1726
  }
1727
1727
  .spotpatch-agent-setup { padding: 12px; }
1728
- .spotpatch-agent-selectors { display: grid; grid-template-columns: 1fr; gap: 10px; }
1728
+ .spotpatch-agent-selectors { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
1729
+ .spotpatch-agent-mode { grid-column: 1 / -1; }
1729
1730
  .spotpatch-agent-selectors label { min-width: 0; color: var(--spotpatch-text-secondary); font-size: 11.5px; font-weight: 580; }
1730
1731
  .spotpatch-agent select {
1731
1732
  box-sizing: border-box;
@@ -1910,12 +1911,17 @@ var AGENT_PANEL_STYLES = `
1910
1911
  white-space: pre;
1911
1912
  user-select: text;
1912
1913
  }
1914
+ @media (max-width: 520px) {
1915
+ .spotpatch-agent-selectors { grid-template-columns: 1fr; }
1916
+ .spotpatch-agent-mode { grid-column: auto; }
1917
+ }
1913
1918
  `;
1914
1919
  function addOption(document, select, value, label) {
1915
1920
  const option = document.createElement("option");
1916
1921
  option.value = value;
1917
1922
  option.textContent = label;
1918
1923
  select.append(option);
1924
+ return option;
1919
1925
  }
1920
1926
  function createAgentPanel(document, ai, localizer) {
1921
1927
  let messages = localizer.messages();
@@ -1933,6 +1939,11 @@ function createAgentPanel(document, ai, localizer) {
1933
1939
  setup.className = "spotpatch-agent-setup";
1934
1940
  const selectors = createMarkedElement(document, "div");
1935
1941
  selectors.className = "spotpatch-agent-selectors";
1942
+ const modeLabel = createMarkedElement(document, "label");
1943
+ modeLabel.className = "spotpatch-agent-mode";
1944
+ const modeText = createMarkedElement(document, "span");
1945
+ const modeSelect = createMarkedElement(document, "select");
1946
+ modeLabel.append(modeText, modeSelect);
1936
1947
  const providerLabel = createMarkedElement(document, "label");
1937
1948
  const providerText = createMarkedElement(document, "span");
1938
1949
  const providerSelect = createMarkedElement(document, "select");
@@ -1941,7 +1952,7 @@ function createAgentPanel(document, ai, localizer) {
1941
1952
  const modelText = createMarkedElement(document, "span");
1942
1953
  const modelSelect = createMarkedElement(document, "select");
1943
1954
  modelLabel.append(modelText, modelSelect);
1944
- selectors.append(providerLabel, modelLabel);
1955
+ selectors.append(modeLabel, providerLabel, modelLabel);
1945
1956
  const consent = createMarkedElement(document, "label");
1946
1957
  consent.className = "spotpatch-consent";
1947
1958
  const consentCheckbox = createMarkedElement(document, "input");
@@ -2008,8 +2019,8 @@ function createAgentPanel(document, ai, localizer) {
2008
2019
  const revertButton = createButton(document, messages.agent.revert);
2009
2020
  const resetButton = createButton(document, messages.agent.revise);
2010
2021
  const providers = ai.enabled ? ai.providers : [];
2011
- const trustedFastMode = ai.enabled && ai.applyMode === "trusted-auto";
2012
- consent.classList.toggle("spotpatch-trusted-consent", trustedFastMode);
2022
+ const trustedFastModeAvailable = ai.enabled && ai.applyMode === "trusted-auto";
2023
+ const configuredApplyMode = ai.enabled ? ai.applyMode : "review";
2013
2024
  const providerById = new Map(providers.map((provider) => [provider.id, provider]));
2014
2025
  let contextReady = false;
2015
2026
  let editingEnabled = true;
@@ -2033,14 +2044,42 @@ function createAgentPanel(document, ai, localizer) {
2033
2044
  if (ai.enabled) {
2034
2045
  providerSelect.value = ai.defaultProvider;
2035
2046
  }
2047
+ let reviewOption;
2048
+ let trustedOption;
2049
+ let autoOption;
2050
+ if (configuredApplyMode === "auto") {
2051
+ autoOption = addOption(document, modeSelect, "auto", messages.agent.autoGated);
2052
+ } else {
2053
+ reviewOption = addOption(document, modeSelect, "review", messages.agent.review);
2054
+ if (trustedFastModeAvailable) {
2055
+ trustedOption = addOption(
2056
+ document,
2057
+ modeSelect,
2058
+ "trusted-auto",
2059
+ messages.agent.trustedFast
2060
+ );
2061
+ }
2062
+ }
2063
+ const defaultApplyMode = trustedFastModeAvailable ? "review" : configuredApplyMode;
2064
+ modeSelect.value = defaultApplyMode;
2065
+ modeLabel.hidden = !trustedFastModeAvailable;
2066
+ const selectedApplyMode = () => modeSelect.value === "trusted-auto" ? "trusted-auto" : defaultApplyMode;
2067
+ const trustedFastMode = () => selectedApplyMode() === "trusted-auto";
2036
2068
  const selectedProvider = () => providerById.get(providerSelect.value);
2037
2069
  const consentMessage = (provider) => {
2038
2070
  if (provider === void 0) {
2039
2071
  return messages.agent.providerUnavailable;
2040
2072
  }
2041
- return trustedFastMode ? messages.agent.trustedFastConsent(provider.label) : messages.agent.consent(provider.label);
2073
+ return trustedFastMode() ? messages.agent.trustedFastConsent(provider.label) : messages.agent.consent(provider.label);
2074
+ };
2075
+ const localChangesConsentGranted = () => trustedFastMode() ? consentCheckbox.checked : workspaceConsentCheckbox.checked;
2076
+ const renderMode = () => {
2077
+ const trusted = trustedFastMode();
2078
+ consent.classList.toggle("spotpatch-trusted-consent", trusted);
2079
+ badge.textContent = trusted ? messages.agent.trustedFast : configuredApplyMode === "auto" ? messages.agent.autoGated : messages.agent.review;
2080
+ consentText.textContent = consentMessage(selectedProvider());
2081
+ workspaceConsent.hidden = trusted || latestWorkspaceState !== "consent-required";
2042
2082
  };
2043
- const localChangesConsentGranted = () => trustedFastMode ? consentCheckbox.checked : workspaceConsentCheckbox.checked;
2044
2083
  const populateModels = () => {
2045
2084
  const provider = selectedProvider();
2046
2085
  modelSelect.replaceChildren();
@@ -2107,7 +2146,14 @@ function createAgentPanel(document, ai, localizer) {
2107
2146
  capabilityReady = false;
2108
2147
  refreshActions();
2109
2148
  }
2149
+ function handleModeChange() {
2150
+ consentCheckbox.checked = false;
2151
+ workspaceConsentCheckbox.checked = false;
2152
+ renderMode();
2153
+ refreshActions();
2154
+ }
2110
2155
  populateModels();
2156
+ modeSelect.addEventListener("change", handleModeChange);
2111
2157
  providerSelect.addEventListener("change", handleProviderChange);
2112
2158
  modelSelect.addEventListener("change", handleModelChange);
2113
2159
  consentCheckbox.addEventListener("change", refreshActions);
@@ -2161,7 +2207,11 @@ function createAgentPanel(document, ai, localizer) {
2161
2207
  function applyMessages() {
2162
2208
  messages = localizer.messages();
2163
2209
  title.textContent = messages.agent.title;
2164
- badge.textContent = trustedFastMode ? messages.agent.trustedFast : ai.enabled && ai.applyMode === "auto" ? messages.agent.autoGated : messages.agent.review;
2210
+ modeText.textContent = messages.agent.mode;
2211
+ if (reviewOption !== void 0) reviewOption.textContent = messages.agent.review;
2212
+ if (trustedOption !== void 0)
2213
+ trustedOption.textContent = messages.agent.trustedFast;
2214
+ if (autoOption !== void 0) autoOption.textContent = messages.agent.autoGated;
2165
2215
  providerText.textContent = messages.agent.provider;
2166
2216
  modelText.textContent = messages.agent.model;
2167
2217
  providerSelect.setAttribute("aria-label", messages.agent.providerAriaLabel);
@@ -2173,8 +2223,7 @@ function createAgentPanel(document, ai, localizer) {
2173
2223
  applyButton.textContent = messages.agent.apply;
2174
2224
  revertButton.textContent = messages.agent.revert;
2175
2225
  resetButton.textContent = messages.agent.revise;
2176
- const provider = selectedProvider();
2177
- consentText.textContent = consentMessage(provider);
2226
+ renderMode();
2178
2227
  if (latestCapabilityState === "idle") {
2179
2228
  capability.textContent = messages.agent.connectionNotTested;
2180
2229
  } else if (latestCapabilityState === "probing") {
@@ -2196,6 +2245,7 @@ function createAgentPanel(document, ai, localizer) {
2196
2245
  applyMessages();
2197
2246
  return Object.freeze({
2198
2247
  root,
2248
+ modeSelect,
2199
2249
  providerSelect,
2200
2250
  modelSelect,
2201
2251
  consentCheckbox,
@@ -2218,6 +2268,7 @@ function createAgentPanel(document, ai, localizer) {
2218
2268
  (candidate) => candidate.id === modelSelect.value
2219
2269
  );
2220
2270
  return provider === void 0 || model === void 0 ? void 0 : Object.freeze({
2271
+ applyMode: selectedApplyMode(),
2221
2272
  providerProfileId: provider.id,
2222
2273
  modelProfileId: model.id
2223
2274
  });
@@ -2238,7 +2289,7 @@ function createAgentPanel(document, ai, localizer) {
2238
2289
  latestWorkspaceErrorCode = errorCode ?? snapshot?.errorCode;
2239
2290
  workspace.dataset.state = state;
2240
2291
  if (state !== "checking") {
2241
- workspaceConsent.hidden = trustedFastMode || state !== "consent-required";
2292
+ workspaceConsent.hidden = trustedFastMode() || state !== "consent-required";
2242
2293
  }
2243
2294
  if (state === "idle" || state === "ready" || state === "blocked") {
2244
2295
  workspaceConsentCheckbox.checked = false;
@@ -2252,6 +2303,7 @@ function createAgentPanel(document, ai, localizer) {
2252
2303
  job.hidden = false;
2253
2304
  providerSelect.disabled = true;
2254
2305
  modelSelect.disabled = true;
2306
+ modeSelect.disabled = true;
2255
2307
  consentCheckbox.disabled = true;
2256
2308
  workspaceConsentCheckbox.disabled = true;
2257
2309
  latestSnapshot = snapshot;
@@ -2270,6 +2322,7 @@ function createAgentPanel(document, ai, localizer) {
2270
2322
  job.hidden = true;
2271
2323
  providerSelect.disabled = false;
2272
2324
  modelSelect.disabled = false;
2325
+ modeSelect.disabled = false;
2273
2326
  consentCheckbox.disabled = false;
2274
2327
  workspaceConsentCheckbox.disabled = false;
2275
2328
  activity.replaceChildren();
@@ -2288,6 +2341,7 @@ function createAgentPanel(document, ai, localizer) {
2288
2341
  editingEnabled = enabled;
2289
2342
  providerSelect.disabled = !enabled || jobPresented;
2290
2343
  modelSelect.disabled = !enabled || jobPresented;
2344
+ modeSelect.disabled = !enabled || jobPresented;
2291
2345
  consentCheckbox.disabled = !enabled || jobPresented;
2292
2346
  workspaceConsentCheckbox.disabled = !enabled || jobPresented;
2293
2347
  refreshActions();
@@ -2310,6 +2364,7 @@ function createAgentPanel(document, ai, localizer) {
2310
2364
  unsubscribeLocale();
2311
2365
  providerSelect.removeEventListener("change", handleProviderChange);
2312
2366
  modelSelect.removeEventListener("change", handleModelChange);
2367
+ modeSelect.removeEventListener("change", handleModeChange);
2313
2368
  consentCheckbox.removeEventListener("change", refreshActions);
2314
2369
  workspaceConsentCheckbox.removeEventListener("change", refreshActions);
2315
2370
  }
@@ -2715,6 +2770,7 @@ var UI_MESSAGES = Object.freeze({
2715
2770
  }),
2716
2771
  agent: Object.freeze({
2717
2772
  title: "AI code agent",
2773
+ mode: "Execution mode",
2718
2774
  review: "Review",
2719
2775
  autoGated: "Auto gated",
2720
2776
  trustedFast: "Trusted fast",
@@ -2852,6 +2908,7 @@ var UI_MESSAGES = Object.freeze({
2852
2908
  }),
2853
2909
  agent: Object.freeze({
2854
2910
  title: "AI \u4EE3\u7801 Agent",
2911
+ mode: "\u6267\u884C\u65B9\u5F0F",
2855
2912
  review: "\u5BA1\u9605\u6A21\u5F0F",
2856
2913
  autoGated: "\u53D7\u63A7\u81EA\u52A8\u6A21\u5F0F",
2857
2914
  trustedFast: "\u53EF\u4FE1\u5FEB\u901F\u6A21\u5F0F",
@@ -4216,6 +4273,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
4216
4273
  closeButton,
4217
4274
  agentProviderSelect: agentPanel.providerSelect,
4218
4275
  agentModelSelect: agentPanel.modelSelect,
4276
+ agentModeSelect: agentPanel.modeSelect,
4219
4277
  agentConsentCheckbox: agentPanel.consentCheckbox,
4220
4278
  agentWorkspaceConsentCheckbox: agentPanel.workspaceConsentCheckbox,
4221
4279
  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