@spotpatch/runtime 1.1.2 → 1.2.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 +266 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +266 -14
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -146,6 +146,35 @@ function isAgentCapabilitySnapshot(value) {
|
|
|
146
146
|
}
|
|
147
147
|
return isProfileId(value.providerProfileId) && isBoundedString(value.providerLabel, 100) && isProfileId(value.modelProfileId) && isBoundedString(value.modelLabel, 100) && (value.protocol === "responses" || value.protocol === "chat-completions") && typeof value.state === "string" && CAPABILITY_STATE_VALUES.has(value.state) && typeof value.authenticated === "boolean" && typeof value.modelAvailable === "boolean" && typeof value.toolCalling === "boolean" && typeof value.toolResultContinuation === "boolean" && typeof value.streaming === "boolean" && (value.checkedAt === void 0 || isIsoTimestamp(value.checkedAt)) && (value.errorCode === void 0 || isAgentErrorCode(value.errorCode));
|
|
148
148
|
}
|
|
149
|
+
function isAgentWorkspaceHealthSnapshot(value) {
|
|
150
|
+
if (!isRecord(value) || !hasOnlyKeys(value, [
|
|
151
|
+
"state",
|
|
152
|
+
"checkedAt",
|
|
153
|
+
"changes",
|
|
154
|
+
"canIncludeLocalChanges",
|
|
155
|
+
"errorCode"
|
|
156
|
+
]) || value.state !== "ready" && value.state !== "consent-required" && value.state !== "blocked" || !isIsoTimestamp(value.checkedAt) || typeof value.canIncludeLocalChanges !== "boolean" || value.errorCode !== void 0 && !isAgentErrorCode(value.errorCode) || !isRecord(value.changes) || !hasOnlyKeys(value.changes, [
|
|
157
|
+
"staged",
|
|
158
|
+
"unstaged",
|
|
159
|
+
"untracked",
|
|
160
|
+
"conflicted",
|
|
161
|
+
"total"
|
|
162
|
+
])) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
const changes = value.changes;
|
|
166
|
+
const { staged, unstaged, untracked, conflicted, total } = changes;
|
|
167
|
+
if (!isNonnegativeInteger(staged) || !isNonnegativeInteger(unstaged) || !isNonnegativeInteger(untracked) || !isNonnegativeInteger(conflicted) || !isNonnegativeInteger(total) || total < staged || total < unstaged || total < untracked || total < conflicted || total > staged + unstaged + untracked) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
if (value.state === "ready") {
|
|
171
|
+
return total === 0 && !value.canIncludeLocalChanges && value.errorCode === void 0;
|
|
172
|
+
}
|
|
173
|
+
if (value.state === "consent-required") {
|
|
174
|
+
return total > 0 && conflicted === 0 && value.canIncludeLocalChanges && value.errorCode === void 0;
|
|
175
|
+
}
|
|
176
|
+
return !value.canIncludeLocalChanges && value.errorCode !== void 0;
|
|
177
|
+
}
|
|
149
178
|
function isAgentJobSnapshot(value) {
|
|
150
179
|
if (!isRecord(value) || !hasOnlyKeys(value, [
|
|
151
180
|
"jobId",
|
|
@@ -486,6 +515,17 @@ function createRuntimeApi(options) {
|
|
|
486
515
|
request
|
|
487
516
|
);
|
|
488
517
|
},
|
|
518
|
+
async agentWorkspaceHealth() {
|
|
519
|
+
const data = await requestJson(
|
|
520
|
+
SPOTPATCH_ENDPOINTS.agentWorkspaceHealth,
|
|
521
|
+
"POST",
|
|
522
|
+
emptyAction
|
|
523
|
+
);
|
|
524
|
+
if (!isAgentWorkspaceHealthSnapshot(data)) {
|
|
525
|
+
throw new RuntimeApiError();
|
|
526
|
+
}
|
|
527
|
+
return deepFreeze(data);
|
|
528
|
+
},
|
|
489
529
|
async createAgentJob(request) {
|
|
490
530
|
const serverRequest = omitBrowserCodeContext(request);
|
|
491
531
|
return parseJobSnapshot(
|
|
@@ -1563,15 +1603,62 @@ var AGENT_PANEL_STYLES = `
|
|
|
1563
1603
|
min-height: 46px;
|
|
1564
1604
|
margin-top: 7px;
|
|
1565
1605
|
border: 1px solid var(--spotpatch-border);
|
|
1566
|
-
border-radius:
|
|
1567
|
-
padding:
|
|
1606
|
+
border-radius: 12px;
|
|
1607
|
+
padding: 10px 38px 10px 13px;
|
|
1568
1608
|
color: #e8ebf2;
|
|
1569
1609
|
color-scheme: dark;
|
|
1570
|
-
background:
|
|
1610
|
+
background: linear-gradient(180deg, rgb(255 255 255 / 4%), rgb(255 255 255 / 2%));
|
|
1571
1611
|
font-size: 15px;
|
|
1612
|
+
font-weight: 560;
|
|
1613
|
+
line-height: 1.35;
|
|
1572
1614
|
outline: none;
|
|
1615
|
+
transition: 160ms ease;
|
|
1616
|
+
}
|
|
1617
|
+
.spotpatch-agent select:hover { border-color: rgb(148 163 184 / 38%); background-color: rgb(255 255 255 / 5%); }
|
|
1618
|
+
.spotpatch-agent select:focus-visible { border-color: rgb(139 124 247 / 76%); box-shadow: 0 0 0 3px rgb(109 93 246 / 18%); }
|
|
1619
|
+
.spotpatch-agent select option { min-height: 42px; color: #e8ebf2; background: #10151e; }
|
|
1620
|
+
@supports (appearance: base-select) {
|
|
1621
|
+
.spotpatch-agent select,
|
|
1622
|
+
::picker(select) { appearance: base-select; }
|
|
1623
|
+
.spotpatch-agent select { padding: 10px 13px; }
|
|
1624
|
+
.spotpatch-agent select::picker-icon {
|
|
1625
|
+
color: #9da6b5;
|
|
1626
|
+
transition: rotate 180ms cubic-bezier(.2, .8, .2, 1);
|
|
1627
|
+
}
|
|
1628
|
+
.spotpatch-agent select:open::picker-icon { rotate: 180deg; color: #c4b5fd; }
|
|
1629
|
+
.spotpatch-agent select::picker(select) {
|
|
1630
|
+
top: calc(anchor(bottom) + 7px);
|
|
1631
|
+
left: anchor(left);
|
|
1632
|
+
width: anchor-size(width);
|
|
1633
|
+
max-height: min(280px, 40vh);
|
|
1634
|
+
margin: 0;
|
|
1635
|
+
overflow: hidden;
|
|
1636
|
+
border: 1px solid rgb(139 124 247 / 28%);
|
|
1637
|
+
border-radius: 12px;
|
|
1638
|
+
padding: 6px;
|
|
1639
|
+
background: #10151e;
|
|
1640
|
+
box-shadow: 0 18px 50px rgb(0 0 0 / 38%);
|
|
1641
|
+
opacity: 0;
|
|
1642
|
+
transform: translateY(-5px) scale(.985);
|
|
1643
|
+
transition: opacity 150ms ease, transform 180ms cubic-bezier(.2, .8, .2, 1), overlay 180ms allow-discrete, display 180ms allow-discrete;
|
|
1644
|
+
}
|
|
1645
|
+
::picker(select):popover-open { opacity: 1; transform: translateY(0) scale(1); }
|
|
1646
|
+
@starting-style {
|
|
1647
|
+
::picker(select):popover-open { opacity: 0; transform: translateY(-5px) scale(.985); }
|
|
1648
|
+
}
|
|
1649
|
+
.spotpatch-agent select option {
|
|
1650
|
+
min-height: 42px;
|
|
1651
|
+
border-radius: 8px;
|
|
1652
|
+
padding: 10px 12px;
|
|
1653
|
+
color: #dfe4ee;
|
|
1654
|
+
background: transparent;
|
|
1655
|
+
cursor: pointer;
|
|
1656
|
+
}
|
|
1657
|
+
.spotpatch-agent select option:hover,
|
|
1658
|
+
.spotpatch-agent select option:focus { color: #fff; background: rgb(109 93 246 / 16%); }
|
|
1659
|
+
.spotpatch-agent select option:checked { color: #fff; background: rgb(109 93 246 / 24%); }
|
|
1660
|
+
.spotpatch-agent select option::checkmark { color: #8b7cf7; }
|
|
1573
1661
|
}
|
|
1574
|
-
.spotpatch-agent select option { color: #e8ebf2; background: #10151e; }
|
|
1575
1662
|
.spotpatch-agent select:focus-visible,
|
|
1576
1663
|
.spotpatch-consent input:focus-visible {
|
|
1577
1664
|
outline: 2px solid #8b7cf7;
|
|
@@ -1588,11 +1675,22 @@ var AGENT_PANEL_STYLES = `
|
|
|
1588
1675
|
line-height: 1.6;
|
|
1589
1676
|
}
|
|
1590
1677
|
.spotpatch-consent input { width: 16px; height: 16px; flex: none; margin: 3px 0 0; accent-color: var(--spotpatch-accent); }
|
|
1678
|
+
.spotpatch-workspace-consent {
|
|
1679
|
+
margin-top: 12px;
|
|
1680
|
+
border: 1px solid rgb(251 191 36 / 18%);
|
|
1681
|
+
border-radius: 10px;
|
|
1682
|
+
padding: 11px 12px;
|
|
1683
|
+
background: rgb(120 53 15 / 9%);
|
|
1684
|
+
}
|
|
1685
|
+
.spotpatch-workspace-consent strong { display: block; color: #fde68a; font-size: 13px; font-weight: 620; }
|
|
1686
|
+
.spotpatch-workspace-consent small { display: block; margin-top: 2px; color: #aeb6c4; font-size: 12px; line-height: 1.5; }
|
|
1687
|
+
.spotpatch-agent-health-list { display: grid; gap: 8px; margin-top: 14px; }
|
|
1688
|
+
.spotpatch-agent-workspace,
|
|
1591
1689
|
.spotpatch-agent-capability {
|
|
1592
1690
|
display: flex;
|
|
1593
1691
|
align-items: center;
|
|
1594
1692
|
gap: 8px;
|
|
1595
|
-
margin:
|
|
1693
|
+
margin: 0;
|
|
1596
1694
|
color: #929bab;
|
|
1597
1695
|
font-size: 13px;
|
|
1598
1696
|
}
|
|
@@ -1609,6 +1707,21 @@ var AGENT_PANEL_STYLES = `
|
|
|
1609
1707
|
.spotpatch-agent-capability[data-state="ready"]::before { background: var(--spotpatch-success); }
|
|
1610
1708
|
.spotpatch-agent-capability[data-state="error"] { color: #fecaca; }
|
|
1611
1709
|
.spotpatch-agent-capability[data-state="error"]::before { background: var(--spotpatch-danger); }
|
|
1710
|
+
.spotpatch-agent-workspace::before {
|
|
1711
|
+
width: 6px;
|
|
1712
|
+
height: 6px;
|
|
1713
|
+
flex: none;
|
|
1714
|
+
border-radius: 999px;
|
|
1715
|
+
background: #64748b;
|
|
1716
|
+
content: "";
|
|
1717
|
+
}
|
|
1718
|
+
.spotpatch-agent-workspace[data-state="checking"]::before { background: var(--spotpatch-warning); }
|
|
1719
|
+
.spotpatch-agent-workspace[data-state="ready"] { color: #a7f3d0; }
|
|
1720
|
+
.spotpatch-agent-workspace[data-state="ready"]::before { background: var(--spotpatch-success); }
|
|
1721
|
+
.spotpatch-agent-workspace[data-state="consent-required"] { color: #fde68a; }
|
|
1722
|
+
.spotpatch-agent-workspace[data-state="consent-required"]::before { background: #fbbf24; }
|
|
1723
|
+
.spotpatch-agent-workspace[data-state="blocked"] { color: #fecaca; }
|
|
1724
|
+
.spotpatch-agent-workspace[data-state="blocked"]::before { background: var(--spotpatch-danger); }
|
|
1612
1725
|
.spotpatch-agent-job { padding: 16px; }
|
|
1613
1726
|
.spotpatch-agent-job-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
|
1614
1727
|
.spotpatch-agent-model { min-width: 0; overflow: hidden; color: #d6dafe; font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -1697,10 +1810,26 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1697
1810
|
consentCheckbox.type = "checkbox";
|
|
1698
1811
|
const consentText = createMarkedElement(document, "span");
|
|
1699
1812
|
consent.append(consentCheckbox, consentText);
|
|
1813
|
+
const workspaceConsent = createMarkedElement(document, "label");
|
|
1814
|
+
workspaceConsent.className = "spotpatch-consent spotpatch-workspace-consent";
|
|
1815
|
+
workspaceConsent.hidden = true;
|
|
1816
|
+
const workspaceConsentCheckbox = createMarkedElement(document, "input");
|
|
1817
|
+
workspaceConsentCheckbox.type = "checkbox";
|
|
1818
|
+
const workspaceConsentContent = createMarkedElement(document, "span");
|
|
1819
|
+
const workspaceConsentTitle = createMarkedElement(document, "strong");
|
|
1820
|
+
const workspaceConsentHelp = createMarkedElement(document, "small");
|
|
1821
|
+
workspaceConsentContent.append(workspaceConsentTitle, workspaceConsentHelp);
|
|
1822
|
+
workspaceConsent.append(workspaceConsentCheckbox, workspaceConsentContent);
|
|
1823
|
+
const healthList = createMarkedElement(document, "div");
|
|
1824
|
+
healthList.className = "spotpatch-agent-health-list";
|
|
1825
|
+
const workspace = createMarkedElement(document, "p");
|
|
1826
|
+
workspace.className = "spotpatch-agent-workspace";
|
|
1827
|
+
workspace.dataset.state = "idle";
|
|
1700
1828
|
const capability = createMarkedElement(document, "p");
|
|
1701
1829
|
capability.className = "spotpatch-agent-capability";
|
|
1702
1830
|
capability.dataset.state = "idle";
|
|
1703
|
-
|
|
1831
|
+
healthList.append(workspace, capability);
|
|
1832
|
+
setup.append(selectors, consent, workspaceConsent, healthList);
|
|
1704
1833
|
const job = createMarkedElement(document, "div");
|
|
1705
1834
|
job.className = "spotpatch-agent-job";
|
|
1706
1835
|
job.hidden = true;
|
|
@@ -1759,6 +1888,9 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1759
1888
|
let latestCapabilityState = "idle";
|
|
1760
1889
|
let latestCapabilityMessage = messages.agent.connectionNotTested;
|
|
1761
1890
|
let latestCapabilityErrorCode;
|
|
1891
|
+
let latestWorkspaceState = "idle";
|
|
1892
|
+
let latestWorkspaceSnapshot;
|
|
1893
|
+
let latestWorkspaceErrorCode;
|
|
1762
1894
|
for (const provider of providers) {
|
|
1763
1895
|
addOption(document, providerSelect, provider.id, provider.label);
|
|
1764
1896
|
}
|
|
@@ -1786,7 +1918,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1786
1918
|
testButton.hidden = !setupVisible;
|
|
1787
1919
|
runButton.hidden = !setupVisible;
|
|
1788
1920
|
testButton.disabled = !editingEnabled || capabilityProbing || selectedProvider() === void 0;
|
|
1789
|
-
runButton.disabled = !editingEnabled || capabilityProbing || !contextReady || !consentCheckbox.checked || selectedProvider() === void 0 || modelSelect.value.length === 0;
|
|
1921
|
+
runButton.disabled = !editingEnabled || capabilityProbing || !contextReady || !consentCheckbox.checked || latestWorkspaceState === "idle" || latestWorkspaceState === "checking" || latestWorkspaceState === "blocked" || latestWorkspaceState === "consent-required" && !workspaceConsentCheckbox.checked || selectedProvider() === void 0 || modelSelect.value.length === 0;
|
|
1790
1922
|
if (!jobPresented || !selectionVisible) {
|
|
1791
1923
|
cancelButton.hidden = true;
|
|
1792
1924
|
applyButton.hidden = true;
|
|
@@ -1794,6 +1926,24 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1794
1926
|
resetButton.hidden = true;
|
|
1795
1927
|
}
|
|
1796
1928
|
};
|
|
1929
|
+
const renderWorkspaceMessage = () => {
|
|
1930
|
+
if (latestWorkspaceState === "idle") {
|
|
1931
|
+
workspace.textContent = messages.agent.workspaceNotChecked;
|
|
1932
|
+
} else if (latestWorkspaceState === "checking") {
|
|
1933
|
+
workspace.textContent = messages.agent.checkingWorkspace;
|
|
1934
|
+
} else if (latestWorkspaceState === "ready") {
|
|
1935
|
+
workspace.textContent = messages.agent.workspaceReady;
|
|
1936
|
+
} else if (latestWorkspaceState === "consent-required") {
|
|
1937
|
+
const changes = latestWorkspaceSnapshot?.changes;
|
|
1938
|
+
workspace.textContent = messages.agent.workspaceDirty(
|
|
1939
|
+
changes?.staged ?? 0,
|
|
1940
|
+
changes?.unstaged ?? 0,
|
|
1941
|
+
changes?.untracked ?? 0
|
|
1942
|
+
);
|
|
1943
|
+
} else {
|
|
1944
|
+
workspace.textContent = latestWorkspaceErrorCode === void 0 ? messages.errors.INTERNAL_ERROR : messages.errors[latestWorkspaceErrorCode];
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1797
1947
|
function handleProviderChange() {
|
|
1798
1948
|
populateModels();
|
|
1799
1949
|
consentCheckbox.checked = false;
|
|
@@ -1818,6 +1968,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1818
1968
|
providerSelect.addEventListener("change", handleProviderChange);
|
|
1819
1969
|
modelSelect.addEventListener("change", handleModelChange);
|
|
1820
1970
|
consentCheckbox.addEventListener("change", refreshActions);
|
|
1971
|
+
workspaceConsentCheckbox.addEventListener("change", refreshActions);
|
|
1821
1972
|
function renderCurrentJob() {
|
|
1822
1973
|
if (latestSnapshot === void 0) {
|
|
1823
1974
|
return;
|
|
@@ -1872,6 +2023,8 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1872
2023
|
modelText.textContent = messages.agent.model;
|
|
1873
2024
|
providerSelect.setAttribute("aria-label", messages.agent.providerAriaLabel);
|
|
1874
2025
|
modelSelect.setAttribute("aria-label", messages.agent.modelAriaLabel);
|
|
2026
|
+
workspaceConsentTitle.textContent = messages.agent.includeLocalChanges;
|
|
2027
|
+
workspaceConsentHelp.textContent = messages.agent.includeLocalChangesHelp;
|
|
1875
2028
|
diff.setAttribute("aria-label", messages.agent.diffAriaLabel);
|
|
1876
2029
|
testButton.textContent = messages.agent.testConnection;
|
|
1877
2030
|
applyButton.textContent = messages.agent.apply;
|
|
@@ -1892,6 +2045,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1892
2045
|
} else {
|
|
1893
2046
|
capability.textContent = latestCapabilityMessage;
|
|
1894
2047
|
}
|
|
2048
|
+
renderWorkspaceMessage();
|
|
1895
2049
|
refreshActions();
|
|
1896
2050
|
renderCurrentJob();
|
|
1897
2051
|
}
|
|
@@ -1902,6 +2056,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1902
2056
|
providerSelect,
|
|
1903
2057
|
modelSelect,
|
|
1904
2058
|
consentCheckbox,
|
|
2059
|
+
workspaceConsentCheckbox,
|
|
1905
2060
|
testButton,
|
|
1906
2061
|
runButton,
|
|
1907
2062
|
cancelButton,
|
|
@@ -1911,6 +2066,9 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1911
2066
|
consentGranted() {
|
|
1912
2067
|
return consentCheckbox.checked;
|
|
1913
2068
|
},
|
|
2069
|
+
workspaceConsentGranted() {
|
|
2070
|
+
return workspaceConsentCheckbox.checked;
|
|
2071
|
+
},
|
|
1914
2072
|
readSelection() {
|
|
1915
2073
|
const provider = selectedProvider();
|
|
1916
2074
|
const model = provider?.models.find(
|
|
@@ -1931,6 +2089,20 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1931
2089
|
capability.textContent = capabilitySnapshot?.state === "agent-ready" ? `${message} \xB7 ${messages.agent.toolsReady}` : message;
|
|
1932
2090
|
refreshActions();
|
|
1933
2091
|
},
|
|
2092
|
+
renderWorkspaceHealth(state, snapshot, errorCode) {
|
|
2093
|
+
latestWorkspaceState = state;
|
|
2094
|
+
latestWorkspaceSnapshot = snapshot;
|
|
2095
|
+
latestWorkspaceErrorCode = errorCode ?? snapshot?.errorCode;
|
|
2096
|
+
workspace.dataset.state = state;
|
|
2097
|
+
if (state !== "checking") {
|
|
2098
|
+
workspaceConsent.hidden = state !== "consent-required";
|
|
2099
|
+
}
|
|
2100
|
+
if (state === "idle" || state === "ready" || state === "blocked") {
|
|
2101
|
+
workspaceConsentCheckbox.checked = false;
|
|
2102
|
+
}
|
|
2103
|
+
renderWorkspaceMessage();
|
|
2104
|
+
refreshActions();
|
|
2105
|
+
},
|
|
1934
2106
|
renderJob(snapshot, result, activities, errorCode) {
|
|
1935
2107
|
jobPresented = true;
|
|
1936
2108
|
setup.hidden = true;
|
|
@@ -1938,6 +2110,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1938
2110
|
providerSelect.disabled = true;
|
|
1939
2111
|
modelSelect.disabled = true;
|
|
1940
2112
|
consentCheckbox.disabled = true;
|
|
2113
|
+
workspaceConsentCheckbox.disabled = true;
|
|
1941
2114
|
latestSnapshot = snapshot;
|
|
1942
2115
|
latestResult = result;
|
|
1943
2116
|
latestActivities = activities;
|
|
@@ -1955,6 +2128,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1955
2128
|
providerSelect.disabled = false;
|
|
1956
2129
|
modelSelect.disabled = false;
|
|
1957
2130
|
consentCheckbox.disabled = false;
|
|
2131
|
+
workspaceConsentCheckbox.disabled = false;
|
|
1958
2132
|
activity.replaceChildren();
|
|
1959
2133
|
files.replaceChildren();
|
|
1960
2134
|
checks.replaceChildren();
|
|
@@ -1972,6 +2146,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1972
2146
|
providerSelect.disabled = !enabled || jobPresented;
|
|
1973
2147
|
modelSelect.disabled = !enabled || jobPresented;
|
|
1974
2148
|
consentCheckbox.disabled = !enabled || jobPresented;
|
|
2149
|
+
workspaceConsentCheckbox.disabled = !enabled || jobPresented;
|
|
1975
2150
|
refreshActions();
|
|
1976
2151
|
},
|
|
1977
2152
|
setProviderConsent(granted) {
|
|
@@ -1993,6 +2168,7 @@ function createAgentPanel(document, ai, localizer) {
|
|
|
1993
2168
|
providerSelect.removeEventListener("change", handleProviderChange);
|
|
1994
2169
|
modelSelect.removeEventListener("change", handleModelChange);
|
|
1995
2170
|
consentCheckbox.removeEventListener("change", refreshActions);
|
|
2171
|
+
workspaceConsentCheckbox.removeEventListener("change", refreshActions);
|
|
1996
2172
|
}
|
|
1997
2173
|
});
|
|
1998
2174
|
}
|
|
@@ -2162,8 +2338,16 @@ var ERROR_MESSAGES_EN = Object.freeze({
|
|
|
2162
2338
|
[ERROR_CODES2.AGENT_BUSY]: "Another write Agent job is still active.",
|
|
2163
2339
|
[ERROR_CODES2.AGENT_LIMIT_EXCEEDED]: "The Agent stopped at a configured time, turn, output, or size limit.",
|
|
2164
2340
|
[ERROR_CODES2.AGENT_CANCELLED]: "The Agent job was cancelled.",
|
|
2165
|
-
[ERROR_CODES2.WORKTREE_DIRTY]: "
|
|
2341
|
+
[ERROR_CODES2.WORKTREE_DIRTY]: "Confirm inclusion of local changes before running AI.",
|
|
2342
|
+
[ERROR_CODES2.WORKTREE_NOT_REPOSITORY]: "Vite root must be an initialized Git repository root.",
|
|
2343
|
+
[ERROR_CODES2.WORKTREE_OPERATION_IN_PROGRESS]: "Finish the active merge, rebase, cherry-pick, or revert.",
|
|
2344
|
+
[ERROR_CODES2.WORKTREE_CONFLICTED]: "Resolve all Git conflicts before running AI.",
|
|
2345
|
+
[ERROR_CODES2.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "Reduce untracked files below the safe count and size limits.",
|
|
2346
|
+
[ERROR_CODES2.WORKTREE_UNTRACKED_UNSUPPORTED]: "An untracked path is missing, linked, or not a regular file.",
|
|
2347
|
+
[ERROR_CODES2.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "Local changes cannot be isolated safely.",
|
|
2166
2348
|
[ERROR_CODES2.TOOL_DENIED]: "A model tool request violated the local safety policy.",
|
|
2349
|
+
[ERROR_CODES2.TOOL_INPUT_INVALID]: "The model sent invalid tool arguments or reused a tool ID.",
|
|
2350
|
+
[ERROR_CODES2.TOOL_PATH_DENIED]: "The model requested a protected, linked, non-text, or external path.",
|
|
2167
2351
|
[ERROR_CODES2.PATCH_REJECTED]: "The proposed patch did not pass local policy.",
|
|
2168
2352
|
[ERROR_CODES2.VALIDATION_FAILED]: "Required project checks failed. The change cannot be applied.",
|
|
2169
2353
|
[ERROR_CODES2.APPLY_CONFLICT]: "Project files changed after the Agent baseline; no overwrite was performed.",
|
|
@@ -2187,8 +2371,16 @@ var ERROR_MESSAGES_ZH = Object.freeze({
|
|
|
2187
2371
|
[ERROR_CODES2.AGENT_BUSY]: "\u5F53\u524D\u9879\u76EE\u5DF2\u6709\u4E00\u4E2A\u5199\u5165\u4EFB\u52A1\u6B63\u5728\u8FD0\u884C\u3002",
|
|
2188
2372
|
[ERROR_CODES2.AGENT_LIMIT_EXCEEDED]: "Agent \u8FBE\u5230\u65F6\u95F4\u3001\u8F6E\u6B21\u3001\u8F93\u51FA\u6216\u53D8\u66F4\u89C4\u6A21\u9650\u5236\u3002",
|
|
2189
2373
|
[ERROR_CODES2.AGENT_CANCELLED]: "Agent \u4EFB\u52A1\u5DF2\u53D6\u6D88\u3002",
|
|
2190
|
-
[ERROR_CODES2.WORKTREE_DIRTY]: "\u8FD0\u884C AI \u524D\uFF0C\u8BF7\
|
|
2374
|
+
[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",
|
|
2375
|
+
[ERROR_CODES2.WORKTREE_NOT_REPOSITORY]: "Vite \u6839\u76EE\u5F55\u4E0D\u662F\u5DF2\u521D\u59CB\u5316 Git \u4ED3\u5E93\u7684\u9876\u5C42\u76EE\u5F55\u3002",
|
|
2376
|
+
[ERROR_CODES2.WORKTREE_OPERATION_IN_PROGRESS]: "\u8BF7\u5148\u5B8C\u6210\u5F53\u524D merge\u3001rebase\u3001cherry-pick \u6216 revert\uFF0C\u518D\u8FD0\u884C AI\u3002",
|
|
2377
|
+
[ERROR_CODES2.WORKTREE_CONFLICTED]: "\u8BF7\u5148\u89E3\u51B3\u5168\u90E8 Git \u51B2\u7A81\uFF0C\u518D\u8FD0\u884C AI\u3002",
|
|
2378
|
+
[ERROR_CODES2.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "\u672A\u8DDF\u8E2A\u6587\u4EF6\u8D85\u8FC7\u5B89\u5168\u6570\u91CF\u6216\u4F53\u79EF\u4E0A\u9650\uFF0C\u8BF7\u5148\u7CBE\u7B80\u3002",
|
|
2379
|
+
[ERROR_CODES2.WORKTREE_UNTRACKED_UNSUPPORTED]: "\u672A\u8DDF\u8E2A\u9879\u5DF2\u4E22\u5931\u3001\u662F\u7B26\u53F7\u94FE\u63A5\u6216\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u3002",
|
|
2380
|
+
[ERROR_CODES2.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "\u5F53\u524D\u672C\u5730\u4FEE\u6539\u65E0\u6CD5\u5B89\u5168\u9694\u79BB\u3002",
|
|
2191
2381
|
[ERROR_CODES2.TOOL_DENIED]: "\u6A21\u578B\u5DE5\u5177\u8BF7\u6C42\u8FDD\u53CD\u672C\u5730\u5B89\u5168\u7B56\u7565\u3002",
|
|
2382
|
+
[ERROR_CODES2.TOOL_INPUT_INVALID]: "\u6A21\u578B\u53D1\u9001\u4E86\u65E0\u6548\u5DE5\u5177\u53C2\u6570\uFF0C\u6216\u590D\u7528\u4E86\u5DE5\u5177\u8C03\u7528 ID\u3002",
|
|
2383
|
+
[ERROR_CODES2.TOOL_PATH_DENIED]: "\u6A21\u578B\u8BF7\u6C42\u4E86\u53D7\u4FDD\u62A4\u3001\u975E\u6587\u672C\u3001\u7B26\u53F7\u94FE\u63A5\u6216\u9879\u76EE\u5916\u8DEF\u5F84\u3002",
|
|
2192
2384
|
[ERROR_CODES2.PATCH_REJECTED]: "\u5EFA\u8BAE\u8865\u4E01\u672A\u901A\u8FC7\u672C\u5730\u7B56\u7565\u68C0\u67E5\u3002",
|
|
2193
2385
|
[ERROR_CODES2.VALIDATION_FAILED]: "\u9879\u76EE\u5FC5\u9700\u68C0\u67E5\u5931\u8D25\uFF0C\u4E0D\u80FD\u5E94\u7528\u672C\u6B21\u53D8\u66F4\u3002",
|
|
2194
2386
|
[ERROR_CODES2.APPLY_CONFLICT]: "Agent \u5EFA\u7ACB\u57FA\u7EBF\u540E\u9879\u76EE\u6587\u4EF6\u5DF2\u53D8\u5316\uFF0C\u672A\u6267\u884C\u8986\u76D6\u3002",
|
|
@@ -2353,6 +2545,13 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2353
2545
|
providerUnavailable: "Provider configuration is unavailable.",
|
|
2354
2546
|
consent: (provider) => `I understand selected context and allowed source may be sent to ${provider}; its data policy is my responsibility.`,
|
|
2355
2547
|
connectionNotTested: "Connection not tested",
|
|
2548
|
+
workspaceNotChecked: "Local workspace not checked",
|
|
2549
|
+
checkingWorkspace: "Checking Git workspace and isolated execution\u2026",
|
|
2550
|
+
workspaceReady: "Local workspace is ready for isolated execution",
|
|
2551
|
+
workspaceDirty: (staged, unstaged, untracked) => `Local changes found \xB7 ${String(staged)} staged \xB7 ${String(unstaged)} unstaged \xB7 ${String(untracked)} untracked`,
|
|
2552
|
+
includeLocalChanges: "Allow the Agent to continue from my current local changes",
|
|
2553
|
+
includeLocalChangesHelp: "The Agent may edit these files. SpotPatch preserves the baseline and applies or reverts only the Agent delta.",
|
|
2554
|
+
localChangesConsentRequired: "Confirm inclusion of current local changes before running AI.",
|
|
2356
2555
|
capabilityVerified: "Agent capability verified",
|
|
2357
2556
|
capabilityVerifiedAnnouncement: "AI provider capability verified.",
|
|
2358
2557
|
testingCapability: "Testing authentication, tools, continuation, and streaming\u2026",
|
|
@@ -2361,7 +2560,7 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2361
2560
|
reverting: "Reverting the applied Agent change.",
|
|
2362
2561
|
consentRequired: "Confirm remote provider data transmission before running AI.",
|
|
2363
2562
|
toolsReady: "tools and streaming ready",
|
|
2364
|
-
testConnection: "
|
|
2563
|
+
testConnection: "Check environment",
|
|
2365
2564
|
verifyAndRun: "Verify & run",
|
|
2366
2565
|
verifying: "Verifying\u2026",
|
|
2367
2566
|
run: "Run AI",
|
|
@@ -2482,6 +2681,13 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2482
2681
|
providerUnavailable: "\u6A21\u578B\u670D\u52A1\u914D\u7F6E\u4E0D\u53EF\u7528\u3002",
|
|
2483
2682
|
consent: (provider) => `\u6211\u4E86\u89E3\u9009\u4E2D\u4E0A\u4E0B\u6587\u4E0E\u83B7\u51C6\u6E90\u7801\u53EF\u80FD\u53D1\u9001\u5230 ${provider}\uFF0C\u5E76\u81EA\u884C\u8D1F\u8D23\u5176\u6570\u636E\u7B56\u7565\u3002`,
|
|
2484
2683
|
connectionNotTested: "\u5C1A\u672A\u6D4B\u8BD5\u8FDE\u63A5",
|
|
2684
|
+
workspaceNotChecked: "\u5C1A\u672A\u68C0\u67E5\u672C\u5730\u5DE5\u4F5C\u533A",
|
|
2685
|
+
checkingWorkspace: "\u6B63\u5728\u68C0\u67E5 Git \u5DE5\u4F5C\u533A\u4E0E\u9694\u79BB\u6267\u884C\u73AF\u5883\u2026\u2026",
|
|
2686
|
+
workspaceReady: "\u672C\u5730\u5DE5\u4F5C\u533A\u5DF2\u6EE1\u8DB3\u9694\u79BB\u6267\u884C\u6761\u4EF6",
|
|
2687
|
+
workspaceDirty: (staged, unstaged, untracked) => `\u53D1\u73B0\u672C\u5730\u4FEE\u6539 \xB7 \u6682\u5B58 ${String(staged)} \xB7 \u672A\u6682\u5B58 ${String(unstaged)} \xB7 \u672A\u8DDF\u8E2A ${String(untracked)}`,
|
|
2688
|
+
includeLocalChanges: "\u5141\u8BB8 Agent \u57FA\u4E8E\u6211\u5F53\u524D\u7684\u672C\u5730\u4FEE\u6539\u7EE7\u7EED",
|
|
2689
|
+
includeLocalChangesHelp: "Agent \u53EF\u80FD\u7EE7\u7EED\u4FEE\u6539\u8FD9\u4E9B\u6587\u4EF6\uFF1BSpotPatch \u4F1A\u4FDD\u7559\u539F\u57FA\u7EBF\uFF0C\u4EC5\u5E94\u7528\u6216\u64A4\u9500 Agent \u81EA\u5DF1\u7684\u589E\u91CF\u3002",
|
|
2690
|
+
localChangesConsentRequired: "\u8FD0\u884C AI \u524D\uFF0C\u8BF7\u786E\u8BA4\u5141\u8BB8\u7EB3\u5165\u5F53\u524D\u672C\u5730\u4FEE\u6539\u3002",
|
|
2485
2691
|
capabilityVerified: "Agent \u80FD\u529B\u9A8C\u8BC1\u901A\u8FC7",
|
|
2486
2692
|
capabilityVerifiedAnnouncement: "AI \u6A21\u578B\u670D\u52A1\u80FD\u529B\u9A8C\u8BC1\u901A\u8FC7\u3002",
|
|
2487
2693
|
testingCapability: "\u6B63\u5728\u9A8C\u8BC1\u9274\u6743\u3001\u5DE5\u5177\u8C03\u7528\u3001\u8FDE\u7EED\u8C03\u7528\u4E0E\u6D41\u5F0F\u54CD\u5E94\u2026\u2026",
|
|
@@ -2490,7 +2696,7 @@ var UI_MESSAGES = Object.freeze({
|
|
|
2490
2696
|
reverting: "\u6B63\u5728\u64A4\u9500\u5DF2\u5E94\u7528\u7684 Agent \u53D8\u66F4\u3002",
|
|
2491
2697
|
consentRequired: "\u8FD0\u884C AI \u524D\uFF0C\u8BF7\u5148\u786E\u8BA4\u5141\u8BB8\u5411\u8FDC\u7A0B\u6A21\u578B\u670D\u52A1\u4F20\u8F93\u6570\u636E\u3002",
|
|
2492
2698
|
toolsReady: "\u5DE5\u5177\u8C03\u7528\u4E0E\u6D41\u5F0F\u54CD\u5E94\u5DF2\u5C31\u7EEA",
|
|
2493
|
-
testConnection: "\
|
|
2699
|
+
testConnection: "\u68C0\u67E5\u8FD0\u884C\u73AF\u5883",
|
|
2494
2700
|
verifyAndRun: "\u9A8C\u8BC1\u5E76\u8FD0\u884C",
|
|
2495
2701
|
verifying: "\u9A8C\u8BC1\u4E2D\u2026\u2026",
|
|
2496
2702
|
run: "\u8FD0\u884C AI",
|
|
@@ -3740,6 +3946,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3740
3946
|
agentProviderSelect: agentPanel.providerSelect,
|
|
3741
3947
|
agentModelSelect: agentPanel.modelSelect,
|
|
3742
3948
|
agentConsentCheckbox: agentPanel.consentCheckbox,
|
|
3949
|
+
agentWorkspaceConsentCheckbox: agentPanel.workspaceConsentCheckbox,
|
|
3743
3950
|
agentTestButton: agentPanel.testButton,
|
|
3744
3951
|
agentRunButton: agentPanel.runButton,
|
|
3745
3952
|
agentCancelButton: agentPanel.cancelButton,
|
|
@@ -3851,6 +4058,10 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3851
4058
|
previewButton.classList.toggle("spotpatch-primary", !agentReady);
|
|
3852
4059
|
placeDialog();
|
|
3853
4060
|
},
|
|
4061
|
+
renderAgentWorkspaceHealth(state, snapshot, errorCode) {
|
|
4062
|
+
agentPanel.renderWorkspaceHealth(state, snapshot, errorCode);
|
|
4063
|
+
placeDialog();
|
|
4064
|
+
},
|
|
3854
4065
|
renderAgentJob(snapshot, result, activities, errorCode) {
|
|
3855
4066
|
agentPanel.renderJob(snapshot, result, activities, errorCode);
|
|
3856
4067
|
placeDialog();
|
|
@@ -3871,6 +4082,7 @@ function createRuntimeView(document, shortcut, ai = Object.freeze({ enabled: fal
|
|
|
3871
4082
|
},
|
|
3872
4083
|
locale: localizer.locale,
|
|
3873
4084
|
messages: localizer.messages,
|
|
4085
|
+
agentWorkspaceConsentGranted: agentPanel.workspaceConsentGranted,
|
|
3874
4086
|
subscribeLocale: localizer.subscribe,
|
|
3875
4087
|
dispose() {
|
|
3876
4088
|
diagnostics.removeEventListener("toggle", placeDialog);
|
|
@@ -3974,6 +4186,22 @@ function createAgentWorkflow(options) {
|
|
|
3974
4186
|
let appliedDuringCurrentJob = false;
|
|
3975
4187
|
let actionPending = false;
|
|
3976
4188
|
const selectedProfiles = () => options.view.readAgentSelection();
|
|
4189
|
+
const refreshWorkspaceHealth = async (workflowRevision) => {
|
|
4190
|
+
options.view.renderAgentWorkspaceHealth("checking");
|
|
4191
|
+
try {
|
|
4192
|
+
const health = await options.api.agentWorkspaceHealth();
|
|
4193
|
+
if (workflowRevision !== revision) {
|
|
4194
|
+
return health;
|
|
4195
|
+
}
|
|
4196
|
+
options.view.renderAgentWorkspaceHealth(health.state, health, health.errorCode);
|
|
4197
|
+
return health;
|
|
4198
|
+
} catch (error) {
|
|
4199
|
+
if (workflowRevision === revision) {
|
|
4200
|
+
options.view.renderAgentWorkspaceHealth("blocked", void 0, errorCode(error));
|
|
4201
|
+
}
|
|
4202
|
+
throw error;
|
|
4203
|
+
}
|
|
4204
|
+
};
|
|
3977
4205
|
const renderJob = (explicitErrorCode) => {
|
|
3978
4206
|
if (snapshot === void 0) {
|
|
3979
4207
|
return;
|
|
@@ -4149,6 +4377,10 @@ function createAgentWorkflow(options) {
|
|
|
4149
4377
|
},
|
|
4150
4378
|
beginSelection() {
|
|
4151
4379
|
resetState();
|
|
4380
|
+
const workflowRevision = revision;
|
|
4381
|
+
if (options.ai.enabled) {
|
|
4382
|
+
void refreshWorkspaceHealth(workflowRevision).catch(() => void 0);
|
|
4383
|
+
}
|
|
4152
4384
|
},
|
|
4153
4385
|
cancel() {
|
|
4154
4386
|
if (snapshot?.canCancel === true) {
|
|
@@ -4181,12 +4413,17 @@ function createAgentWorkflow(options) {
|
|
|
4181
4413
|
providerOrModelChanged() {
|
|
4182
4414
|
revision += 1;
|
|
4183
4415
|
restoreProviderState();
|
|
4416
|
+
const workflowRevision = revision;
|
|
4417
|
+
void refreshWorkspaceHealth(workflowRevision).catch(() => void 0);
|
|
4184
4418
|
},
|
|
4185
4419
|
reset() {
|
|
4186
4420
|
const mustReselect = appliedDuringCurrentJob;
|
|
4187
4421
|
resetState();
|
|
4188
4422
|
if (mustReselect) {
|
|
4189
4423
|
options.onReselectRequired();
|
|
4424
|
+
} else if (options.ai.enabled) {
|
|
4425
|
+
const workflowRevision = revision;
|
|
4426
|
+
void refreshWorkspaceHealth(workflowRevision).catch(() => void 0);
|
|
4190
4427
|
}
|
|
4191
4428
|
},
|
|
4192
4429
|
revert() {
|
|
@@ -4213,15 +4450,27 @@ function createAgentWorkflow(options) {
|
|
|
4213
4450
|
providerConsents.add(selection.providerProfileId);
|
|
4214
4451
|
const workflowRevision = ++revision;
|
|
4215
4452
|
options.view.setAgentEditingEnabled(false);
|
|
4216
|
-
void
|
|
4453
|
+
void Promise.all([
|
|
4454
|
+
probe(workflowRevision),
|
|
4455
|
+
refreshWorkspaceHealth(workflowRevision)
|
|
4456
|
+
]).then(async ([, health]) => {
|
|
4217
4457
|
if (workflowRevision !== revision) {
|
|
4218
4458
|
return;
|
|
4219
4459
|
}
|
|
4460
|
+
if (health.state === "blocked") {
|
|
4461
|
+
throw new RuntimeApiError(
|
|
4462
|
+
health.errorCode ?? ERROR_CODES3.WORKTREE_LOCAL_CHANGES_UNSUPPORTED
|
|
4463
|
+
);
|
|
4464
|
+
}
|
|
4465
|
+
if (health.state === "consent-required" && !options.view.agentWorkspaceConsentGranted()) {
|
|
4466
|
+
throw new RuntimeApiError(ERROR_CODES3.WORKTREE_DIRTY);
|
|
4467
|
+
}
|
|
4220
4468
|
const created = await options.api.createAgentJob({
|
|
4221
4469
|
annotation,
|
|
4222
4470
|
providerProfileId: selection.providerProfileId,
|
|
4223
4471
|
modelProfileId: selection.modelProfileId,
|
|
4224
|
-
providerDataConsent: true
|
|
4472
|
+
providerDataConsent: true,
|
|
4473
|
+
workingTreeMode: health.state === "consent-required" ? "include-local-changes" : "require-clean"
|
|
4225
4474
|
});
|
|
4226
4475
|
if (workflowRevision !== revision) {
|
|
4227
4476
|
return;
|
|
@@ -4250,7 +4499,10 @@ function createAgentWorkflow(options) {
|
|
|
4250
4499
|
return;
|
|
4251
4500
|
}
|
|
4252
4501
|
const workflowRevision = ++revision;
|
|
4253
|
-
void
|
|
4502
|
+
void Promise.all([
|
|
4503
|
+
probe(workflowRevision),
|
|
4504
|
+
refreshWorkspaceHealth(workflowRevision)
|
|
4505
|
+
]).catch((error) => {
|
|
4254
4506
|
if (workflowRevision === revision) {
|
|
4255
4507
|
options.view.renderAgentCapability(
|
|
4256
4508
|
"error",
|