@spencer-kit/coder-studio 0.3.2 → 0.3.4
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/CHANGELOG.md +12 -0
- package/dist/esm/bin.mjs +1155 -636
- package/dist/esm/bin.mjs.map +4 -4
- package/dist/esm/server-runner.mjs +1137 -618
- package/dist/esm/server-runner.mjs.map +4 -4
- package/dist/web/assets/index-gL8kTxHV.css +1 -0
- package/dist/web/assets/index-xgtwbfqN.js +111 -0
- package/dist/web/assets/index-xgtwbfqN.js.map +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-BjrMfcUG.js +0 -111
- package/dist/web/assets/index-BjrMfcUG.js.map +0 -1
- package/dist/web/assets/index-mL_Aq31j.css +0 -1
|
@@ -115,8 +115,8 @@ var init_plugin = __esm({
|
|
|
115
115
|
init_web_ui_routing();
|
|
116
116
|
init_login_protection();
|
|
117
117
|
AUTH_COOKIE_NAME = "coder_studio_auth";
|
|
118
|
-
isPublicPath = (
|
|
119
|
-
const pathname = getRequestPathname(
|
|
118
|
+
isPublicPath = (path10) => {
|
|
119
|
+
const pathname = getRequestPathname(path10);
|
|
120
120
|
return pathname === "/" || pathname === "/login" || pathname === "/healthz" || pathname === "/auth/status" || pathname === "/auth/login" || pathname === "/auth/logout" || pathname.startsWith("/@") || isPublicStaticPath(pathname);
|
|
121
121
|
};
|
|
122
122
|
parseCookies = (cookieHeader) => {
|
|
@@ -787,11 +787,11 @@ var init_src = __esm({
|
|
|
787
787
|
|
|
788
788
|
// packages/utils/src/direct-execution.ts
|
|
789
789
|
import { posix, resolve as resolve2 } from "node:path";
|
|
790
|
-
function isWindowsDrivePath(
|
|
791
|
-
return /^[A-Za-z]:\//.test(
|
|
790
|
+
function isWindowsDrivePath(path10) {
|
|
791
|
+
return /^[A-Za-z]:\//.test(path10);
|
|
792
792
|
}
|
|
793
|
-
function normalizeComparablePath(
|
|
794
|
-
let normalized =
|
|
793
|
+
function normalizeComparablePath(path10) {
|
|
794
|
+
let normalized = path10.replace(/\\/g, "/");
|
|
795
795
|
if (/^\/[A-Za-z]:\//.test(normalized)) {
|
|
796
796
|
normalized = normalized.slice(1);
|
|
797
797
|
}
|
|
@@ -815,8 +815,8 @@ function normalizeModuleUrlPath(moduleUrl) {
|
|
|
815
815
|
if (url.protocol !== "file:") {
|
|
816
816
|
return null;
|
|
817
817
|
}
|
|
818
|
-
const
|
|
819
|
-
return normalizeComparablePath(
|
|
818
|
+
const path10 = `${url.host ? `//${url.host}` : ""}${decodeURIComponent(url.pathname)}`;
|
|
819
|
+
return normalizeComparablePath(path10);
|
|
820
820
|
}
|
|
821
821
|
function normalizeArgvPath(argv1) {
|
|
822
822
|
const isAbsoluteWindowsPath = /^[A-Za-z]:[\\/]/.test(argv1) || /^\\\\/.test(argv1);
|
|
@@ -995,10 +995,10 @@ var init_image = __esm({
|
|
|
995
995
|
// packages/server/src/fs/file-io.ts
|
|
996
996
|
import { createHash } from "crypto";
|
|
997
997
|
import { readFile as fsReadFile, writeFile as fsWriteFile, mkdir, rm, stat } from "fs/promises";
|
|
998
|
-
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
999
|
-
async function statSafe(
|
|
998
|
+
import { dirname as dirname3, isAbsolute, relative, resolve as resolve3 } from "path";
|
|
999
|
+
async function statSafe(path10) {
|
|
1000
1000
|
try {
|
|
1001
|
-
return await stat(
|
|
1001
|
+
return await stat(path10);
|
|
1002
1002
|
} catch {
|
|
1003
1003
|
return null;
|
|
1004
1004
|
}
|
|
@@ -1031,7 +1031,8 @@ async function deleteEntry(rootPath, relPath) {
|
|
|
1031
1031
|
function resolveSafe(root, relPath) {
|
|
1032
1032
|
const absRoot = resolve3(root);
|
|
1033
1033
|
const abs = resolve3(absRoot, relPath);
|
|
1034
|
-
|
|
1034
|
+
const rel = relative(absRoot, abs);
|
|
1035
|
+
if (rel === ".." || rel.startsWith(`..${"/"}`) || isAbsolute(rel)) {
|
|
1035
1036
|
throw { code: "path_escape", message: "Path escapes workspace root" };
|
|
1036
1037
|
}
|
|
1037
1038
|
return abs;
|
|
@@ -1093,8 +1094,10 @@ var init_file_io = __esm({
|
|
|
1093
1094
|
// packages/server/src/routes/file-asset.ts
|
|
1094
1095
|
import { createReadStream } from "fs";
|
|
1095
1096
|
import { realpath, stat as stat2 } from "fs/promises";
|
|
1097
|
+
import { isAbsolute as isAbsolute2, relative as relative2 } from "path";
|
|
1096
1098
|
function isPathInsideRoot(rootPath, targetPath) {
|
|
1097
|
-
|
|
1099
|
+
const rel = relative2(rootPath, targetPath);
|
|
1100
|
+
return rel !== ".." && !rel.startsWith(`..${"/"}`) && !isAbsolute2(rel);
|
|
1098
1101
|
}
|
|
1099
1102
|
function registerFileAssetRoutes(app, deps) {
|
|
1100
1103
|
app.get(
|
|
@@ -1219,12 +1222,12 @@ async function ensureSafeUploadDir(rootDir, targetDir) {
|
|
|
1219
1222
|
await mkdir2(resolvedRoot, { recursive: true });
|
|
1220
1223
|
await assertDirectorySegmentSafe(resolvedRoot);
|
|
1221
1224
|
}
|
|
1222
|
-
const
|
|
1223
|
-
if (!
|
|
1225
|
+
const relative5 = path3.relative(resolvedRoot, resolvedTarget);
|
|
1226
|
+
if (!relative5) {
|
|
1224
1227
|
return;
|
|
1225
1228
|
}
|
|
1226
1229
|
let current = resolvedRoot;
|
|
1227
|
-
for (const segment of
|
|
1230
|
+
for (const segment of relative5.split(path3.sep)) {
|
|
1228
1231
|
current = path3.join(current, segment);
|
|
1229
1232
|
try {
|
|
1230
1233
|
await assertDirectorySegmentSafe(current);
|
|
@@ -1773,189 +1776,265 @@ var init_app = __esm({
|
|
|
1773
1776
|
}
|
|
1774
1777
|
});
|
|
1775
1778
|
|
|
1776
|
-
// packages/server/src/
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
const selected = audit.findings.filter((f) => opts.removeIds.includes(f.id));
|
|
1815
|
-
if (selected.length === 0) {
|
|
1816
|
-
return { removed: [], backupPath: null, noop: true };
|
|
1817
|
-
}
|
|
1818
|
-
const original = readFileSync5(configPath, "utf-8");
|
|
1819
|
-
const backupPath = writeBackup(configPath, original, opts.backupDir);
|
|
1820
|
-
const linesToDrop = /* @__PURE__ */ new Set();
|
|
1821
|
-
for (const finding of selected) {
|
|
1822
|
-
for (let ln = finding.startLine; ln <= finding.endLine; ln++) {
|
|
1823
|
-
linesToDrop.add(ln);
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
const originalLines = original.split(/\r?\n/);
|
|
1827
|
-
const kept = [];
|
|
1828
|
-
for (let i = 0; i < originalLines.length; i++) {
|
|
1829
|
-
const ln = i + 1;
|
|
1830
|
-
if (linesToDrop.has(ln)) continue;
|
|
1831
|
-
kept.push(originalLines[i]);
|
|
1832
|
-
}
|
|
1833
|
-
const cleaned = collapseBlankRunsNearDeletions(kept);
|
|
1834
|
-
const output = cleaned.join("\n");
|
|
1835
|
-
atomicWrite(configPath, output);
|
|
1836
|
-
return {
|
|
1837
|
-
removed: selected.map((f) => f.id),
|
|
1838
|
-
backupPath,
|
|
1839
|
-
noop: false
|
|
1840
|
-
};
|
|
1841
|
-
}
|
|
1842
|
-
function detectTopLevelNotify(lines) {
|
|
1843
|
-
const headerRegex = /^\s*\[/;
|
|
1844
|
-
const notifyRegex = /^\s*notify\s*=\s*(.*)$/;
|
|
1845
|
-
let inTopLevel = true;
|
|
1846
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1847
|
-
const line = lines[i];
|
|
1848
|
-
const trimmed = line.trim();
|
|
1849
|
-
if (headerRegex.test(trimmed)) {
|
|
1850
|
-
inTopLevel = false;
|
|
1851
|
-
continue;
|
|
1852
|
-
}
|
|
1853
|
-
if (!inTopLevel) continue;
|
|
1854
|
-
const m = trimmed.match(notifyRegex);
|
|
1855
|
-
if (!m) continue;
|
|
1856
|
-
const rhs = (m[1] ?? "").trim();
|
|
1857
|
-
if (rhs.startsWith("[") && rhs.endsWith("]") && countBrackets(rhs) === 0) {
|
|
1858
|
-
return makeNotifyFinding(lines, i, i);
|
|
1859
|
-
}
|
|
1860
|
-
if (rhs.startsWith("[")) {
|
|
1861
|
-
let depth = countBrackets(rhs);
|
|
1862
|
-
for (let j = i + 1; j < lines.length; j++) {
|
|
1863
|
-
depth += countBrackets(lines[j]);
|
|
1864
|
-
if (depth === 0) {
|
|
1865
|
-
return makeNotifyFinding(lines, i, j);
|
|
1779
|
+
// packages/server/src/git/auto-fetch.ts
|
|
1780
|
+
var PERIOD_SETTING_KEY, DEFAULT_PERIOD_SEC, TICK_INTERVAL_MS, OPEN_TIME_COOLDOWN_MS, MAX_CONSECUTIVE_FAILURES, JITTER_RATIO, AutoFetchScheduler;
|
|
1781
|
+
var init_auto_fetch = __esm({
|
|
1782
|
+
"packages/server/src/git/auto-fetch.ts"() {
|
|
1783
|
+
"use strict";
|
|
1784
|
+
PERIOD_SETTING_KEY = "git.autofetchPeriodSec";
|
|
1785
|
+
DEFAULT_PERIOD_SEC = 180;
|
|
1786
|
+
TICK_INTERVAL_MS = 1e3;
|
|
1787
|
+
OPEN_TIME_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
1788
|
+
MAX_CONSECUTIVE_FAILURES = 3;
|
|
1789
|
+
JITTER_RATIO = 0.1;
|
|
1790
|
+
AutoFetchScheduler = class {
|
|
1791
|
+
constructor(deps) {
|
|
1792
|
+
this.deps = deps;
|
|
1793
|
+
this.now = deps.now ?? Date.now;
|
|
1794
|
+
this.random = deps.random ?? (() => 0.5);
|
|
1795
|
+
this.setTimeoutFn = deps.setTimeout ?? globalThis.setTimeout;
|
|
1796
|
+
this.setIntervalFn = deps.setInterval ?? globalThis.setInterval;
|
|
1797
|
+
this.clearIntervalFn = deps.clearInterval ?? globalThis.clearInterval;
|
|
1798
|
+
this.clearTimeoutFn = deps.clearTimeout ?? globalThis.clearTimeout;
|
|
1799
|
+
this.start();
|
|
1800
|
+
}
|
|
1801
|
+
deps;
|
|
1802
|
+
clientWorkspaceMap = /* @__PURE__ */ new Map();
|
|
1803
|
+
workspaceStateMap = /* @__PURE__ */ new Map();
|
|
1804
|
+
now;
|
|
1805
|
+
random;
|
|
1806
|
+
setTimeoutFn;
|
|
1807
|
+
setIntervalFn;
|
|
1808
|
+
clearIntervalFn;
|
|
1809
|
+
clearTimeoutFn;
|
|
1810
|
+
pendingTimeouts = /* @__PURE__ */ new Set();
|
|
1811
|
+
tickTimer = null;
|
|
1812
|
+
stopped = false;
|
|
1813
|
+
registerViewer(clientId, workspaceId) {
|
|
1814
|
+
const previousWorkspaceId = this.clientWorkspaceMap.get(clientId);
|
|
1815
|
+
if (previousWorkspaceId === workspaceId) {
|
|
1816
|
+
return;
|
|
1866
1817
|
}
|
|
1818
|
+
if (previousWorkspaceId) {
|
|
1819
|
+
this.unregisterViewer(clientId);
|
|
1820
|
+
}
|
|
1821
|
+
this.clientWorkspaceMap.set(clientId, workspaceId);
|
|
1822
|
+
const state = this.getOrCreateState(workspaceId);
|
|
1823
|
+
state.viewerCount += 1;
|
|
1824
|
+
if (state.viewerCount === 1) {
|
|
1825
|
+
state.blocked = false;
|
|
1826
|
+
state.consecutiveFailures = 0;
|
|
1827
|
+
}
|
|
1828
|
+
this.ensureNextPeriodicFetch(state, false);
|
|
1829
|
+
}
|
|
1830
|
+
unregisterViewer(clientId) {
|
|
1831
|
+
const workspaceId = this.clientWorkspaceMap.get(clientId);
|
|
1832
|
+
if (!workspaceId) {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
this.clientWorkspaceMap.delete(clientId);
|
|
1836
|
+
const state = this.workspaceStateMap.get(workspaceId);
|
|
1837
|
+
if (!state) {
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
state.viewerCount = Math.max(0, state.viewerCount - 1);
|
|
1841
|
+
if (state.viewerCount === 0) {
|
|
1842
|
+
state.blocked = false;
|
|
1843
|
+
state.consecutiveFailures = 0;
|
|
1844
|
+
state.nextFetchAt = void 0;
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
triggerOpenTimeFetch(workspaceId) {
|
|
1848
|
+
const state = this.getOrCreateState(workspaceId);
|
|
1849
|
+
const lastFetchAt = state.lastFetchAt;
|
|
1850
|
+
if (this.stopped || state.inFlight) {
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
if (lastFetchAt !== void 0 && this.now() - lastFetchAt < OPEN_TIME_COOLDOWN_MS) {
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
const timer = this.setTimeoutFn(() => {
|
|
1857
|
+
this.pendingTimeouts.delete(timer);
|
|
1858
|
+
if (this.stopped) {
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
void this.fetchWorkspace(workspaceId, "open");
|
|
1862
|
+
}, 0);
|
|
1863
|
+
this.pendingTimeouts.add(timer);
|
|
1864
|
+
}
|
|
1865
|
+
recordSuccess(workspaceId) {
|
|
1866
|
+
const state = this.getOrCreateState(workspaceId);
|
|
1867
|
+
state.lastFetchAt = this.now();
|
|
1868
|
+
state.consecutiveFailures = 0;
|
|
1869
|
+
state.blocked = false;
|
|
1870
|
+
state.nextFetchAt = void 0;
|
|
1871
|
+
this.ensureNextPeriodicFetch(state, true);
|
|
1872
|
+
}
|
|
1873
|
+
recordFailure(workspaceId) {
|
|
1874
|
+
const state = this.getOrCreateState(workspaceId);
|
|
1875
|
+
state.consecutiveFailures += 1;
|
|
1876
|
+
state.nextFetchAt = void 0;
|
|
1877
|
+
if (state.consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
|
|
1878
|
+
state.blocked = true;
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
this.ensureNextPeriodicFetch(state, true);
|
|
1882
|
+
}
|
|
1883
|
+
getLastFetchAt(workspaceId) {
|
|
1884
|
+
return this.workspaceStateMap.get(workspaceId)?.lastFetchAt;
|
|
1885
|
+
}
|
|
1886
|
+
async runExclusive(workspaceId, op) {
|
|
1887
|
+
const release = await this.acquireWorkspaceOperation(workspaceId);
|
|
1888
|
+
try {
|
|
1889
|
+
return await op();
|
|
1890
|
+
} finally {
|
|
1891
|
+
release();
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
start() {
|
|
1895
|
+
if (this.tickTimer) {
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
this.stopped = false;
|
|
1899
|
+
this.tickTimer = this.setIntervalFn(() => {
|
|
1900
|
+
this.evaluateDueFetches();
|
|
1901
|
+
}, TICK_INTERVAL_MS);
|
|
1902
|
+
}
|
|
1903
|
+
stop() {
|
|
1904
|
+
if (this.tickTimer) {
|
|
1905
|
+
this.clearIntervalFn(this.tickTimer);
|
|
1906
|
+
this.tickTimer = null;
|
|
1907
|
+
}
|
|
1908
|
+
this.stopped = true;
|
|
1909
|
+
for (const timer of this.pendingTimeouts) {
|
|
1910
|
+
this.clearTimeoutFn(timer);
|
|
1911
|
+
}
|
|
1912
|
+
this.pendingTimeouts.clear();
|
|
1913
|
+
}
|
|
1914
|
+
evaluateDueFetches() {
|
|
1915
|
+
const now = this.now();
|
|
1916
|
+
for (const [workspaceId, state] of this.workspaceStateMap) {
|
|
1917
|
+
if (!this.shouldCheckWorkspace(state)) {
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
if (state.nextFetchAt === void 0) {
|
|
1921
|
+
this.ensureNextPeriodicFetch(state, false);
|
|
1922
|
+
}
|
|
1923
|
+
if (state.nextFetchAt === void 0 || state.nextFetchAt > now) {
|
|
1924
|
+
continue;
|
|
1925
|
+
}
|
|
1926
|
+
void this.fetchWorkspace(workspaceId, "periodic", state.nextFetchAt);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
shouldCheckWorkspace(state) {
|
|
1930
|
+
return this.getPeriodMs() > 0 && state.viewerCount > 0 && !state.inFlight && !state.blocked;
|
|
1931
|
+
}
|
|
1932
|
+
ensureNextPeriodicFetch(state, resetSchedule) {
|
|
1933
|
+
const periodMs = this.getPeriodMs();
|
|
1934
|
+
if (periodMs <= 0 || state.viewerCount <= 0 || state.blocked || state.inFlight) {
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (!resetSchedule && state.nextFetchAt !== void 0) {
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
if (state.lastFetchAt === void 0) {
|
|
1941
|
+
state.nextFetchAt = this.now();
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1944
|
+
const nextFetchAt = state.lastFetchAt + this.getJitteredPeriodMs(periodMs);
|
|
1945
|
+
state.nextFetchAt = Math.max(this.now(), nextFetchAt);
|
|
1946
|
+
}
|
|
1947
|
+
getPeriodMs() {
|
|
1948
|
+
const configuredPeriodSec = this.deps.settingsRepo.get(PERIOD_SETTING_KEY);
|
|
1949
|
+
const periodSec = configuredPeriodSec ?? DEFAULT_PERIOD_SEC;
|
|
1950
|
+
return Math.max(0, periodSec) * 1e3;
|
|
1951
|
+
}
|
|
1952
|
+
getJitteredPeriodMs(periodMs) {
|
|
1953
|
+
const jitterScale = 1 + (this.random() - 0.5) * 2 * JITTER_RATIO;
|
|
1954
|
+
return Math.round(periodMs * jitterScale);
|
|
1955
|
+
}
|
|
1956
|
+
getOrCreateState(workspaceId) {
|
|
1957
|
+
const existingState = this.workspaceStateMap.get(workspaceId);
|
|
1958
|
+
if (existingState) {
|
|
1959
|
+
return existingState;
|
|
1960
|
+
}
|
|
1961
|
+
const state = {
|
|
1962
|
+
viewerCount: 0,
|
|
1963
|
+
consecutiveFailures: 0,
|
|
1964
|
+
inFlight: false,
|
|
1965
|
+
blocked: false,
|
|
1966
|
+
waiters: []
|
|
1967
|
+
};
|
|
1968
|
+
this.workspaceStateMap.set(workspaceId, state);
|
|
1969
|
+
return state;
|
|
1970
|
+
}
|
|
1971
|
+
async fetchWorkspace(workspaceId, mode, scheduledAt) {
|
|
1972
|
+
if (this.stopped) {
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
const state = this.getOrCreateState(workspaceId);
|
|
1976
|
+
if (state.inFlight || state.blocked) {
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
if (!this.deps.workspaceMgr.get(workspaceId)) {
|
|
1980
|
+
state.nextFetchAt = void 0;
|
|
1981
|
+
return;
|
|
1982
|
+
}
|
|
1983
|
+
await this.runExclusive(workspaceId, async () => {
|
|
1984
|
+
const currentState = this.getOrCreateState(workspaceId);
|
|
1985
|
+
if (this.stopped || currentState.blocked) {
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
if (!this.deps.workspaceMgr.get(workspaceId)) {
|
|
1989
|
+
currentState.nextFetchAt = void 0;
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
if (mode === "open") {
|
|
1993
|
+
const lastFetchAt = currentState.lastFetchAt;
|
|
1994
|
+
if (lastFetchAt !== void 0 && this.now() - lastFetchAt < OPEN_TIME_COOLDOWN_MS) {
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
} else if (scheduledAt !== void 0 && currentState.lastFetchAt !== void 0 && currentState.lastFetchAt >= scheduledAt) {
|
|
1998
|
+
return;
|
|
1999
|
+
}
|
|
2000
|
+
try {
|
|
2001
|
+
await this.deps.runFetch(workspaceId);
|
|
2002
|
+
this.recordSuccess(workspaceId);
|
|
2003
|
+
} catch {
|
|
2004
|
+
this.recordFailure(workspaceId);
|
|
2005
|
+
}
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2008
|
+
acquireWorkspaceOperation(workspaceId) {
|
|
2009
|
+
const state = this.getOrCreateState(workspaceId);
|
|
2010
|
+
return new Promise((resolve4) => {
|
|
2011
|
+
const grant = () => {
|
|
2012
|
+
state.inFlight = true;
|
|
2013
|
+
state.nextFetchAt = void 0;
|
|
2014
|
+
let released = false;
|
|
2015
|
+
resolve4(() => {
|
|
2016
|
+
if (released) {
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2019
|
+
released = true;
|
|
2020
|
+
const next = state.waiters.shift();
|
|
2021
|
+
if (next) {
|
|
2022
|
+
next();
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
2025
|
+
state.inFlight = false;
|
|
2026
|
+
this.ensureNextPeriodicFetch(state, true);
|
|
2027
|
+
});
|
|
2028
|
+
};
|
|
2029
|
+
if (state.inFlight) {
|
|
2030
|
+
state.waiters.push(grant);
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
grant();
|
|
2034
|
+
});
|
|
1867
2035
|
}
|
|
1868
|
-
return null;
|
|
1869
|
-
}
|
|
1870
|
-
return makeNotifyFinding(lines, i, i);
|
|
1871
|
-
}
|
|
1872
|
-
return null;
|
|
1873
|
-
}
|
|
1874
|
-
function makeNotifyFinding(lines, startIdx, endIdx) {
|
|
1875
|
-
return {
|
|
1876
|
-
id: "toml_notify",
|
|
1877
|
-
type: "toml_notify",
|
|
1878
|
-
severity: "warn",
|
|
1879
|
-
startLine: startIdx + 1,
|
|
1880
|
-
endLine: endIdx + 1,
|
|
1881
|
-
snippet: lines.slice(startIdx, endIdx + 1).join("\n"),
|
|
1882
|
-
message: "config.toml \u9876\u5C42\u8BBE\u7F6E\u4E86 notify\uFF0C\u4F1A\u4E0E Coder Studio \u7684\u542F\u52A8\u53C2\u6570\u6CE8\u5165\u51B2\u7A81\uFF0C\u53EF\u80FD\u5BFC\u81F4 session \u72B6\u6001\u4E0D\u540C\u6B65\u3002"
|
|
1883
|
-
};
|
|
1884
|
-
}
|
|
1885
|
-
function detectCodexHooksFlag(lines) {
|
|
1886
|
-
const headerRegex = /^\s*\[([^\]]+)\]\s*$/;
|
|
1887
|
-
const codexHooksRegex = /^\s*codex_hooks\s*=\s*true\b/;
|
|
1888
|
-
let currentSection = null;
|
|
1889
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1890
|
-
const line = lines[i];
|
|
1891
|
-
const headerMatch = line.match(headerRegex);
|
|
1892
|
-
if (headerMatch) {
|
|
1893
|
-
currentSection = headerMatch[1].trim();
|
|
1894
|
-
continue;
|
|
1895
|
-
}
|
|
1896
|
-
if (currentSection !== "features") continue;
|
|
1897
|
-
if (!codexHooksRegex.test(line)) continue;
|
|
1898
|
-
return {
|
|
1899
|
-
id: "toml_codex_hooks",
|
|
1900
|
-
type: "toml_codex_hooks",
|
|
1901
|
-
severity: "info",
|
|
1902
|
-
startLine: i + 1,
|
|
1903
|
-
endLine: i + 1,
|
|
1904
|
-
snippet: line,
|
|
1905
|
-
message: "[features] codex_hooks = true \u542F\u7528\u4E86 Codex CLI \u7684\u5B9E\u9A8C\u6027 hook \u5F15\u64CE\uFF0C\u53EF\u80FD\u5F71\u54CD notify \u7684\u884C\u4E3A\u3002\u82E5\u4E0D\u4E3B\u52A8\u4F7F\u7528\u8BE5\u7279\u6027\uFF0C\u5EFA\u8BAE\u5173\u95ED\u3002"
|
|
1906
2036
|
};
|
|
1907
2037
|
}
|
|
1908
|
-
return null;
|
|
1909
|
-
}
|
|
1910
|
-
function countBrackets(s) {
|
|
1911
|
-
let n = 0;
|
|
1912
|
-
for (const ch of s) {
|
|
1913
|
-
if (ch === "[") n++;
|
|
1914
|
-
else if (ch === "]") n--;
|
|
1915
|
-
}
|
|
1916
|
-
return n;
|
|
1917
|
-
}
|
|
1918
|
-
function writeBackup(configPath, original, backupDir) {
|
|
1919
|
-
const dir = backupDir ?? dirname4(configPath);
|
|
1920
|
-
if (!existsSync6(dir)) {
|
|
1921
|
-
mkdirSync3(dir, { recursive: true });
|
|
1922
|
-
}
|
|
1923
|
-
const ts = formatTimestamp(/* @__PURE__ */ new Date());
|
|
1924
|
-
const backupPath = join3(dir, `${basenameNoTomlExt(configPath)}.bak.${ts}.toml`);
|
|
1925
|
-
writeFileSync3(backupPath, original, "utf-8");
|
|
1926
|
-
return backupPath;
|
|
1927
|
-
}
|
|
1928
|
-
function atomicWrite(configPath, contents) {
|
|
1929
|
-
const tempPath = `${configPath}.tmp`;
|
|
1930
|
-
writeFileSync3(tempPath, contents, "utf-8");
|
|
1931
|
-
renameSync(tempPath, configPath);
|
|
1932
|
-
}
|
|
1933
|
-
function basenameNoTomlExt(p) {
|
|
1934
|
-
const base = p.split(/[\\/]/).pop() ?? "config.toml";
|
|
1935
|
-
return base.replace(/\.toml$/i, "");
|
|
1936
|
-
}
|
|
1937
|
-
function formatTimestamp(d) {
|
|
1938
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
1939
|
-
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
1940
|
-
}
|
|
1941
|
-
function collapseBlankRunsNearDeletions(lines) {
|
|
1942
|
-
const out = [];
|
|
1943
|
-
let blankRun = 0;
|
|
1944
|
-
for (const line of lines) {
|
|
1945
|
-
if (line.trim() === "") {
|
|
1946
|
-
blankRun++;
|
|
1947
|
-
if (blankRun <= 2) out.push(line);
|
|
1948
|
-
} else {
|
|
1949
|
-
blankRun = 0;
|
|
1950
|
-
out.push(line);
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
return out;
|
|
1954
|
-
}
|
|
1955
|
-
var init_codex_config_audit = __esm({
|
|
1956
|
-
"packages/server/src/config/codex-config-audit.ts"() {
|
|
1957
|
-
"use strict";
|
|
1958
|
-
}
|
|
1959
2038
|
});
|
|
1960
2039
|
|
|
1961
2040
|
// packages/server/src/provider-runtime/command-runner.ts
|
|
@@ -2028,6 +2107,157 @@ var init_command_check = __esm({
|
|
|
2028
2107
|
}
|
|
2029
2108
|
});
|
|
2030
2109
|
|
|
2110
|
+
// packages/server/src/provider-runtime/e2e-provider-mock.ts
|
|
2111
|
+
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2112
|
+
import { dirname as dirname4, join as join3 } from "node:path";
|
|
2113
|
+
function createE2EProviderMockOverrides(env = process.env) {
|
|
2114
|
+
const statePath = env.CODER_STUDIO_E2E_PROVIDER_STATE_PATH;
|
|
2115
|
+
if (!statePath) {
|
|
2116
|
+
return null;
|
|
2117
|
+
}
|
|
2118
|
+
const binDir = env.CODER_STUDIO_E2E_PROVIDER_BIN_DIR;
|
|
2119
|
+
const debugLogPath = env.CODER_STUDIO_E2E_PROVIDER_DEBUG_LOG_PATH;
|
|
2120
|
+
appendDebugLog(debugLogPath, `init statePath=${statePath} binDir=${binDir ?? ""}`);
|
|
2121
|
+
const commandExists = async (command) => {
|
|
2122
|
+
const state = readMockState(statePath);
|
|
2123
|
+
const override = state.commands?.[command];
|
|
2124
|
+
appendDebugLog(
|
|
2125
|
+
debugLogPath,
|
|
2126
|
+
`commandExists ${command} override=${String(override)} state=${JSON.stringify(state.commands ?? {})}`
|
|
2127
|
+
);
|
|
2128
|
+
if (typeof override === "boolean") {
|
|
2129
|
+
return override;
|
|
2130
|
+
}
|
|
2131
|
+
return checkCommandAvailable(command);
|
|
2132
|
+
};
|
|
2133
|
+
const runCommand2 = async (file, args, options) => {
|
|
2134
|
+
const providerId = getInstallProviderId(file, args);
|
|
2135
|
+
appendDebugLog(
|
|
2136
|
+
debugLogPath,
|
|
2137
|
+
`runCommand ${file} ${args.join(" ")} provider=${providerId ?? "none"}`
|
|
2138
|
+
);
|
|
2139
|
+
if (!providerId) {
|
|
2140
|
+
return runCommandAsString(file, args, options);
|
|
2141
|
+
}
|
|
2142
|
+
const state = readMockState(statePath);
|
|
2143
|
+
const behavior = state.installBehavior?.[providerId];
|
|
2144
|
+
appendDebugLog(
|
|
2145
|
+
debugLogPath,
|
|
2146
|
+
`behavior ${providerId} ${JSON.stringify(behavior)} state=${JSON.stringify(state)}`
|
|
2147
|
+
);
|
|
2148
|
+
if (!behavior) {
|
|
2149
|
+
return runCommandAsString(file, args, options);
|
|
2150
|
+
}
|
|
2151
|
+
if (behavior.result === "success") {
|
|
2152
|
+
writeMockState(statePath, (draft) => {
|
|
2153
|
+
draft.commands ??= {};
|
|
2154
|
+
draft.commands[providerId] = true;
|
|
2155
|
+
});
|
|
2156
|
+
if (binDir) {
|
|
2157
|
+
ensureProviderCommand(binDir, providerId);
|
|
2158
|
+
}
|
|
2159
|
+
appendDebugLog(debugLogPath, `install success ${providerId}`);
|
|
2160
|
+
return {
|
|
2161
|
+
stdout: `installed ${providerId}`,
|
|
2162
|
+
stderr: ""
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
const message = behavior.message ?? (behavior.result === "permission_denied" ? "permission denied" : "command not found");
|
|
2166
|
+
throw Object.assign(new Error(message), {
|
|
2167
|
+
exitCode: 1,
|
|
2168
|
+
stdout: "",
|
|
2169
|
+
stderr: message
|
|
2170
|
+
});
|
|
2171
|
+
};
|
|
2172
|
+
return {
|
|
2173
|
+
commandExists,
|
|
2174
|
+
runCommand: runCommand2
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
function getInstallProviderId(file, args) {
|
|
2178
|
+
if (file !== "npm" || args.length !== 3) {
|
|
2179
|
+
return null;
|
|
2180
|
+
}
|
|
2181
|
+
if (args[0] !== "install" || args[1] !== "-g") {
|
|
2182
|
+
return null;
|
|
2183
|
+
}
|
|
2184
|
+
const packageName = args[2];
|
|
2185
|
+
if (packageName === PROVIDER_INSTALL_PACKAGES.claude) {
|
|
2186
|
+
return "claude";
|
|
2187
|
+
}
|
|
2188
|
+
if (packageName === PROVIDER_INSTALL_PACKAGES.codex) {
|
|
2189
|
+
return "codex";
|
|
2190
|
+
}
|
|
2191
|
+
return null;
|
|
2192
|
+
}
|
|
2193
|
+
function readMockState(statePath) {
|
|
2194
|
+
if (!existsSync6(statePath)) {
|
|
2195
|
+
return {};
|
|
2196
|
+
}
|
|
2197
|
+
const raw = readFileSync5(statePath, "utf8");
|
|
2198
|
+
if (!raw.trim()) {
|
|
2199
|
+
return {};
|
|
2200
|
+
}
|
|
2201
|
+
try {
|
|
2202
|
+
return JSON.parse(raw);
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
throw new Error(
|
|
2205
|
+
`Invalid provider mock state at ${statePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
function writeMockState(statePath, updater) {
|
|
2210
|
+
const nextState = readMockState(statePath);
|
|
2211
|
+
updater(nextState);
|
|
2212
|
+
mkdirSync3(dirname4(statePath), { recursive: true });
|
|
2213
|
+
writeFileSync3(statePath, JSON.stringify(nextState, null, 2));
|
|
2214
|
+
return nextState;
|
|
2215
|
+
}
|
|
2216
|
+
function ensureProviderCommand(binDir, providerId) {
|
|
2217
|
+
mkdirSync3(binDir, { recursive: true });
|
|
2218
|
+
const scriptPath = join3(binDir, providerId);
|
|
2219
|
+
writeFileSync3(scriptPath, PROVIDER_COMMAND_SCRIPTS[providerId], "utf8");
|
|
2220
|
+
chmodSync(scriptPath, 493);
|
|
2221
|
+
}
|
|
2222
|
+
function appendDebugLog(path10, line) {
|
|
2223
|
+
if (!path10) {
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
mkdirSync3(dirname4(path10), { recursive: true });
|
|
2227
|
+
writeFileSync3(path10, `${line}
|
|
2228
|
+
`, { flag: "a" });
|
|
2229
|
+
}
|
|
2230
|
+
var PROVIDER_INSTALL_PACKAGES, PROVIDER_COMMAND_SCRIPTS;
|
|
2231
|
+
var init_e2e_provider_mock = __esm({
|
|
2232
|
+
"packages/server/src/provider-runtime/e2e-provider-mock.ts"() {
|
|
2233
|
+
"use strict";
|
|
2234
|
+
init_command_check();
|
|
2235
|
+
init_command_runner();
|
|
2236
|
+
PROVIDER_INSTALL_PACKAGES = {
|
|
2237
|
+
claude: "@anthropic-ai/claude-code",
|
|
2238
|
+
codex: "@openai/codex"
|
|
2239
|
+
};
|
|
2240
|
+
PROVIDER_COMMAND_SCRIPTS = {
|
|
2241
|
+
claude: `#!/usr/bin/env bash
|
|
2242
|
+
set -euo pipefail
|
|
2243
|
+
trap 'exit 0' TERM INT
|
|
2244
|
+
printf 'Mock Claude ready\\n'
|
|
2245
|
+
while true; do
|
|
2246
|
+
sleep 1
|
|
2247
|
+
done
|
|
2248
|
+
`,
|
|
2249
|
+
codex: `#!/usr/bin/env bash
|
|
2250
|
+
set -euo pipefail
|
|
2251
|
+
trap 'exit 0' TERM INT
|
|
2252
|
+
printf 'Session ID: abcdef-123456\\n> '
|
|
2253
|
+
while true; do
|
|
2254
|
+
sleep 1
|
|
2255
|
+
done
|
|
2256
|
+
`
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
});
|
|
2260
|
+
|
|
2031
2261
|
// packages/server/src/provider-runtime/install-manager.ts
|
|
2032
2262
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2033
2263
|
function getErrorDetails(error) {
|
|
@@ -4188,7 +4418,7 @@ function parseStatus(porcelainV2) {
|
|
|
4188
4418
|
continue;
|
|
4189
4419
|
}
|
|
4190
4420
|
if (record.startsWith("? ")) {
|
|
4191
|
-
untracked.push({ path: record.substring(2) });
|
|
4421
|
+
untracked.push({ path: record.substring(2), status: "untracked" });
|
|
4192
4422
|
}
|
|
4193
4423
|
}
|
|
4194
4424
|
return {
|
|
@@ -4209,11 +4439,11 @@ function parseOrdinaryChangedEntry(record, staged, modified, deleted) {
|
|
|
4209
4439
|
if (!xy) {
|
|
4210
4440
|
return;
|
|
4211
4441
|
}
|
|
4212
|
-
const
|
|
4213
|
-
if (!
|
|
4442
|
+
const path10 = parts.slice(8).join(" ");
|
|
4443
|
+
if (!path10) {
|
|
4214
4444
|
return;
|
|
4215
4445
|
}
|
|
4216
|
-
pushChange({ path:
|
|
4446
|
+
pushChange({ path: path10 }, xy, staged, modified, deleted);
|
|
4217
4447
|
}
|
|
4218
4448
|
function parseRenamedEntry(record, oldPathRecord, staged, modified, deleted) {
|
|
4219
4449
|
const parts = record.split(" ");
|
|
@@ -4225,27 +4455,52 @@ function parseRenamedEntry(record, oldPathRecord, staged, modified, deleted) {
|
|
|
4225
4455
|
const pathAndMaybeOldPath = pathTokens.join(" ");
|
|
4226
4456
|
const inlinePathParts = pathAndMaybeOldPath.split(" ");
|
|
4227
4457
|
const fallbackPath = !oldPathRecord && inlinePathParts.length === 1 && pathTokens.length > 1 ? pathTokens.slice(0, -1).join(" ") : void 0;
|
|
4228
|
-
const
|
|
4229
|
-
if (!
|
|
4458
|
+
const path10 = fallbackPath ?? inlinePathParts[0];
|
|
4459
|
+
if (!path10) {
|
|
4230
4460
|
return;
|
|
4231
4461
|
}
|
|
4232
4462
|
const oldPath = (oldPathRecord && !oldPathRecord.startsWith("#") ? oldPathRecord : void 0) ?? inlinePathParts[1] ?? (pathTokens.length > 1 ? pathTokens[pathTokens.length - 1] : void 0);
|
|
4233
|
-
pushChange({ path:
|
|
4463
|
+
pushChange({ path: path10, oldPath }, xy, staged, modified, deleted);
|
|
4234
4464
|
}
|
|
4235
4465
|
function pushChange(change, xy, staged, modified, deleted) {
|
|
4236
4466
|
const indexStatus = xy[0];
|
|
4237
4467
|
const worktreeStatus = xy[1];
|
|
4238
4468
|
if (indexStatus && indexStatus !== "." && indexStatus !== " ") {
|
|
4239
|
-
staged.push(
|
|
4469
|
+
staged.push({
|
|
4470
|
+
...change,
|
|
4471
|
+
status: resolveGitChangeStatus(indexStatus, change.oldPath)
|
|
4472
|
+
});
|
|
4240
4473
|
}
|
|
4241
4474
|
if (!worktreeStatus || worktreeStatus === "." || worktreeStatus === " ") {
|
|
4242
4475
|
return;
|
|
4243
4476
|
}
|
|
4244
4477
|
if (worktreeStatus === "D") {
|
|
4245
|
-
deleted.push({ path: change.path });
|
|
4478
|
+
deleted.push({ path: change.path, status: "deleted" });
|
|
4246
4479
|
return;
|
|
4247
4480
|
}
|
|
4248
|
-
modified.push({
|
|
4481
|
+
modified.push({
|
|
4482
|
+
path: change.path,
|
|
4483
|
+
oldPath: change.oldPath,
|
|
4484
|
+
status: resolveGitChangeStatus(worktreeStatus, change.oldPath)
|
|
4485
|
+
});
|
|
4486
|
+
}
|
|
4487
|
+
function resolveGitChangeStatus(code, oldPath) {
|
|
4488
|
+
switch (code) {
|
|
4489
|
+
case "A":
|
|
4490
|
+
return "added";
|
|
4491
|
+
case "D":
|
|
4492
|
+
return "deleted";
|
|
4493
|
+
case "R":
|
|
4494
|
+
return "renamed";
|
|
4495
|
+
case "C":
|
|
4496
|
+
return oldPath ? "renamed" : "added";
|
|
4497
|
+
case "U":
|
|
4498
|
+
return "modified";
|
|
4499
|
+
case "M":
|
|
4500
|
+
case "T":
|
|
4501
|
+
default:
|
|
4502
|
+
return oldPath ? "renamed" : "modified";
|
|
4503
|
+
}
|
|
4249
4504
|
}
|
|
4250
4505
|
var init_status_parser = __esm({
|
|
4251
4506
|
"packages/server/src/git/status-parser.ts"() {
|
|
@@ -4315,6 +4570,40 @@ async function getGitStatus(cwd) {
|
|
|
4315
4570
|
headSubject: headSubjectOutput.trim()
|
|
4316
4571
|
};
|
|
4317
4572
|
}
|
|
4573
|
+
async function getGitHistory(cwd, limit = 5) {
|
|
4574
|
+
try {
|
|
4575
|
+
const { stdout } = await runGit(cwd, [
|
|
4576
|
+
"log",
|
|
4577
|
+
`--max-count=${Math.max(1, limit)}`,
|
|
4578
|
+
"--format=%H%x1f%h%x1f%s%x1f%an%x1f%at%x1e"
|
|
4579
|
+
]);
|
|
4580
|
+
return stdout.split("").map((record) => record.trim()).filter((record) => record.length > 0).map((record) => {
|
|
4581
|
+
const [sha = "", shortSha = "", subject = "", authorName = "", authoredAt = "0"] = record.split("");
|
|
4582
|
+
return {
|
|
4583
|
+
sha,
|
|
4584
|
+
shortSha,
|
|
4585
|
+
subject,
|
|
4586
|
+
authorName,
|
|
4587
|
+
authoredAt: Number.parseInt(authoredAt, 10) * 1e3
|
|
4588
|
+
};
|
|
4589
|
+
}).filter((entry) => entry.sha && entry.subject);
|
|
4590
|
+
} catch (error) {
|
|
4591
|
+
if (error instanceof GitError && /does not have any commits yet/i.test(error.stderr)) {
|
|
4592
|
+
return [];
|
|
4593
|
+
}
|
|
4594
|
+
throw error;
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
async function getGitCommitDiff(cwd, sha) {
|
|
4598
|
+
const { stdout } = await runGit(cwd, [
|
|
4599
|
+
"show",
|
|
4600
|
+
"--format=medium",
|
|
4601
|
+
"--no-color",
|
|
4602
|
+
"--end-of-options",
|
|
4603
|
+
sha
|
|
4604
|
+
]);
|
|
4605
|
+
return stdout;
|
|
4606
|
+
}
|
|
4318
4607
|
async function getGitStatusSummary(cwd) {
|
|
4319
4608
|
const { stdout } = await runGit(cwd, ["status", "--short"]);
|
|
4320
4609
|
return stdout.trim();
|
|
@@ -4335,12 +4624,12 @@ async function discardChanges(cwd, paths) {
|
|
|
4335
4624
|
if (paths.length === 0) return;
|
|
4336
4625
|
const trackedPaths = [];
|
|
4337
4626
|
const untrackedPaths = [];
|
|
4338
|
-
for (const
|
|
4627
|
+
for (const path10 of paths) {
|
|
4339
4628
|
try {
|
|
4340
|
-
await runGit(cwd, ["ls-files", "--error-unmatch", "--",
|
|
4341
|
-
trackedPaths.push(
|
|
4629
|
+
await runGit(cwd, ["ls-files", "--error-unmatch", "--", path10]);
|
|
4630
|
+
trackedPaths.push(path10);
|
|
4342
4631
|
} catch {
|
|
4343
|
-
untrackedPaths.push(
|
|
4632
|
+
untrackedPaths.push(path10);
|
|
4344
4633
|
}
|
|
4345
4634
|
}
|
|
4346
4635
|
if (trackedPaths.length > 0) {
|
|
@@ -4379,6 +4668,7 @@ async function runGitPush(cwd, options) {
|
|
|
4379
4668
|
if (!remote) {
|
|
4380
4669
|
remote = await getPreferredRemote(cwd) ?? void 0;
|
|
4381
4670
|
}
|
|
4671
|
+
const summaryBranch = branch ?? await getCurrentBranchName(cwd);
|
|
4382
4672
|
if (remote && branch) {
|
|
4383
4673
|
args.push(remote, `HEAD:${branch}`);
|
|
4384
4674
|
} else if (remote) {
|
|
@@ -4396,8 +4686,13 @@ async function runGitPush(cwd, options) {
|
|
|
4396
4686
|
if (options?.auth) {
|
|
4397
4687
|
await persistGitHttpCredentials(cwd, options.auth, remoteMetadata);
|
|
4398
4688
|
}
|
|
4399
|
-
|
|
4400
|
-
|
|
4689
|
+
return {
|
|
4690
|
+
success: true,
|
|
4691
|
+
message: "Push completed successfully",
|
|
4692
|
+
remote,
|
|
4693
|
+
branch: summaryBranch,
|
|
4694
|
+
updated: !isPushUpToDate(stdout, stderr)
|
|
4695
|
+
};
|
|
4401
4696
|
} catch (error) {
|
|
4402
4697
|
throw normalizeGitAuthFailure(error, {
|
|
4403
4698
|
operation: "push",
|
|
@@ -4421,6 +4716,7 @@ async function runGitPull(cwd, options) {
|
|
|
4421
4716
|
if (!remote && branch) {
|
|
4422
4717
|
remote = await getPreferredRemote(cwd) ?? "origin";
|
|
4423
4718
|
}
|
|
4719
|
+
const summaryBranch = branch ?? await getCurrentBranchName(cwd);
|
|
4424
4720
|
if (remote && branch) {
|
|
4425
4721
|
args.push(remote, branch);
|
|
4426
4722
|
}
|
|
@@ -4450,8 +4746,14 @@ async function runGitPull(cwd, options) {
|
|
|
4450
4746
|
}
|
|
4451
4747
|
}
|
|
4452
4748
|
}
|
|
4453
|
-
|
|
4454
|
-
|
|
4749
|
+
return {
|
|
4750
|
+
success: true,
|
|
4751
|
+
message: "Pull completed successfully",
|
|
4752
|
+
remote,
|
|
4753
|
+
branch: summaryBranch,
|
|
4754
|
+
updated: !isPullUpToDate(stdout, stderr),
|
|
4755
|
+
updatedFiles
|
|
4756
|
+
};
|
|
4455
4757
|
} catch (error) {
|
|
4456
4758
|
throw normalizeGitAuthFailure(error, {
|
|
4457
4759
|
operation: "pull",
|
|
@@ -4463,8 +4765,63 @@ async function runGitPull(cwd, options) {
|
|
|
4463
4765
|
await authExecution.cleanup();
|
|
4464
4766
|
}
|
|
4465
4767
|
}
|
|
4768
|
+
async function runGitFetch(cwd, options) {
|
|
4769
|
+
const args = ["fetch"];
|
|
4770
|
+
const remote = options?.remote;
|
|
4771
|
+
const metadataRemote = remote ?? await getPreferredRemote(cwd) ?? void 0;
|
|
4772
|
+
const prune = options?.prune ?? true;
|
|
4773
|
+
if (remote) {
|
|
4774
|
+
args.push(remote);
|
|
4775
|
+
} else {
|
|
4776
|
+
args.push("--all");
|
|
4777
|
+
}
|
|
4778
|
+
if (prune) {
|
|
4779
|
+
args.push("--prune");
|
|
4780
|
+
}
|
|
4781
|
+
const remoteUrl = metadataRemote ? await getRemoteUrl(cwd, metadataRemote) : null;
|
|
4782
|
+
const remoteMetadata = parseRemoteUrlMetadata(remoteUrl ?? void 0);
|
|
4783
|
+
const authExecution = await prepareGitAuthExecution(options?.auth, remoteMetadata);
|
|
4784
|
+
try {
|
|
4785
|
+
const { stdout, stderr } = await runGit(cwd, args, {
|
|
4786
|
+
timeoutMs: options?.timeoutMs ?? GIT_NETWORK_TIMEOUT_MS,
|
|
4787
|
+
env: authExecution.env,
|
|
4788
|
+
config: authExecution.config
|
|
4789
|
+
});
|
|
4790
|
+
if (options?.auth) {
|
|
4791
|
+
await persistGitHttpCredentials(cwd, options.auth, remoteMetadata);
|
|
4792
|
+
}
|
|
4793
|
+
const message = stdout || stderr || "Fetch completed successfully";
|
|
4794
|
+
return {
|
|
4795
|
+
success: true,
|
|
4796
|
+
message,
|
|
4797
|
+
updatedRefs: parseFetchUpdatedRefs(stderr)
|
|
4798
|
+
};
|
|
4799
|
+
} catch (error) {
|
|
4800
|
+
throw normalizeGitAuthFailure(error, {
|
|
4801
|
+
operation: "fetch",
|
|
4802
|
+
remote: metadataRemote,
|
|
4803
|
+
remoteUrl: remoteMetadata.sanitizedUrl ?? remoteUrl ?? void 0,
|
|
4804
|
+
attemptedCredentialAuth: Boolean(options?.auth)
|
|
4805
|
+
});
|
|
4806
|
+
} finally {
|
|
4807
|
+
await authExecution.cleanup();
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
function parseFetchUpdatedRefs(stderr) {
|
|
4811
|
+
const refs = [];
|
|
4812
|
+
for (const rawLine of stderr.split("\n")) {
|
|
4813
|
+
const line = rawLine.trimEnd();
|
|
4814
|
+
const arrowIndex = line.indexOf(" -> ");
|
|
4815
|
+
if (arrowIndex < 0) continue;
|
|
4816
|
+
const target = line.slice(arrowIndex + 4).trim();
|
|
4817
|
+
if (!target) continue;
|
|
4818
|
+
refs.push(target);
|
|
4819
|
+
}
|
|
4820
|
+
return refs;
|
|
4821
|
+
}
|
|
4466
4822
|
async function runGitCheckout(cwd, ref, options) {
|
|
4467
4823
|
const args = ["checkout"];
|
|
4824
|
+
const formatCheckoutError = (error, fallbackMessage) => error instanceof GitError ? error.stderr.trim() || error.message || fallbackMessage : fallbackMessage;
|
|
4468
4825
|
let isRemoteRef = false;
|
|
4469
4826
|
try {
|
|
4470
4827
|
const { stdout: remoteList } = await runGit(cwd, ["remote"]);
|
|
@@ -4476,15 +4833,22 @@ async function runGitCheckout(cwd, ref, options) {
|
|
|
4476
4833
|
if (isRemoteRef && !options?.createBranch) {
|
|
4477
4834
|
const remoteSeparatorIndex = ref.indexOf("/");
|
|
4478
4835
|
const branchName = remoteSeparatorIndex >= 0 ? ref.slice(remoteSeparatorIndex + 1) : ref;
|
|
4479
|
-
|
|
4836
|
+
try {
|
|
4837
|
+
await runGit(cwd, ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`]);
|
|
4838
|
+
const { stdout, stderr } = await runGit(cwd, ["checkout", branchName]);
|
|
4839
|
+
const message = stdout || stderr || `Checkout to ${branchName} completed`;
|
|
4840
|
+
return { success: true, message, branch: branchName };
|
|
4841
|
+
} catch {
|
|
4842
|
+
args.push("-b", branchName, ref);
|
|
4843
|
+
}
|
|
4480
4844
|
try {
|
|
4481
4845
|
const { stdout, stderr } = await runGit(cwd, args);
|
|
4482
4846
|
const message = stdout || stderr || `Checkout to ${ref} completed`;
|
|
4483
4847
|
return { success: true, message, branch: branchName };
|
|
4484
|
-
} catch {
|
|
4848
|
+
} catch (error) {
|
|
4485
4849
|
return {
|
|
4486
4850
|
success: false,
|
|
4487
|
-
message: `Failed to checkout remote branch '${ref}'`
|
|
4851
|
+
message: formatCheckoutError(error, `Failed to checkout remote branch '${ref}'`)
|
|
4488
4852
|
};
|
|
4489
4853
|
}
|
|
4490
4854
|
} else {
|
|
@@ -4498,10 +4862,10 @@ async function runGitCheckout(cwd, ref, options) {
|
|
|
4498
4862
|
const branch = branchMatch?.[1] ?? ref;
|
|
4499
4863
|
const message = stdout || stderr || `Checkout to ${ref} completed`;
|
|
4500
4864
|
return { success: true, message, branch };
|
|
4501
|
-
} catch {
|
|
4865
|
+
} catch (error) {
|
|
4502
4866
|
return {
|
|
4503
4867
|
success: false,
|
|
4504
|
-
message: `Failed to checkout '${ref}'`
|
|
4868
|
+
message: formatCheckoutError(error, `Failed to checkout '${ref}'`)
|
|
4505
4869
|
};
|
|
4506
4870
|
}
|
|
4507
4871
|
}
|
|
@@ -4516,23 +4880,42 @@ async function runGitCreateBranch(cwd, branchName, options) {
|
|
|
4516
4880
|
}
|
|
4517
4881
|
async function runGitListBranches(cwd) {
|
|
4518
4882
|
const { stdout: localOutput } = await runGit(cwd, ["branch", "--list"]);
|
|
4883
|
+
const { stdout: localVerboseOutput } = await runGit(cwd, ["branch", "--list", "-vv"]);
|
|
4519
4884
|
const { stdout: remoteOutput } = await runGit(cwd, ["branch", "-r"]);
|
|
4520
4885
|
const branches = [];
|
|
4521
4886
|
let current = "";
|
|
4887
|
+
const linkedWorktreePathsByBranch = /* @__PURE__ */ new Map();
|
|
4888
|
+
const localVerboseLines = localVerboseOutput.split("\n").filter((line) => line.trim());
|
|
4889
|
+
for (const line of localVerboseLines) {
|
|
4890
|
+
const normalizedLine = line.replace(/^[*+ ]\s+/, "");
|
|
4891
|
+
const branchMatch = normalizedLine.match(/^([^\s]+)\s+/);
|
|
4892
|
+
const worktreeMatch = line.match(/\((.+?)\)\s/);
|
|
4893
|
+
if (!branchMatch?.[1] || !worktreeMatch?.[1]) {
|
|
4894
|
+
continue;
|
|
4895
|
+
}
|
|
4896
|
+
const worktreePath = worktreeMatch[1];
|
|
4897
|
+
if (worktreePath.startsWith("/") || worktreePath.startsWith("~")) {
|
|
4898
|
+
linkedWorktreePathsByBranch.set(branchMatch[1], worktreePath);
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4522
4901
|
const localLines = localOutput.split("\n").filter((line) => line.trim());
|
|
4523
4902
|
for (const line of localLines) {
|
|
4524
4903
|
const isCurrent = line.startsWith("*");
|
|
4525
|
-
const name = line.replace(
|
|
4904
|
+
const name = line.replace(/^[*+ ]\s+/, "").trim();
|
|
4526
4905
|
if (name.startsWith("(HEAD detached")) {
|
|
4527
4906
|
if (isCurrent) {
|
|
4528
4907
|
current = "";
|
|
4529
4908
|
}
|
|
4530
4909
|
continue;
|
|
4531
4910
|
}
|
|
4911
|
+
if (linkedWorktreePathsByBranch.has(name) && !isCurrent) {
|
|
4912
|
+
continue;
|
|
4913
|
+
}
|
|
4532
4914
|
branches.push({
|
|
4533
4915
|
name,
|
|
4534
4916
|
isRemote: false,
|
|
4535
|
-
isCurrent
|
|
4917
|
+
isCurrent,
|
|
4918
|
+
linkedWorktreePath: linkedWorktreePathsByBranch.get(name)
|
|
4536
4919
|
});
|
|
4537
4920
|
if (isCurrent) {
|
|
4538
4921
|
current = name;
|
|
@@ -4580,6 +4963,23 @@ async function resolveRemoteBranchTarget(cwd, mode) {
|
|
|
4580
4963
|
return null;
|
|
4581
4964
|
}
|
|
4582
4965
|
}
|
|
4966
|
+
async function getCurrentBranchName(cwd) {
|
|
4967
|
+
try {
|
|
4968
|
+
const { stdout } = await runGit(cwd, ["branch", "--show-current"]);
|
|
4969
|
+
const branch = stdout.trim();
|
|
4970
|
+
return branch || void 0;
|
|
4971
|
+
} catch {
|
|
4972
|
+
return void 0;
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
function isPushUpToDate(stdout, stderr) {
|
|
4976
|
+
return /Everything up-to-date/i.test(`${stdout}
|
|
4977
|
+
${stderr}`);
|
|
4978
|
+
}
|
|
4979
|
+
function isPullUpToDate(stdout, stderr) {
|
|
4980
|
+
return /Already up[ -]to[ -]date\.?/i.test(`${stdout}
|
|
4981
|
+
${stderr}`);
|
|
4982
|
+
}
|
|
4583
4983
|
async function getPreferredRemote(cwd) {
|
|
4584
4984
|
try {
|
|
4585
4985
|
const { stdout } = await runGit(cwd, ["remote"]);
|
|
@@ -4964,7 +5364,7 @@ var init_context_builder = __esm({
|
|
|
4964
5364
|
});
|
|
4965
5365
|
|
|
4966
5366
|
// packages/server/src/terminal/pty-host.ts
|
|
4967
|
-
import { chmodSync, existsSync as existsSync7, statSync } from "node:fs";
|
|
5367
|
+
import { chmodSync as chmodSync2, existsSync as existsSync7, statSync } from "node:fs";
|
|
4968
5368
|
import { createRequire } from "node:module";
|
|
4969
5369
|
import path6 from "node:path";
|
|
4970
5370
|
function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
@@ -4976,7 +5376,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
4976
5376
|
const resolve4 = deps.resolve ?? ((id) => require2.resolve(id));
|
|
4977
5377
|
const fileExists = deps.existsSync ?? existsSync7;
|
|
4978
5378
|
const stat7 = deps.statSync ?? statSync;
|
|
4979
|
-
const chmod = deps.chmodSync ??
|
|
5379
|
+
const chmod = deps.chmodSync ?? chmodSync2;
|
|
4980
5380
|
let packageJsonPath;
|
|
4981
5381
|
try {
|
|
4982
5382
|
packageJsonPath = resolve4(NODE_PTY_PKG);
|
|
@@ -7011,14 +7411,14 @@ var init_manager3 = __esm({
|
|
|
7011
7411
|
// packages/server/src/workspace/validator.ts
|
|
7012
7412
|
import { constants } from "fs";
|
|
7013
7413
|
import { access, stat as stat5 } from "fs/promises";
|
|
7014
|
-
async function validatePath(
|
|
7414
|
+
async function validatePath(path10) {
|
|
7015
7415
|
try {
|
|
7016
|
-
const stats = await stat5(
|
|
7416
|
+
const stats = await stat5(path10);
|
|
7017
7417
|
if (!stats.isDirectory()) {
|
|
7018
7418
|
return { valid: false, error: "Path is not a directory" };
|
|
7019
7419
|
}
|
|
7020
|
-
await access(
|
|
7021
|
-
await access(
|
|
7420
|
+
await access(path10, constants.R_OK);
|
|
7421
|
+
await access(path10, constants.W_OK);
|
|
7022
7422
|
return { valid: true };
|
|
7023
7423
|
} catch (error) {
|
|
7024
7424
|
if (error.code === "ENOENT") {
|
|
@@ -7035,8 +7435,8 @@ var init_validator = __esm({
|
|
|
7035
7435
|
"packages/server/src/workspace/validator.ts"() {
|
|
7036
7436
|
"use strict";
|
|
7037
7437
|
WorkspaceValidator = class {
|
|
7038
|
-
async validate(
|
|
7039
|
-
const result = await validatePath(
|
|
7438
|
+
async validate(path10) {
|
|
7439
|
+
const result = await validatePath(path10);
|
|
7040
7440
|
if (!result.valid) {
|
|
7041
7441
|
throw new Error(`Invalid workspace path: ${result.error}`);
|
|
7042
7442
|
}
|
|
@@ -7048,12 +7448,12 @@ var init_validator = __esm({
|
|
|
7048
7448
|
// packages/server/src/fs/gitignore.ts
|
|
7049
7449
|
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
|
|
7050
7450
|
import ignore from "ignore";
|
|
7051
|
-
import { join as join5, relative } from "path";
|
|
7052
|
-
function normalizePath(
|
|
7053
|
-
return
|
|
7451
|
+
import { join as join5, relative as relative3 } from "path";
|
|
7452
|
+
function normalizePath(path10) {
|
|
7453
|
+
return path10.replace(/\\/g, "/");
|
|
7054
7454
|
}
|
|
7055
|
-
function relativeToRoot(rootPath,
|
|
7056
|
-
return normalizePath(
|
|
7455
|
+
function relativeToRoot(rootPath, path10) {
|
|
7456
|
+
return normalizePath(relative3(rootPath, path10));
|
|
7057
7457
|
}
|
|
7058
7458
|
function isDefaultTreeIgnored(name) {
|
|
7059
7459
|
return name.startsWith(".") || name === "node_modules" || name === ".git";
|
|
@@ -7061,11 +7461,11 @@ function isDefaultTreeIgnored(name) {
|
|
|
7061
7461
|
function isAlwaysTreeIgnored(name) {
|
|
7062
7462
|
return name === "node_modules" || name === ".git";
|
|
7063
7463
|
}
|
|
7064
|
-
function isIgnoredByGitignore(ig,
|
|
7065
|
-
if (!
|
|
7464
|
+
function isIgnoredByGitignore(ig, path10) {
|
|
7465
|
+
if (!path10 || path10.startsWith("..")) {
|
|
7066
7466
|
return false;
|
|
7067
7467
|
}
|
|
7068
|
-
return ig.ignores(
|
|
7468
|
+
return ig.ignores(path10) || ig.ignores(`${path10}/`);
|
|
7069
7469
|
}
|
|
7070
7470
|
function createGitignoreFilter(rootPath, dirPath) {
|
|
7071
7471
|
const gitignorePath = join5(rootPath, ".gitignore");
|
|
@@ -7085,16 +7485,16 @@ function createGitignoreFilter(rootPath, dirPath) {
|
|
|
7085
7485
|
function createWatcherIgnoreFilter(rootPath) {
|
|
7086
7486
|
const gitignorePath = join5(rootPath, ".gitignore");
|
|
7087
7487
|
if (!existsSync8(gitignorePath)) {
|
|
7088
|
-
return (
|
|
7488
|
+
return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
|
|
7089
7489
|
}
|
|
7090
7490
|
const gitignoreContent = readFileSync7(gitignorePath, "utf-8");
|
|
7091
7491
|
const ig = ignore().add(gitignoreContent);
|
|
7092
|
-
return (
|
|
7093
|
-
const normalizedPath = normalizePath(
|
|
7492
|
+
return (path10) => {
|
|
7493
|
+
const normalizedPath = normalizePath(path10);
|
|
7094
7494
|
if (DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizedPath))) {
|
|
7095
7495
|
return true;
|
|
7096
7496
|
}
|
|
7097
|
-
const relativePath = relativeToRoot(rootPath,
|
|
7497
|
+
const relativePath = relativeToRoot(rootPath, path10);
|
|
7098
7498
|
return isIgnoredByGitignore(ig, relativePath);
|
|
7099
7499
|
};
|
|
7100
7500
|
}
|
|
@@ -7214,6 +7614,11 @@ var init_manager4 = __esm({
|
|
|
7214
7614
|
new WorkspaceWatcher(workspaceId, rootPath, this.deps.broadcaster)
|
|
7215
7615
|
);
|
|
7216
7616
|
}
|
|
7617
|
+
hydrateWatchers() {
|
|
7618
|
+
for (const workspace of this.list()) {
|
|
7619
|
+
this.startWatcher(workspace.id, workspace.path);
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7217
7622
|
updateUiState(workspaceId, uiState) {
|
|
7218
7623
|
const workspace = this.get(workspaceId);
|
|
7219
7624
|
if (!workspace) {
|
|
@@ -7248,6 +7653,7 @@ var init_manager4 = __esm({
|
|
|
7248
7653
|
workspaceId: existing.id,
|
|
7249
7654
|
patch: { lastActiveAt: Date.now() }
|
|
7250
7655
|
});
|
|
7656
|
+
this.deps.autoFetch?.triggerOpenTimeFetch(existing.id);
|
|
7251
7657
|
return existing;
|
|
7252
7658
|
}
|
|
7253
7659
|
const workspace = {
|
|
@@ -7285,6 +7691,7 @@ var init_manager4 = __esm({
|
|
|
7285
7691
|
patch: workspace
|
|
7286
7692
|
});
|
|
7287
7693
|
this.startWatcher(workspace.id, workspace.path);
|
|
7694
|
+
this.deps.autoFetch?.triggerOpenTimeFetch(workspace.id);
|
|
7288
7695
|
return workspace;
|
|
7289
7696
|
}
|
|
7290
7697
|
/**
|
|
@@ -7369,12 +7776,12 @@ var init_manager4 = __esm({
|
|
|
7369
7776
|
* @param path - Workspace path
|
|
7370
7777
|
* @returns Workspace or undefined
|
|
7371
7778
|
*/
|
|
7372
|
-
getByPath(
|
|
7779
|
+
getByPath(path10) {
|
|
7373
7780
|
const row = this.deps.db.prepare(
|
|
7374
7781
|
`SELECT id, path, target_runtime, wsl_distro, opened_at, last_active_at, ui_state
|
|
7375
7782
|
FROM workspaces
|
|
7376
7783
|
WHERE path = ?`
|
|
7377
|
-
).get(
|
|
7784
|
+
).get(path10);
|
|
7378
7785
|
if (!row) return void 0;
|
|
7379
7786
|
return {
|
|
7380
7787
|
id: row.id,
|
|
@@ -7395,13 +7802,87 @@ var init_manager4 = __esm({
|
|
|
7395
7802
|
const now = Date.now();
|
|
7396
7803
|
this.deps.db.prepare("UPDATE workspaces SET last_active_at = ? WHERE id = ?").run(now, workspaceId);
|
|
7397
7804
|
}
|
|
7805
|
+
recordFetch(workspaceId) {
|
|
7806
|
+
this.deps.autoFetch?.recordSuccess(workspaceId);
|
|
7807
|
+
}
|
|
7398
7808
|
};
|
|
7399
7809
|
}
|
|
7400
7810
|
});
|
|
7401
7811
|
|
|
7402
|
-
// packages/server/src/ws/
|
|
7403
|
-
|
|
7404
|
-
|
|
7812
|
+
// packages/server/src/ws/dispatch.ts
|
|
7813
|
+
function registerCommand(op, schema, handler) {
|
|
7814
|
+
handlers.set(op, handler);
|
|
7815
|
+
schemas.set(op, schema);
|
|
7816
|
+
}
|
|
7817
|
+
async function dispatch(msg, ctx, clientId) {
|
|
7818
|
+
const handler = handlers.get(msg.op);
|
|
7819
|
+
if (!handler) {
|
|
7820
|
+
return {
|
|
7821
|
+
kind: "result",
|
|
7822
|
+
id: msg.id,
|
|
7823
|
+
ok: false,
|
|
7824
|
+
error: {
|
|
7825
|
+
code: "unknown_op",
|
|
7826
|
+
message: `Unknown operation: ${msg.op}`
|
|
7827
|
+
}
|
|
7828
|
+
};
|
|
7829
|
+
}
|
|
7830
|
+
try {
|
|
7831
|
+
const schema = schemas.get(msg.op);
|
|
7832
|
+
let args = msg.args;
|
|
7833
|
+
if (schema) {
|
|
7834
|
+
args = schema.parse(msg.args);
|
|
7835
|
+
}
|
|
7836
|
+
const data = await handler(args, ctx, clientId);
|
|
7837
|
+
return {
|
|
7838
|
+
kind: "result",
|
|
7839
|
+
id: msg.id,
|
|
7840
|
+
ok: true,
|
|
7841
|
+
data
|
|
7842
|
+
};
|
|
7843
|
+
} catch (error) {
|
|
7844
|
+
const normalizedError = normalizeError(error);
|
|
7845
|
+
return {
|
|
7846
|
+
kind: "result",
|
|
7847
|
+
id: msg.id,
|
|
7848
|
+
ok: false,
|
|
7849
|
+
error: normalizedError
|
|
7850
|
+
};
|
|
7851
|
+
}
|
|
7852
|
+
}
|
|
7853
|
+
function normalizeError(error) {
|
|
7854
|
+
const candidate = error;
|
|
7855
|
+
if (candidate.name === "ZodError") {
|
|
7856
|
+
return {
|
|
7857
|
+
code: "validation_error",
|
|
7858
|
+
message: "Invalid arguments",
|
|
7859
|
+
details: candidate.errors
|
|
7860
|
+
};
|
|
7861
|
+
}
|
|
7862
|
+
if (candidate.code) {
|
|
7863
|
+
return {
|
|
7864
|
+
code: candidate.code,
|
|
7865
|
+
message: candidate.message ?? String(candidate.code),
|
|
7866
|
+
details: candidate.details
|
|
7867
|
+
};
|
|
7868
|
+
}
|
|
7869
|
+
return {
|
|
7870
|
+
code: "internal_error",
|
|
7871
|
+
message: candidate.message || "An internal error occurred"
|
|
7872
|
+
};
|
|
7873
|
+
}
|
|
7874
|
+
var handlers, schemas;
|
|
7875
|
+
var init_dispatch = __esm({
|
|
7876
|
+
"packages/server/src/ws/dispatch.ts"() {
|
|
7877
|
+
"use strict";
|
|
7878
|
+
handlers = /* @__PURE__ */ new Map();
|
|
7879
|
+
schemas = /* @__PURE__ */ new Map();
|
|
7880
|
+
}
|
|
7881
|
+
});
|
|
7882
|
+
|
|
7883
|
+
// packages/server/src/ws/fencing.ts
|
|
7884
|
+
var DEFAULT_OPTIONS, FencingManager;
|
|
7885
|
+
var init_fencing = __esm({
|
|
7405
7886
|
"packages/server/src/ws/fencing.ts"() {
|
|
7406
7887
|
"use strict";
|
|
7407
7888
|
DEFAULT_OPTIONS = {
|
|
@@ -7571,127 +8052,6 @@ var init_fencing = __esm({
|
|
|
7571
8052
|
}
|
|
7572
8053
|
});
|
|
7573
8054
|
|
|
7574
|
-
// packages/server/src/ws/dispatch.ts
|
|
7575
|
-
async function debounce(key, op, windowMs) {
|
|
7576
|
-
let entry = debounceMap.get(key);
|
|
7577
|
-
if (entry) {
|
|
7578
|
-
clearTimeout(entry.timer);
|
|
7579
|
-
entry.op = op;
|
|
7580
|
-
} else {
|
|
7581
|
-
let resolve4;
|
|
7582
|
-
let reject;
|
|
7583
|
-
const promise = new Promise((res, rej) => {
|
|
7584
|
-
resolve4 = res;
|
|
7585
|
-
reject = rej;
|
|
7586
|
-
});
|
|
7587
|
-
entry = {
|
|
7588
|
-
timer: void 0,
|
|
7589
|
-
promise,
|
|
7590
|
-
resolve: resolve4,
|
|
7591
|
-
reject,
|
|
7592
|
-
op
|
|
7593
|
-
};
|
|
7594
|
-
debounceMap.set(key, entry);
|
|
7595
|
-
}
|
|
7596
|
-
entry.timer = setTimeout(async () => {
|
|
7597
|
-
debounceMap.delete(key);
|
|
7598
|
-
try {
|
|
7599
|
-
const result = await entry.op();
|
|
7600
|
-
entry.resolve(result);
|
|
7601
|
-
} catch (err) {
|
|
7602
|
-
entry.reject(err);
|
|
7603
|
-
}
|
|
7604
|
-
}, windowMs);
|
|
7605
|
-
return entry.promise;
|
|
7606
|
-
}
|
|
7607
|
-
function registerCommand(op, schema, handler) {
|
|
7608
|
-
handlers.set(op, handler);
|
|
7609
|
-
schemas.set(op, schema);
|
|
7610
|
-
}
|
|
7611
|
-
async function dispatch(msg, ctx, clientId) {
|
|
7612
|
-
const handler = handlers.get(msg.op);
|
|
7613
|
-
if (!handler) {
|
|
7614
|
-
return {
|
|
7615
|
-
kind: "result",
|
|
7616
|
-
id: msg.id,
|
|
7617
|
-
ok: false,
|
|
7618
|
-
error: {
|
|
7619
|
-
code: "unknown_op",
|
|
7620
|
-
message: `Unknown operation: ${msg.op}`
|
|
7621
|
-
}
|
|
7622
|
-
};
|
|
7623
|
-
}
|
|
7624
|
-
try {
|
|
7625
|
-
const schema = schemas.get(msg.op);
|
|
7626
|
-
let args = msg.args;
|
|
7627
|
-
if (schema) {
|
|
7628
|
-
args = schema.parse(msg.args);
|
|
7629
|
-
}
|
|
7630
|
-
const data = await executeWithDebounce(msg.op, args, ctx, clientId);
|
|
7631
|
-
return {
|
|
7632
|
-
kind: "result",
|
|
7633
|
-
id: msg.id,
|
|
7634
|
-
ok: true,
|
|
7635
|
-
data
|
|
7636
|
-
};
|
|
7637
|
-
} catch (error) {
|
|
7638
|
-
const normalizedError = normalizeError(error);
|
|
7639
|
-
return {
|
|
7640
|
-
kind: "result",
|
|
7641
|
-
id: msg.id,
|
|
7642
|
-
ok: false,
|
|
7643
|
-
error: normalizedError
|
|
7644
|
-
};
|
|
7645
|
-
}
|
|
7646
|
-
}
|
|
7647
|
-
async function executeWithDebounce(op, args, ctx, clientId) {
|
|
7648
|
-
const handler = handlers.get(op);
|
|
7649
|
-
if (op === "git.status") {
|
|
7650
|
-
const workspaceId = getWorkspaceId(args);
|
|
7651
|
-
const key = workspaceId ? `git.status:${workspaceId}` : op;
|
|
7652
|
-
return debounce(key, () => handler(args, ctx, clientId), DEBOUNCE_GIT_STATUS_MS);
|
|
7653
|
-
}
|
|
7654
|
-
return handler(args, ctx, clientId);
|
|
7655
|
-
}
|
|
7656
|
-
function getWorkspaceId(args) {
|
|
7657
|
-
if (typeof args !== "object" || args === null || !("workspaceId" in args)) {
|
|
7658
|
-
return void 0;
|
|
7659
|
-
}
|
|
7660
|
-
const workspaceId = args.workspaceId;
|
|
7661
|
-
return typeof workspaceId === "string" ? workspaceId : void 0;
|
|
7662
|
-
}
|
|
7663
|
-
function normalizeError(error) {
|
|
7664
|
-
const candidate = error;
|
|
7665
|
-
if (candidate.name === "ZodError") {
|
|
7666
|
-
return {
|
|
7667
|
-
code: "validation_error",
|
|
7668
|
-
message: "Invalid arguments",
|
|
7669
|
-
details: candidate.errors
|
|
7670
|
-
};
|
|
7671
|
-
}
|
|
7672
|
-
if (candidate.code) {
|
|
7673
|
-
return {
|
|
7674
|
-
code: candidate.code,
|
|
7675
|
-
message: candidate.message ?? String(candidate.code),
|
|
7676
|
-
details: candidate.details
|
|
7677
|
-
};
|
|
7678
|
-
}
|
|
7679
|
-
return {
|
|
7680
|
-
code: "internal_error",
|
|
7681
|
-
message: candidate.message || "An internal error occurred"
|
|
7682
|
-
};
|
|
7683
|
-
}
|
|
7684
|
-
var handlers, schemas, debounceMap, DEBOUNCE_GIT_STATUS_MS;
|
|
7685
|
-
var init_dispatch = __esm({
|
|
7686
|
-
"packages/server/src/ws/dispatch.ts"() {
|
|
7687
|
-
"use strict";
|
|
7688
|
-
handlers = /* @__PURE__ */ new Map();
|
|
7689
|
-
schemas = /* @__PURE__ */ new Map();
|
|
7690
|
-
debounceMap = /* @__PURE__ */ new Map();
|
|
7691
|
-
DEBOUNCE_GIT_STATUS_MS = 500;
|
|
7692
|
-
}
|
|
7693
|
-
});
|
|
7694
|
-
|
|
7695
8055
|
// packages/server/src/commands/terminal.ts
|
|
7696
8056
|
import { basename as basename2 } from "node:path";
|
|
7697
8057
|
import { z as z5 } from "zod";
|
|
@@ -8540,6 +8900,7 @@ var init_hub = __esm({
|
|
|
8540
8900
|
handleClose(client) {
|
|
8541
8901
|
this.clients.delete(client.id);
|
|
8542
8902
|
this.discardPendingBinaryWaiters(client.id);
|
|
8903
|
+
this.deps.commandContext?.autoFetch.unregisterViewer(client.id);
|
|
8543
8904
|
}
|
|
8544
8905
|
/**
|
|
8545
8906
|
* Takeover: Force close existing writer and accept new one
|
|
@@ -8732,7 +9093,7 @@ var init_hub = __esm({
|
|
|
8732
9093
|
|
|
8733
9094
|
// packages/server/src/commands/workspace.ts
|
|
8734
9095
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
8735
|
-
import { homedir as
|
|
9096
|
+
import { homedir as homedir3 } from "node:os";
|
|
8736
9097
|
import { join as join6 } from "node:path";
|
|
8737
9098
|
import { z as z6 } from "zod";
|
|
8738
9099
|
var init_workspace = __esm({
|
|
@@ -8748,7 +9109,7 @@ var init_workspace = __esm({
|
|
|
8748
9109
|
path: z6.string().optional()
|
|
8749
9110
|
}),
|
|
8750
9111
|
async (args) => {
|
|
8751
|
-
const basePath = args.path ||
|
|
9112
|
+
const basePath = args.path || homedir3();
|
|
8752
9113
|
const entries = await readdir2(basePath, { withFileTypes: true });
|
|
8753
9114
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
8754
9115
|
name: entry.name,
|
|
@@ -8821,6 +9182,35 @@ var init_workspace = __esm({
|
|
|
8821
9182
|
}
|
|
8822
9183
|
});
|
|
8823
9184
|
|
|
9185
|
+
// packages/server/src/commands/workspace-activity.ts
|
|
9186
|
+
import { z as z7 } from "zod";
|
|
9187
|
+
var init_workspace_activity = __esm({
|
|
9188
|
+
"packages/server/src/commands/workspace-activity.ts"() {
|
|
9189
|
+
"use strict";
|
|
9190
|
+
init_dispatch();
|
|
9191
|
+
registerCommand(
|
|
9192
|
+
"workspace.activate",
|
|
9193
|
+
z7.object({
|
|
9194
|
+
workspaceId: z7.string()
|
|
9195
|
+
}),
|
|
9196
|
+
async (args, ctx, clientId) => {
|
|
9197
|
+
if (!clientId) {
|
|
9198
|
+
return {};
|
|
9199
|
+
}
|
|
9200
|
+
ctx.autoFetch.registerViewer(clientId, args.workspaceId);
|
|
9201
|
+
return {};
|
|
9202
|
+
}
|
|
9203
|
+
);
|
|
9204
|
+
registerCommand("workspace.deactivate", z7.object({}), async (_args, ctx, clientId) => {
|
|
9205
|
+
if (!clientId) {
|
|
9206
|
+
return {};
|
|
9207
|
+
}
|
|
9208
|
+
ctx.autoFetch.unregisterViewer(clientId);
|
|
9209
|
+
return {};
|
|
9210
|
+
});
|
|
9211
|
+
}
|
|
9212
|
+
});
|
|
9213
|
+
|
|
8824
9214
|
// packages/server/src/provider-runtime/runtime-status.ts
|
|
8825
9215
|
function canAutoInstall(provider, platform, missingCommands, missingPrerequisites, availableCommands) {
|
|
8826
9216
|
const strategies = provider.install.strategies[platform] ?? [];
|
|
@@ -8915,7 +9305,7 @@ var init_runtime_status = __esm({
|
|
|
8915
9305
|
});
|
|
8916
9306
|
|
|
8917
9307
|
// packages/server/src/commands/session.ts
|
|
8918
|
-
import { z as
|
|
9308
|
+
import { z as z8 } from "zod";
|
|
8919
9309
|
function getProviderFromRegistry(providerId, registry) {
|
|
8920
9310
|
return registry.find((provider) => provider.id === providerId);
|
|
8921
9311
|
}
|
|
@@ -8926,8 +9316,8 @@ var init_session = __esm({
|
|
|
8926
9316
|
init_dispatch();
|
|
8927
9317
|
registerCommand(
|
|
8928
9318
|
"session.list",
|
|
8929
|
-
|
|
8930
|
-
workspaceId:
|
|
9319
|
+
z8.object({
|
|
9320
|
+
workspaceId: z8.string()
|
|
8931
9321
|
}),
|
|
8932
9322
|
async (args, ctx) => {
|
|
8933
9323
|
return ctx.sessionMgr.getForWorkspace(args.workspaceId);
|
|
@@ -8935,10 +9325,10 @@ var init_session = __esm({
|
|
|
8935
9325
|
);
|
|
8936
9326
|
registerCommand(
|
|
8937
9327
|
"session.create",
|
|
8938
|
-
|
|
8939
|
-
workspaceId:
|
|
8940
|
-
providerId:
|
|
8941
|
-
draft:
|
|
9328
|
+
z8.object({
|
|
9329
|
+
workspaceId: z8.string(),
|
|
9330
|
+
providerId: z8.string(),
|
|
9331
|
+
draft: z8.string().optional()
|
|
8942
9332
|
}),
|
|
8943
9333
|
async (args, ctx) => {
|
|
8944
9334
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -8972,8 +9362,8 @@ var init_session = __esm({
|
|
|
8972
9362
|
);
|
|
8973
9363
|
registerCommand(
|
|
8974
9364
|
"session.stop",
|
|
8975
|
-
|
|
8976
|
-
sessionId:
|
|
9365
|
+
z8.object({
|
|
9366
|
+
sessionId: z8.string()
|
|
8977
9367
|
}),
|
|
8978
9368
|
async (args, ctx) => {
|
|
8979
9369
|
await ctx.sessionMgr.stop(args.sessionId);
|
|
@@ -8981,8 +9371,8 @@ var init_session = __esm({
|
|
|
8981
9371
|
);
|
|
8982
9372
|
registerCommand(
|
|
8983
9373
|
"session.remove",
|
|
8984
|
-
|
|
8985
|
-
sessionId:
|
|
9374
|
+
z8.object({
|
|
9375
|
+
sessionId: z8.string()
|
|
8986
9376
|
}),
|
|
8987
9377
|
async (args, ctx) => {
|
|
8988
9378
|
const session = ctx.sessionMgr.get(args.sessionId);
|
|
@@ -9000,7 +9390,7 @@ var init_session = __esm({
|
|
|
9000
9390
|
|
|
9001
9391
|
// packages/server/src/fs/tree.ts
|
|
9002
9392
|
import { readdir as readdir3, stat as stat6 } from "fs/promises";
|
|
9003
|
-
import { join as join7, relative as
|
|
9393
|
+
import { join as join7, relative as relative4 } from "path";
|
|
9004
9394
|
async function readTree(rootPath, subdir) {
|
|
9005
9395
|
const targetPath = subdir ? join7(rootPath, subdir) : rootPath;
|
|
9006
9396
|
const filter = createGitignoreFilter(rootPath, targetPath);
|
|
@@ -9011,7 +9401,7 @@ async function readTree(rootPath, subdir) {
|
|
|
9011
9401
|
continue;
|
|
9012
9402
|
}
|
|
9013
9403
|
const fullPath = join7(targetPath, entry.name);
|
|
9014
|
-
const relPath =
|
|
9404
|
+
const relPath = relative4(rootPath, fullPath);
|
|
9015
9405
|
if (entry.isDirectory()) {
|
|
9016
9406
|
nodes.push({
|
|
9017
9407
|
name: entry.name,
|
|
@@ -9055,7 +9445,7 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
9055
9445
|
filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
9056
9446
|
for (const entry of filteredEntries) {
|
|
9057
9447
|
const fullPath = join7(dirPath, entry.name);
|
|
9058
|
-
const relPath =
|
|
9448
|
+
const relPath = relative4(rootPath, fullPath);
|
|
9059
9449
|
if (entry.isDirectory()) {
|
|
9060
9450
|
await walk(fullPath);
|
|
9061
9451
|
continue;
|
|
@@ -9147,7 +9537,7 @@ var init_tree = __esm({
|
|
|
9147
9537
|
});
|
|
9148
9538
|
|
|
9149
9539
|
// packages/server/src/commands/file.ts
|
|
9150
|
-
import { z as
|
|
9540
|
+
import { z as z9 } from "zod";
|
|
9151
9541
|
var init_file = __esm({
|
|
9152
9542
|
"packages/server/src/commands/file.ts"() {
|
|
9153
9543
|
"use strict";
|
|
@@ -9156,9 +9546,9 @@ var init_file = __esm({
|
|
|
9156
9546
|
init_dispatch();
|
|
9157
9547
|
registerCommand(
|
|
9158
9548
|
"file.readTree",
|
|
9159
|
-
|
|
9160
|
-
workspaceId:
|
|
9161
|
-
subPath:
|
|
9549
|
+
z9.object({
|
|
9550
|
+
workspaceId: z9.string(),
|
|
9551
|
+
subPath: z9.string().optional()
|
|
9162
9552
|
}),
|
|
9163
9553
|
async (args, ctx) => {
|
|
9164
9554
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9170,10 +9560,10 @@ var init_file = __esm({
|
|
|
9170
9560
|
);
|
|
9171
9561
|
registerCommand(
|
|
9172
9562
|
"file.search",
|
|
9173
|
-
|
|
9174
|
-
workspaceId:
|
|
9175
|
-
query:
|
|
9176
|
-
limit:
|
|
9563
|
+
z9.object({
|
|
9564
|
+
workspaceId: z9.string(),
|
|
9565
|
+
query: z9.string(),
|
|
9566
|
+
limit: z9.number().int().positive().max(50).optional()
|
|
9177
9567
|
}),
|
|
9178
9568
|
async (args, ctx) => {
|
|
9179
9569
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9185,9 +9575,9 @@ var init_file = __esm({
|
|
|
9185
9575
|
);
|
|
9186
9576
|
registerCommand(
|
|
9187
9577
|
"file.read",
|
|
9188
|
-
|
|
9189
|
-
workspaceId:
|
|
9190
|
-
path:
|
|
9578
|
+
z9.object({
|
|
9579
|
+
workspaceId: z9.string(),
|
|
9580
|
+
path: z9.string()
|
|
9191
9581
|
}),
|
|
9192
9582
|
async (args, ctx) => {
|
|
9193
9583
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9199,9 +9589,9 @@ var init_file = __esm({
|
|
|
9199
9589
|
);
|
|
9200
9590
|
registerCommand(
|
|
9201
9591
|
"file.create",
|
|
9202
|
-
|
|
9203
|
-
workspaceId:
|
|
9204
|
-
path:
|
|
9592
|
+
z9.object({
|
|
9593
|
+
workspaceId: z9.string(),
|
|
9594
|
+
path: z9.string()
|
|
9205
9595
|
}),
|
|
9206
9596
|
async (args, ctx) => {
|
|
9207
9597
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9219,9 +9609,9 @@ var init_file = __esm({
|
|
|
9219
9609
|
);
|
|
9220
9610
|
registerCommand(
|
|
9221
9611
|
"file.mkdir",
|
|
9222
|
-
|
|
9223
|
-
workspaceId:
|
|
9224
|
-
path:
|
|
9612
|
+
z9.object({
|
|
9613
|
+
workspaceId: z9.string(),
|
|
9614
|
+
path: z9.string()
|
|
9225
9615
|
}),
|
|
9226
9616
|
async (args, ctx) => {
|
|
9227
9617
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9239,9 +9629,9 @@ var init_file = __esm({
|
|
|
9239
9629
|
);
|
|
9240
9630
|
registerCommand(
|
|
9241
9631
|
"file.delete",
|
|
9242
|
-
|
|
9243
|
-
workspaceId:
|
|
9244
|
-
path:
|
|
9632
|
+
z9.object({
|
|
9633
|
+
workspaceId: z9.string(),
|
|
9634
|
+
path: z9.string()
|
|
9245
9635
|
}),
|
|
9246
9636
|
async (args, ctx) => {
|
|
9247
9637
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9259,11 +9649,11 @@ var init_file = __esm({
|
|
|
9259
9649
|
);
|
|
9260
9650
|
registerCommand(
|
|
9261
9651
|
"file.write",
|
|
9262
|
-
|
|
9263
|
-
workspaceId:
|
|
9264
|
-
path:
|
|
9265
|
-
content:
|
|
9266
|
-
baseHash:
|
|
9652
|
+
z9.object({
|
|
9653
|
+
workspaceId: z9.string(),
|
|
9654
|
+
path: z9.string(),
|
|
9655
|
+
content: z9.string(),
|
|
9656
|
+
baseHash: z9.string().optional()
|
|
9267
9657
|
// For conflict detection
|
|
9268
9658
|
}),
|
|
9269
9659
|
async (args, ctx) => {
|
|
@@ -9322,11 +9712,11 @@ async function getUntrackedFileDiff(cwd, filePath) {
|
|
|
9322
9712
|
await rm5(tempDir, { recursive: true, force: true });
|
|
9323
9713
|
}
|
|
9324
9714
|
}
|
|
9325
|
-
async function getFileDiff(cwd,
|
|
9326
|
-
if (!staged && !await isTrackedPath(cwd,
|
|
9327
|
-
return getUntrackedFileDiff(cwd,
|
|
9715
|
+
async function getFileDiff(cwd, path10, staged = false) {
|
|
9716
|
+
if (!staged && !await isTrackedPath(cwd, path10)) {
|
|
9717
|
+
return getUntrackedFileDiff(cwd, path10);
|
|
9328
9718
|
}
|
|
9329
|
-
const args = staged ? ["diff", "--staged", "--",
|
|
9719
|
+
const args = staged ? ["diff", "--staged", "--", path10] : ["diff", "--", path10];
|
|
9330
9720
|
const result = await runGit(cwd, args);
|
|
9331
9721
|
return result.stdout;
|
|
9332
9722
|
}
|
|
@@ -9337,8 +9727,7 @@ var init_diff = __esm({
|
|
|
9337
9727
|
}
|
|
9338
9728
|
});
|
|
9339
9729
|
|
|
9340
|
-
// packages/server/src/commands/git.ts
|
|
9341
|
-
import { z as z9 } from "zod";
|
|
9730
|
+
// packages/server/src/commands/git-events.ts
|
|
9342
9731
|
function emitGitStateChanged(ctx, workspaceId, options) {
|
|
9343
9732
|
ctx.eventBus.emit({
|
|
9344
9733
|
type: "git.state.changed",
|
|
@@ -9348,21 +9737,38 @@ function emitGitStateChanged(ctx, workspaceId, options) {
|
|
|
9348
9737
|
worktreeChanged: options?.worktreeChanged
|
|
9349
9738
|
});
|
|
9350
9739
|
}
|
|
9351
|
-
var
|
|
9740
|
+
var init_git_events = __esm({
|
|
9741
|
+
"packages/server/src/commands/git-events.ts"() {
|
|
9742
|
+
"use strict";
|
|
9743
|
+
}
|
|
9744
|
+
});
|
|
9745
|
+
|
|
9746
|
+
// packages/server/src/commands/git.ts
|
|
9747
|
+
import { z as z10 } from "zod";
|
|
9748
|
+
async function runGitNetworkOperation(ctx, workspaceId, op) {
|
|
9749
|
+
if (!ctx.autoFetch?.runExclusive) {
|
|
9750
|
+
return op();
|
|
9751
|
+
}
|
|
9752
|
+
return ctx.autoFetch.runExclusive(workspaceId, op);
|
|
9753
|
+
}
|
|
9754
|
+
var gitHttpAuthSchema, gitCommitRevisionSchema, GIT_BACKGROUND_FETCH_TIMEOUT_MS;
|
|
9352
9755
|
var init_git2 = __esm({
|
|
9353
9756
|
"packages/server/src/commands/git.ts"() {
|
|
9354
9757
|
"use strict";
|
|
9355
9758
|
init_cli();
|
|
9356
9759
|
init_diff();
|
|
9357
9760
|
init_dispatch();
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9761
|
+
init_git_events();
|
|
9762
|
+
gitHttpAuthSchema = z10.object({
|
|
9763
|
+
username: z10.string(),
|
|
9764
|
+
password: z10.string()
|
|
9361
9765
|
});
|
|
9766
|
+
gitCommitRevisionSchema = z10.string().regex(/^[0-9a-fA-F]{7,64}$/, "Invalid git commit revision");
|
|
9767
|
+
GIT_BACKGROUND_FETCH_TIMEOUT_MS = 30 * 1e3;
|
|
9362
9768
|
registerCommand(
|
|
9363
9769
|
"git.status",
|
|
9364
|
-
|
|
9365
|
-
workspaceId:
|
|
9770
|
+
z10.object({
|
|
9771
|
+
workspaceId: z10.string()
|
|
9366
9772
|
}),
|
|
9367
9773
|
async (args, ctx) => {
|
|
9368
9774
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9374,9 +9780,9 @@ var init_git2 = __esm({
|
|
|
9374
9780
|
);
|
|
9375
9781
|
registerCommand(
|
|
9376
9782
|
"git.stage",
|
|
9377
|
-
|
|
9378
|
-
workspaceId:
|
|
9379
|
-
paths:
|
|
9783
|
+
z10.object({
|
|
9784
|
+
workspaceId: z10.string(),
|
|
9785
|
+
paths: z10.array(z10.string())
|
|
9380
9786
|
}),
|
|
9381
9787
|
async (args, ctx) => {
|
|
9382
9788
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9390,10 +9796,10 @@ var init_git2 = __esm({
|
|
|
9390
9796
|
);
|
|
9391
9797
|
registerCommand(
|
|
9392
9798
|
"git.diff",
|
|
9393
|
-
|
|
9394
|
-
workspaceId:
|
|
9395
|
-
path:
|
|
9396
|
-
staged:
|
|
9799
|
+
z10.object({
|
|
9800
|
+
workspaceId: z10.string(),
|
|
9801
|
+
path: z10.string(),
|
|
9802
|
+
staged: z10.boolean().optional()
|
|
9397
9803
|
}),
|
|
9398
9804
|
async (args, ctx) => {
|
|
9399
9805
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9405,11 +9811,43 @@ var init_git2 = __esm({
|
|
|
9405
9811
|
};
|
|
9406
9812
|
}
|
|
9407
9813
|
);
|
|
9814
|
+
registerCommand(
|
|
9815
|
+
"git.log",
|
|
9816
|
+
z10.object({
|
|
9817
|
+
workspaceId: z10.string(),
|
|
9818
|
+
limit: z10.number().int().min(1).max(50).optional()
|
|
9819
|
+
}),
|
|
9820
|
+
async (args, ctx) => {
|
|
9821
|
+
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
9822
|
+
if (!workspace) {
|
|
9823
|
+
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
9824
|
+
}
|
|
9825
|
+
return {
|
|
9826
|
+
entries: await getGitHistory(workspace.path, args.limit ?? 5)
|
|
9827
|
+
};
|
|
9828
|
+
}
|
|
9829
|
+
);
|
|
9830
|
+
registerCommand(
|
|
9831
|
+
"git.show",
|
|
9832
|
+
z10.object({
|
|
9833
|
+
workspaceId: z10.string(),
|
|
9834
|
+
sha: gitCommitRevisionSchema
|
|
9835
|
+
}),
|
|
9836
|
+
async (args, ctx) => {
|
|
9837
|
+
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
9838
|
+
if (!workspace) {
|
|
9839
|
+
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
9840
|
+
}
|
|
9841
|
+
return {
|
|
9842
|
+
diff: await getGitCommitDiff(workspace.path, args.sha)
|
|
9843
|
+
};
|
|
9844
|
+
}
|
|
9845
|
+
);
|
|
9408
9846
|
registerCommand(
|
|
9409
9847
|
"git.unstage",
|
|
9410
|
-
|
|
9411
|
-
workspaceId:
|
|
9412
|
-
paths:
|
|
9848
|
+
z10.object({
|
|
9849
|
+
workspaceId: z10.string(),
|
|
9850
|
+
paths: z10.array(z10.string())
|
|
9413
9851
|
}),
|
|
9414
9852
|
async (args, ctx) => {
|
|
9415
9853
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9423,9 +9861,9 @@ var init_git2 = __esm({
|
|
|
9423
9861
|
);
|
|
9424
9862
|
registerCommand(
|
|
9425
9863
|
"git.discard",
|
|
9426
|
-
|
|
9427
|
-
workspaceId:
|
|
9428
|
-
paths:
|
|
9864
|
+
z10.object({
|
|
9865
|
+
workspaceId: z10.string(),
|
|
9866
|
+
paths: z10.array(z10.string())
|
|
9429
9867
|
}),
|
|
9430
9868
|
async (args, ctx) => {
|
|
9431
9869
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9441,9 +9879,9 @@ var init_git2 = __esm({
|
|
|
9441
9879
|
);
|
|
9442
9880
|
registerCommand(
|
|
9443
9881
|
"git.commit",
|
|
9444
|
-
|
|
9445
|
-
workspaceId:
|
|
9446
|
-
message:
|
|
9882
|
+
z10.object({
|
|
9883
|
+
workspaceId: z10.string(),
|
|
9884
|
+
message: z10.string()
|
|
9447
9885
|
}),
|
|
9448
9886
|
async (args, ctx) => {
|
|
9449
9887
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9460,11 +9898,11 @@ var init_git2 = __esm({
|
|
|
9460
9898
|
);
|
|
9461
9899
|
registerCommand(
|
|
9462
9900
|
"git.push",
|
|
9463
|
-
|
|
9464
|
-
workspaceId:
|
|
9465
|
-
remote:
|
|
9466
|
-
branch:
|
|
9467
|
-
force:
|
|
9901
|
+
z10.object({
|
|
9902
|
+
workspaceId: z10.string(),
|
|
9903
|
+
remote: z10.string().optional(),
|
|
9904
|
+
branch: z10.string().optional(),
|
|
9905
|
+
force: z10.boolean().optional(),
|
|
9468
9906
|
auth: gitHttpAuthSchema.optional()
|
|
9469
9907
|
}),
|
|
9470
9908
|
async (args, ctx) => {
|
|
@@ -9472,12 +9910,16 @@ var init_git2 = __esm({
|
|
|
9472
9910
|
if (!workspace) {
|
|
9473
9911
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
9474
9912
|
}
|
|
9475
|
-
const result = await
|
|
9476
|
-
|
|
9477
|
-
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9913
|
+
const result = await runGitNetworkOperation(
|
|
9914
|
+
ctx,
|
|
9915
|
+
args.workspaceId,
|
|
9916
|
+
() => runGitPush(workspace.path, {
|
|
9917
|
+
remote: args.remote,
|
|
9918
|
+
branch: args.branch,
|
|
9919
|
+
force: args.force,
|
|
9920
|
+
auth: args.auth
|
|
9921
|
+
})
|
|
9922
|
+
);
|
|
9481
9923
|
emitGitStateChanged(ctx, args.workspaceId, {
|
|
9482
9924
|
branchChanged: true,
|
|
9483
9925
|
worktreeChanged: true
|
|
@@ -9487,10 +9929,10 @@ var init_git2 = __esm({
|
|
|
9487
9929
|
);
|
|
9488
9930
|
registerCommand(
|
|
9489
9931
|
"git.pull",
|
|
9490
|
-
|
|
9491
|
-
workspaceId:
|
|
9492
|
-
remote:
|
|
9493
|
-
branch:
|
|
9932
|
+
z10.object({
|
|
9933
|
+
workspaceId: z10.string(),
|
|
9934
|
+
remote: z10.string().optional(),
|
|
9935
|
+
branch: z10.string().optional(),
|
|
9494
9936
|
auth: gitHttpAuthSchema.optional()
|
|
9495
9937
|
}),
|
|
9496
9938
|
async (args, ctx) => {
|
|
@@ -9498,11 +9940,16 @@ var init_git2 = __esm({
|
|
|
9498
9940
|
if (!workspace) {
|
|
9499
9941
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
9500
9942
|
}
|
|
9501
|
-
const result = await
|
|
9502
|
-
|
|
9503
|
-
|
|
9504
|
-
|
|
9505
|
-
|
|
9943
|
+
const result = await runGitNetworkOperation(
|
|
9944
|
+
ctx,
|
|
9945
|
+
args.workspaceId,
|
|
9946
|
+
() => runGitPull(workspace.path, {
|
|
9947
|
+
remote: args.remote,
|
|
9948
|
+
branch: args.branch,
|
|
9949
|
+
auth: args.auth
|
|
9950
|
+
})
|
|
9951
|
+
);
|
|
9952
|
+
ctx.workspaceMgr.recordFetch(args.workspaceId);
|
|
9506
9953
|
emitGitStateChanged(ctx, args.workspaceId, {
|
|
9507
9954
|
treeChanged: true,
|
|
9508
9955
|
branchChanged: true,
|
|
@@ -9511,12 +9958,46 @@ var init_git2 = __esm({
|
|
|
9511
9958
|
return result;
|
|
9512
9959
|
}
|
|
9513
9960
|
);
|
|
9961
|
+
registerCommand(
|
|
9962
|
+
"git.fetch",
|
|
9963
|
+
z10.object({
|
|
9964
|
+
workspaceId: z10.string(),
|
|
9965
|
+
remote: z10.string().optional(),
|
|
9966
|
+
prune: z10.boolean().optional(),
|
|
9967
|
+
auth: gitHttpAuthSchema.optional(),
|
|
9968
|
+
background: z10.boolean().optional()
|
|
9969
|
+
}),
|
|
9970
|
+
async (args, ctx, clientId) => {
|
|
9971
|
+
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
9972
|
+
if (!workspace) {
|
|
9973
|
+
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
9974
|
+
}
|
|
9975
|
+
try {
|
|
9976
|
+
const isInternalBackgroundFetch = args.background === true && !clientId;
|
|
9977
|
+
const runFetch = () => runGitFetch(workspace.path, {
|
|
9978
|
+
remote: args.remote,
|
|
9979
|
+
prune: args.prune,
|
|
9980
|
+
auth: args.auth,
|
|
9981
|
+
timeoutMs: args.background ? GIT_BACKGROUND_FETCH_TIMEOUT_MS : void 0
|
|
9982
|
+
});
|
|
9983
|
+
const result = isInternalBackgroundFetch ? await runFetch() : await runGitNetworkOperation(ctx, args.workspaceId, runFetch);
|
|
9984
|
+
ctx.workspaceMgr.recordFetch(args.workspaceId);
|
|
9985
|
+
emitGitStateChanged(ctx, args.workspaceId, { branchChanged: true });
|
|
9986
|
+
return result;
|
|
9987
|
+
} catch (err) {
|
|
9988
|
+
if (args.background && err instanceof GitAuthError) {
|
|
9989
|
+
return { success: false, message: err.message, updatedRefs: [] };
|
|
9990
|
+
}
|
|
9991
|
+
throw err;
|
|
9992
|
+
}
|
|
9993
|
+
}
|
|
9994
|
+
);
|
|
9514
9995
|
registerCommand(
|
|
9515
9996
|
"git.checkout",
|
|
9516
|
-
|
|
9517
|
-
workspaceId:
|
|
9518
|
-
ref:
|
|
9519
|
-
createBranch:
|
|
9997
|
+
z10.object({
|
|
9998
|
+
workspaceId: z10.string(),
|
|
9999
|
+
ref: z10.string(),
|
|
10000
|
+
createBranch: z10.boolean().optional()
|
|
9520
10001
|
}),
|
|
9521
10002
|
async (args, ctx) => {
|
|
9522
10003
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9538,10 +10019,10 @@ var init_git2 = __esm({
|
|
|
9538
10019
|
);
|
|
9539
10020
|
registerCommand(
|
|
9540
10021
|
"git.branch",
|
|
9541
|
-
|
|
9542
|
-
workspaceId:
|
|
9543
|
-
name:
|
|
9544
|
-
startPoint:
|
|
10022
|
+
z10.object({
|
|
10023
|
+
workspaceId: z10.string(),
|
|
10024
|
+
name: z10.string(),
|
|
10025
|
+
startPoint: z10.string().optional()
|
|
9545
10026
|
}),
|
|
9546
10027
|
async (args, ctx) => {
|
|
9547
10028
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9560,8 +10041,8 @@ var init_git2 = __esm({
|
|
|
9560
10041
|
);
|
|
9561
10042
|
registerCommand(
|
|
9562
10043
|
"git.branches",
|
|
9563
|
-
|
|
9564
|
-
workspaceId:
|
|
10044
|
+
z10.object({
|
|
10045
|
+
workspaceId: z10.string()
|
|
9565
10046
|
}),
|
|
9566
10047
|
async (args, ctx) => {
|
|
9567
10048
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -9575,8 +10056,8 @@ var init_git2 = __esm({
|
|
|
9575
10056
|
});
|
|
9576
10057
|
|
|
9577
10058
|
// packages/server/src/config/config-io.ts
|
|
9578
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync
|
|
9579
|
-
import { homedir as
|
|
10059
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
10060
|
+
import { homedir as homedir4 } from "node:os";
|
|
9580
10061
|
import { basename as basename3, dirname as dirname5, join as join8 } from "node:path";
|
|
9581
10062
|
function resolveConfigPath(configType) {
|
|
9582
10063
|
if (configType === "codex") {
|
|
@@ -9584,14 +10065,18 @@ function resolveConfigPath(configType) {
|
|
|
9584
10065
|
if (testHome && testHome.trim()) {
|
|
9585
10066
|
return join8(testHome, "config.toml");
|
|
9586
10067
|
}
|
|
9587
|
-
|
|
10068
|
+
const codexHome = process.env.CODEX_HOME;
|
|
10069
|
+
if (codexHome && codexHome.trim()) {
|
|
10070
|
+
return join8(codexHome, "config.toml");
|
|
10071
|
+
}
|
|
10072
|
+
return join8(homedir4(), ".codex", "config.toml");
|
|
9588
10073
|
}
|
|
9589
10074
|
if (configType === "claude") {
|
|
9590
10075
|
const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
|
|
9591
10076
|
if (testHome && testHome.trim()) {
|
|
9592
10077
|
return join8(testHome, "settings.json");
|
|
9593
10078
|
}
|
|
9594
|
-
return join8(
|
|
10079
|
+
return join8(homedir4(), ".claude", "settings.json");
|
|
9595
10080
|
}
|
|
9596
10081
|
throw new Error(`Unknown config type: ${configType}`);
|
|
9597
10082
|
}
|
|
@@ -9620,7 +10105,7 @@ function writeConfigFile(configType, content) {
|
|
|
9620
10105
|
}
|
|
9621
10106
|
const tempPath = `${configPath}.tmp`;
|
|
9622
10107
|
writeFileSync4(tempPath, content, "utf-8");
|
|
9623
|
-
|
|
10108
|
+
renameSync(tempPath, configPath);
|
|
9624
10109
|
return { success: true, backupPath };
|
|
9625
10110
|
} catch (error) {
|
|
9626
10111
|
return {
|
|
@@ -9635,24 +10120,23 @@ function createBackup(filePath) {
|
|
|
9635
10120
|
const ext = filePath.split(".").pop() ?? "";
|
|
9636
10121
|
const base = basename3(filePath, `.${ext}`);
|
|
9637
10122
|
const dir = dirname5(filePath);
|
|
9638
|
-
const ts =
|
|
10123
|
+
const ts = formatTimestamp(/* @__PURE__ */ new Date());
|
|
9639
10124
|
const backupPath = join8(dir, `${base}.bak.${ts}.${ext}`);
|
|
9640
10125
|
writeFileSync4(backupPath, original, "utf-8");
|
|
9641
10126
|
return backupPath;
|
|
9642
10127
|
}
|
|
9643
|
-
function
|
|
10128
|
+
function formatTimestamp(d) {
|
|
9644
10129
|
const pad = (n) => String(n).padStart(2, "0");
|
|
9645
10130
|
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
9646
10131
|
}
|
|
9647
10132
|
var init_config_io = __esm({
|
|
9648
10133
|
"packages/server/src/config/config-io.ts"() {
|
|
9649
10134
|
"use strict";
|
|
9650
|
-
init_codex_config_audit();
|
|
9651
10135
|
}
|
|
9652
10136
|
});
|
|
9653
10137
|
|
|
9654
10138
|
// packages/server/src/commands/settings.ts
|
|
9655
|
-
import { z as
|
|
10139
|
+
import { z as z11 } from "zod";
|
|
9656
10140
|
function flattenSettings(obj, prefix = "") {
|
|
9657
10141
|
const result = {};
|
|
9658
10142
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -9665,7 +10149,7 @@ function flattenSettings(obj, prefix = "") {
|
|
|
9665
10149
|
}
|
|
9666
10150
|
return result;
|
|
9667
10151
|
}
|
|
9668
|
-
var
|
|
10152
|
+
var SettingsSchema;
|
|
9669
10153
|
var init_settings2 = __esm({
|
|
9670
10154
|
"packages/server/src/commands/settings.ts"() {
|
|
9671
10155
|
"use strict";
|
|
@@ -9675,34 +10159,27 @@ var init_settings2 = __esm({
|
|
|
9675
10159
|
init_provider_config_repo();
|
|
9676
10160
|
init_settings();
|
|
9677
10161
|
init_dispatch();
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
|
|
9683
|
-
}
|
|
9684
|
-
};
|
|
9685
|
-
SettingsSchema = z10.object({
|
|
9686
|
-
defaultProviderId: z10.string().optional(),
|
|
9687
|
-
notifications: z10.object({
|
|
9688
|
-
enabled: z10.boolean().optional(),
|
|
9689
|
-
soundEnabled: z10.boolean().optional(),
|
|
10162
|
+
SettingsSchema = z11.object({
|
|
10163
|
+
defaultProviderId: z11.string().optional(),
|
|
10164
|
+
notifications: z11.object({
|
|
10165
|
+
enabled: z11.boolean().optional(),
|
|
10166
|
+
soundEnabled: z11.boolean().optional(),
|
|
9690
10167
|
// Legacy field — accepted for backward compat with older clients but
|
|
9691
10168
|
// no longer surfaced in the UI. The web client now picks the channel
|
|
9692
10169
|
// automatically based on workspace focus + page visibility.
|
|
9693
|
-
onlyWhenBackgrounded:
|
|
10170
|
+
onlyWhenBackgrounded: z11.boolean().optional()
|
|
9694
10171
|
}).optional(),
|
|
9695
|
-
supervisor:
|
|
9696
|
-
evaluationTimeoutSec:
|
|
10172
|
+
supervisor: z11.object({
|
|
10173
|
+
evaluationTimeoutSec: z11.number().int().min(1).max(MAX_SUPERVISOR_EVALUATION_TIMEOUT_SEC).default(DEFAULT_SUPERVISOR_EVALUATION_TIMEOUT_SEC).optional()
|
|
9697
10174
|
}).optional(),
|
|
9698
|
-
appearance:
|
|
9699
|
-
theme:
|
|
9700
|
-
terminalRenderer:
|
|
9701
|
-
locale:
|
|
10175
|
+
appearance: z11.object({
|
|
10176
|
+
theme: z11.enum(["dark"]).optional(),
|
|
10177
|
+
terminalRenderer: z11.enum(["standard", "compatibility"]).optional(),
|
|
10178
|
+
locale: z11.enum(["zh", "en"]).optional()
|
|
9702
10179
|
}).optional(),
|
|
9703
10180
|
providers: ProviderSettingsSchema.optional()
|
|
9704
10181
|
});
|
|
9705
|
-
registerCommand("settings.get",
|
|
10182
|
+
registerCommand("settings.get", z11.object({}), async (_args, ctx) => {
|
|
9706
10183
|
const row = ctx.db.prepare("SELECT key, value FROM user_settings").all();
|
|
9707
10184
|
const settings = {};
|
|
9708
10185
|
for (const { key, value } of row) {
|
|
@@ -9726,11 +10203,6 @@ var init_settings2 = __esm({
|
|
|
9726
10203
|
flattenSettings(sanitizeProviderLaunchConfig(config), `providers.${providerId}`)
|
|
9727
10204
|
);
|
|
9728
10205
|
}
|
|
9729
|
-
try {
|
|
9730
|
-
settings.externalConfigAudit = ctx.codexConfigAudit?.audit() ?? EMPTY_CODEX_AUDIT;
|
|
9731
|
-
} catch {
|
|
9732
|
-
settings.externalConfigAudit = null;
|
|
9733
|
-
}
|
|
9734
10206
|
if (Object.prototype.hasOwnProperty.call(settings, SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY)) {
|
|
9735
10207
|
settings[SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY] = resolveSupervisorEvaluationTimeoutSec(
|
|
9736
10208
|
settings[SUPERVISOR_EVALUATION_TIMEOUT_SETTING_KEY]
|
|
@@ -9740,7 +10212,7 @@ var init_settings2 = __esm({
|
|
|
9740
10212
|
});
|
|
9741
10213
|
registerCommand(
|
|
9742
10214
|
"settings.update",
|
|
9743
|
-
|
|
10215
|
+
z11.object({
|
|
9744
10216
|
settings: SettingsSchema
|
|
9745
10217
|
}),
|
|
9746
10218
|
async (args, ctx) => {
|
|
@@ -9770,31 +10242,12 @@ var init_settings2 = __esm({
|
|
|
9770
10242
|
};
|
|
9771
10243
|
}
|
|
9772
10244
|
);
|
|
9773
|
-
registerCommand(
|
|
9774
|
-
"settings.cleanupCodexConfig",
|
|
9775
|
-
z10.object({
|
|
9776
|
-
removeIds: z10.array(z10.enum(["toml_notify", "toml_codex_hooks"])).min(1)
|
|
9777
|
-
}),
|
|
9778
|
-
async (args, ctx) => {
|
|
9779
|
-
const result = ctx.codexConfigAudit?.cleanup(args.removeIds) ?? {
|
|
9780
|
-
removed: [],
|
|
9781
|
-
backupPath: null,
|
|
9782
|
-
noop: true
|
|
9783
|
-
};
|
|
9784
|
-
return {
|
|
9785
|
-
removed: result.removed,
|
|
9786
|
-
backupPath: result.backupPath,
|
|
9787
|
-
noop: result.noop,
|
|
9788
|
-
audit: ctx.codexConfigAudit?.audit() ?? EMPTY_CODEX_AUDIT
|
|
9789
|
-
};
|
|
9790
|
-
}
|
|
9791
|
-
);
|
|
9792
10245
|
registerCommand(
|
|
9793
10246
|
"settings.previewCommand",
|
|
9794
|
-
|
|
9795
|
-
providerId:
|
|
10247
|
+
z11.object({
|
|
10248
|
+
providerId: z11.string(),
|
|
9796
10249
|
config: ProviderLaunchConfigInputSchema,
|
|
9797
|
-
workspacePath:
|
|
10250
|
+
workspacePath: z11.string().optional()
|
|
9798
10251
|
}),
|
|
9799
10252
|
async (args, ctx) => {
|
|
9800
10253
|
const provider = ctx.providerRegistry.find((item) => item.id === args.providerId);
|
|
@@ -9815,8 +10268,8 @@ var init_settings2 = __esm({
|
|
|
9815
10268
|
);
|
|
9816
10269
|
registerCommand(
|
|
9817
10270
|
"settings.readConfigFile",
|
|
9818
|
-
|
|
9819
|
-
configType:
|
|
10271
|
+
z11.object({
|
|
10272
|
+
configType: z11.enum(["codex", "claude"])
|
|
9820
10273
|
}),
|
|
9821
10274
|
async (args) => {
|
|
9822
10275
|
const result = readConfigFile(args.configType);
|
|
@@ -9825,9 +10278,9 @@ var init_settings2 = __esm({
|
|
|
9825
10278
|
);
|
|
9826
10279
|
registerCommand(
|
|
9827
10280
|
"settings.writeConfigFile",
|
|
9828
|
-
|
|
9829
|
-
configType:
|
|
9830
|
-
content:
|
|
10281
|
+
z11.object({
|
|
10282
|
+
configType: z11.enum(["codex", "claude"]),
|
|
10283
|
+
content: z11.string()
|
|
9831
10284
|
}),
|
|
9832
10285
|
async (args) => {
|
|
9833
10286
|
const result = writeConfigFile(args.configType, args.content);
|
|
@@ -9838,19 +10291,19 @@ var init_settings2 = __esm({
|
|
|
9838
10291
|
});
|
|
9839
10292
|
|
|
9840
10293
|
// packages/server/src/commands/provider.ts
|
|
9841
|
-
import { z as
|
|
10294
|
+
import { z as z12 } from "zod";
|
|
9842
10295
|
var init_provider = __esm({
|
|
9843
10296
|
"packages/server/src/commands/provider.ts"() {
|
|
9844
10297
|
"use strict";
|
|
9845
10298
|
init_runtime_status();
|
|
9846
10299
|
init_dispatch();
|
|
9847
|
-
registerCommand("provider.runtimeStatus",
|
|
10300
|
+
registerCommand("provider.runtimeStatus", z12.object({}), async (_args, ctx) => {
|
|
9848
10301
|
return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
|
|
9849
10302
|
});
|
|
9850
10303
|
registerCommand(
|
|
9851
10304
|
"provider.install.start",
|
|
9852
|
-
|
|
9853
|
-
providerId:
|
|
10305
|
+
z12.object({
|
|
10306
|
+
providerId: z12.string()
|
|
9854
10307
|
}),
|
|
9855
10308
|
async (args, ctx) => {
|
|
9856
10309
|
if (!ctx.providerInstallMgr) {
|
|
@@ -9864,8 +10317,8 @@ var init_provider = __esm({
|
|
|
9864
10317
|
);
|
|
9865
10318
|
registerCommand(
|
|
9866
10319
|
"provider.install.get",
|
|
9867
|
-
|
|
9868
|
-
jobId:
|
|
10320
|
+
z12.object({
|
|
10321
|
+
jobId: z12.string()
|
|
9869
10322
|
}),
|
|
9870
10323
|
async (args, ctx) => {
|
|
9871
10324
|
if (!ctx.providerInstallMgr) {
|
|
@@ -9888,29 +10341,29 @@ var init_provider = __esm({
|
|
|
9888
10341
|
});
|
|
9889
10342
|
|
|
9890
10343
|
// packages/server/src/commands/supervisor.ts
|
|
9891
|
-
import { z as
|
|
10344
|
+
import { z as z13 } from "zod";
|
|
9892
10345
|
var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, supervisorIdSchema;
|
|
9893
10346
|
var init_supervisor2 = __esm({
|
|
9894
10347
|
"packages/server/src/commands/supervisor.ts"() {
|
|
9895
10348
|
"use strict";
|
|
9896
10349
|
init_dispatch();
|
|
9897
|
-
supervisorObjectiveSchema =
|
|
9898
|
-
createSupervisorSchema =
|
|
9899
|
-
sessionId:
|
|
9900
|
-
workspaceId:
|
|
10350
|
+
supervisorObjectiveSchema = z13.string().trim().min(1).max(4e3);
|
|
10351
|
+
createSupervisorSchema = z13.object({
|
|
10352
|
+
sessionId: z13.string(),
|
|
10353
|
+
workspaceId: z13.string(),
|
|
9901
10354
|
objective: supervisorObjectiveSchema,
|
|
9902
|
-
evaluatorProviderId:
|
|
10355
|
+
evaluatorProviderId: z13.string()
|
|
9903
10356
|
}).strict();
|
|
9904
|
-
updateSupervisorSchema =
|
|
9905
|
-
id:
|
|
10357
|
+
updateSupervisorSchema = z13.object({
|
|
10358
|
+
id: z13.string(),
|
|
9906
10359
|
objective: supervisorObjectiveSchema.optional(),
|
|
9907
|
-
evaluatorProviderId:
|
|
10360
|
+
evaluatorProviderId: z13.string().optional()
|
|
9908
10361
|
}).strict().refine(
|
|
9909
10362
|
(input) => input.objective !== void 0 || input.evaluatorProviderId !== void 0,
|
|
9910
10363
|
"objective or evaluatorProviderId is required"
|
|
9911
10364
|
);
|
|
9912
|
-
sessionIdSchema =
|
|
9913
|
-
supervisorIdSchema =
|
|
10365
|
+
sessionIdSchema = z13.object({ sessionId: z13.string() });
|
|
10366
|
+
supervisorIdSchema = z13.object({ id: z13.string() });
|
|
9914
10367
|
registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
|
|
9915
10368
|
return {
|
|
9916
10369
|
supervisor: await ctx.supervisorMgr.create({
|
|
@@ -9953,6 +10406,10 @@ import path8 from "node:path";
|
|
|
9953
10406
|
function normalizeWorktreePath(worktreePath) {
|
|
9954
10407
|
return path8.resolve(worktreePath);
|
|
9955
10408
|
}
|
|
10409
|
+
async function getGitCommonDirPath(repoPath) {
|
|
10410
|
+
const { stdout } = await runGit(repoPath, ["rev-parse", "--git-common-dir"]);
|
|
10411
|
+
return normalizeWorktreePath(path8.resolve(repoPath, stdout.trim()));
|
|
10412
|
+
}
|
|
9956
10413
|
async function resolveWorktreePath(repoPath, worktreePath) {
|
|
9957
10414
|
const normalizedRequested = normalizeWorktreePath(worktreePath);
|
|
9958
10415
|
const worktrees = await listWorktrees(repoPath);
|
|
@@ -10038,19 +10495,30 @@ async function getWorktreeTree(worktreePath) {
|
|
|
10038
10495
|
for (const line of lines) {
|
|
10039
10496
|
const isDir = line.endsWith("/");
|
|
10040
10497
|
const name = isDir ? line.slice(0, -1) : line;
|
|
10041
|
-
const
|
|
10498
|
+
const path10 = `${worktreePath}/${name}`;
|
|
10042
10499
|
nodes.push({
|
|
10043
10500
|
name,
|
|
10044
|
-
path:
|
|
10501
|
+
path: path10,
|
|
10045
10502
|
kind: isDir ? "dir" : "file"
|
|
10046
10503
|
});
|
|
10047
10504
|
}
|
|
10048
10505
|
return nodes;
|
|
10049
10506
|
}
|
|
10050
|
-
async function createWorktree(repoPath, branch,
|
|
10051
|
-
|
|
10507
|
+
async function createWorktree(repoPath, branch, worktreePath) {
|
|
10508
|
+
let createArgs = ["worktree", "add", worktreePath, branch];
|
|
10509
|
+
try {
|
|
10510
|
+
await runGit(repoPath, ["rev-parse", "--verify", "--quiet", `${branch}^{commit}`]);
|
|
10511
|
+
} catch (error) {
|
|
10512
|
+
if (error instanceof GitError) {
|
|
10513
|
+
createArgs = ["worktree", "add", "-b", branch, worktreePath];
|
|
10514
|
+
} else {
|
|
10515
|
+
throw error;
|
|
10516
|
+
}
|
|
10517
|
+
}
|
|
10518
|
+
await runGit(repoPath, createArgs);
|
|
10052
10519
|
const worktrees = await listWorktrees(repoPath);
|
|
10053
|
-
const
|
|
10520
|
+
const normalizedRequested = normalizeWorktreePath(worktreePath);
|
|
10521
|
+
const created = worktrees.find((wt) => normalizeWorktreePath(wt.path) === normalizedRequested);
|
|
10054
10522
|
if (!created) {
|
|
10055
10523
|
throw new Error("Failed to find created worktree");
|
|
10056
10524
|
}
|
|
@@ -10072,13 +10540,41 @@ var init_worktree = __esm({
|
|
|
10072
10540
|
});
|
|
10073
10541
|
|
|
10074
10542
|
// packages/server/src/commands/worktree.ts
|
|
10075
|
-
import
|
|
10543
|
+
import path9 from "node:path";
|
|
10544
|
+
import { z as z14 } from "zod";
|
|
10545
|
+
async function findRelatedWorkspaceIds(ctx, workspacePath) {
|
|
10546
|
+
const targetCommonDir = await getGitCommonDirPath(workspacePath);
|
|
10547
|
+
const relatedWorkspaceIds = await Promise.all(
|
|
10548
|
+
ctx.workspaceMgr.list().map(async (workspace) => {
|
|
10549
|
+
try {
|
|
10550
|
+
const commonDir = await getGitCommonDirPath(workspace.path);
|
|
10551
|
+
return commonDir === targetCommonDir ? workspace.id : null;
|
|
10552
|
+
} catch {
|
|
10553
|
+
return null;
|
|
10554
|
+
}
|
|
10555
|
+
})
|
|
10556
|
+
);
|
|
10557
|
+
return relatedWorkspaceIds.filter((workspaceId) => Boolean(workspaceId));
|
|
10558
|
+
}
|
|
10559
|
+
function emitWorktreeChangedForWorkspaceIds(ctx, workspaceIds) {
|
|
10560
|
+
for (const workspaceId of workspaceIds) {
|
|
10561
|
+
if (!ctx.workspaceMgr.get(workspaceId)) {
|
|
10562
|
+
continue;
|
|
10563
|
+
}
|
|
10564
|
+
emitGitStateChanged(ctx, workspaceId, { worktreeChanged: true });
|
|
10565
|
+
}
|
|
10566
|
+
}
|
|
10567
|
+
function isWorkspaceOpenForPath(ctx, workspacePath) {
|
|
10568
|
+
const targetPath = path9.resolve(workspacePath);
|
|
10569
|
+
return ctx.workspaceMgr.list().some((openWorkspace) => path9.resolve(openWorkspace.path) === targetPath);
|
|
10570
|
+
}
|
|
10076
10571
|
var init_worktree2 = __esm({
|
|
10077
10572
|
"packages/server/src/commands/worktree.ts"() {
|
|
10078
10573
|
"use strict";
|
|
10079
10574
|
init_worktree();
|
|
10080
10575
|
init_dispatch();
|
|
10081
|
-
|
|
10576
|
+
init_git_events();
|
|
10577
|
+
registerCommand("worktree.list", z14.object({ workspaceId: z14.string() }), async (args, ctx) => {
|
|
10082
10578
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10083
10579
|
if (!workspace) {
|
|
10084
10580
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
@@ -10087,7 +10583,7 @@ var init_worktree2 = __esm({
|
|
|
10087
10583
|
});
|
|
10088
10584
|
registerCommand(
|
|
10089
10585
|
"worktree.status",
|
|
10090
|
-
|
|
10586
|
+
z14.object({ workspaceId: z14.string(), worktreePath: z14.string() }),
|
|
10091
10587
|
async (args, ctx) => {
|
|
10092
10588
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10093
10589
|
if (!workspace) {
|
|
@@ -10099,10 +10595,10 @@ var init_worktree2 = __esm({
|
|
|
10099
10595
|
);
|
|
10100
10596
|
registerCommand(
|
|
10101
10597
|
"worktree.diff",
|
|
10102
|
-
|
|
10103
|
-
workspaceId:
|
|
10104
|
-
worktreePath:
|
|
10105
|
-
staged:
|
|
10598
|
+
z14.object({
|
|
10599
|
+
workspaceId: z14.string(),
|
|
10600
|
+
worktreePath: z14.string(),
|
|
10601
|
+
staged: z14.boolean().optional().default(false)
|
|
10106
10602
|
}),
|
|
10107
10603
|
async (args, ctx) => {
|
|
10108
10604
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -10115,7 +10611,7 @@ var init_worktree2 = __esm({
|
|
|
10115
10611
|
);
|
|
10116
10612
|
registerCommand(
|
|
10117
10613
|
"worktree.tree",
|
|
10118
|
-
|
|
10614
|
+
z14.object({ workspaceId: z14.string(), worktreePath: z14.string() }),
|
|
10119
10615
|
async (args, ctx) => {
|
|
10120
10616
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10121
10617
|
if (!workspace) {
|
|
@@ -10127,33 +10623,44 @@ var init_worktree2 = __esm({
|
|
|
10127
10623
|
);
|
|
10128
10624
|
registerCommand(
|
|
10129
10625
|
"worktree.create",
|
|
10130
|
-
|
|
10131
|
-
workspaceId:
|
|
10132
|
-
branch:
|
|
10133
|
-
path:
|
|
10626
|
+
z14.object({
|
|
10627
|
+
workspaceId: z14.string(),
|
|
10628
|
+
branch: z14.string(),
|
|
10629
|
+
path: z14.string()
|
|
10134
10630
|
}),
|
|
10135
10631
|
async (args, ctx) => {
|
|
10136
10632
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10137
10633
|
if (!workspace) {
|
|
10138
10634
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
10139
10635
|
}
|
|
10140
|
-
|
|
10636
|
+
const relatedWorkspaceIds = await findRelatedWorkspaceIds(ctx, workspace.path);
|
|
10637
|
+
const worktree = await createWorktree(workspace.path, args.branch, args.path);
|
|
10638
|
+
emitWorktreeChangedForWorkspaceIds(ctx, relatedWorkspaceIds);
|
|
10639
|
+
return { worktree };
|
|
10141
10640
|
}
|
|
10142
10641
|
);
|
|
10143
10642
|
registerCommand(
|
|
10144
10643
|
"worktree.remove",
|
|
10145
|
-
|
|
10146
|
-
workspaceId:
|
|
10147
|
-
worktreePath:
|
|
10148
|
-
force:
|
|
10644
|
+
z14.object({
|
|
10645
|
+
workspaceId: z14.string(),
|
|
10646
|
+
worktreePath: z14.string(),
|
|
10647
|
+
force: z14.boolean().optional().default(false)
|
|
10149
10648
|
}),
|
|
10150
10649
|
async (args, ctx) => {
|
|
10151
10650
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
10152
10651
|
if (!workspace) {
|
|
10153
10652
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
10154
10653
|
}
|
|
10654
|
+
const relatedWorkspaceIds = await findRelatedWorkspaceIds(ctx, workspace.path);
|
|
10155
10655
|
const worktreePath = await resolveWorktreePath(workspace.path, args.worktreePath);
|
|
10656
|
+
if (isWorkspaceOpenForPath(ctx, worktreePath)) {
|
|
10657
|
+
throw {
|
|
10658
|
+
code: "worktree_in_use",
|
|
10659
|
+
message: `Cannot remove an open worktree workspace: ${worktreePath}`
|
|
10660
|
+
};
|
|
10661
|
+
}
|
|
10156
10662
|
await removeWorktree(workspace.path, worktreePath, args.force);
|
|
10663
|
+
emitWorktreeChangedForWorkspaceIds(ctx, relatedWorkspaceIds);
|
|
10157
10664
|
return {};
|
|
10158
10665
|
}
|
|
10159
10666
|
);
|
|
@@ -10161,7 +10668,7 @@ var init_worktree2 = __esm({
|
|
|
10161
10668
|
});
|
|
10162
10669
|
|
|
10163
10670
|
// packages/server/src/commands/fencing.ts
|
|
10164
|
-
import { z as
|
|
10671
|
+
import { z as z15 } from "zod";
|
|
10165
10672
|
function createMockFencingRequest() {
|
|
10166
10673
|
return {
|
|
10167
10674
|
ip: "127.0.0.1",
|
|
@@ -10174,9 +10681,9 @@ var init_fencing2 = __esm({
|
|
|
10174
10681
|
init_dispatch();
|
|
10175
10682
|
registerCommand(
|
|
10176
10683
|
"fencing.request",
|
|
10177
|
-
|
|
10178
|
-
workspaceId:
|
|
10179
|
-
tabId:
|
|
10684
|
+
z15.object({
|
|
10685
|
+
workspaceId: z15.string(),
|
|
10686
|
+
tabId: z15.string()
|
|
10180
10687
|
}),
|
|
10181
10688
|
async (args, ctx, clientId) => {
|
|
10182
10689
|
return ctx.fencingMgr.requestControl(
|
|
@@ -10189,7 +10696,7 @@ var init_fencing2 = __esm({
|
|
|
10189
10696
|
);
|
|
10190
10697
|
registerCommand(
|
|
10191
10698
|
"fencing.heartbeat",
|
|
10192
|
-
|
|
10699
|
+
z15.object({ workspaceId: z15.string() }),
|
|
10193
10700
|
async (args, ctx, clientId) => {
|
|
10194
10701
|
const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
|
|
10195
10702
|
return { success };
|
|
@@ -10197,13 +10704,13 @@ var init_fencing2 = __esm({
|
|
|
10197
10704
|
);
|
|
10198
10705
|
registerCommand(
|
|
10199
10706
|
"fencing.release",
|
|
10200
|
-
|
|
10707
|
+
z15.object({ workspaceId: z15.string() }),
|
|
10201
10708
|
async (args, ctx, clientId) => {
|
|
10202
10709
|
ctx.fencingMgr.release(args.workspaceId, clientId);
|
|
10203
10710
|
return {};
|
|
10204
10711
|
}
|
|
10205
10712
|
);
|
|
10206
|
-
registerCommand("fencing.status",
|
|
10713
|
+
registerCommand("fencing.status", z15.object({ workspaceId: z15.string() }), async (args, ctx) => {
|
|
10207
10714
|
const controller = ctx.fencingMgr.getController(args.workspaceId);
|
|
10208
10715
|
const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
|
|
10209
10716
|
return {
|
|
@@ -10214,9 +10721,9 @@ var init_fencing2 = __esm({
|
|
|
10214
10721
|
});
|
|
10215
10722
|
registerCommand(
|
|
10216
10723
|
"fencing.takeover",
|
|
10217
|
-
|
|
10218
|
-
workspaceId:
|
|
10219
|
-
tabId:
|
|
10724
|
+
z15.object({
|
|
10725
|
+
workspaceId: z15.string(),
|
|
10726
|
+
tabId: z15.string()
|
|
10220
10727
|
}),
|
|
10221
10728
|
async (args, ctx, clientId) => {
|
|
10222
10729
|
return ctx.fencingMgr.forceTakeover(
|
|
@@ -10235,6 +10742,7 @@ var init_commands = __esm({
|
|
|
10235
10742
|
"packages/server/src/commands/index.ts"() {
|
|
10236
10743
|
"use strict";
|
|
10237
10744
|
init_workspace();
|
|
10745
|
+
init_workspace_activity();
|
|
10238
10746
|
init_session();
|
|
10239
10747
|
init_terminal();
|
|
10240
10748
|
init_file();
|
|
@@ -10248,32 +10756,6 @@ var init_commands = __esm({
|
|
|
10248
10756
|
});
|
|
10249
10757
|
|
|
10250
10758
|
// packages/server/src/server.ts
|
|
10251
|
-
function createCodexConfigAuditApi() {
|
|
10252
|
-
return {
|
|
10253
|
-
audit: () => ({ codex: auditCodexConfigToml() }),
|
|
10254
|
-
cleanup: (removeIds) => {
|
|
10255
|
-
const audit = auditCodexConfigToml();
|
|
10256
|
-
return cleanupCodexConfigToml(audit.configPath, { removeIds });
|
|
10257
|
-
}
|
|
10258
|
-
};
|
|
10259
|
-
}
|
|
10260
|
-
async function logCodexConfigFindings(auditApi, logger) {
|
|
10261
|
-
try {
|
|
10262
|
-
const audit = auditApi.audit();
|
|
10263
|
-
for (const finding of audit.codex.findings) {
|
|
10264
|
-
logger.warn(
|
|
10265
|
-
{
|
|
10266
|
-
configPath: audit.codex.configPath,
|
|
10267
|
-
startLine: finding.startLine,
|
|
10268
|
-
findingMessage: finding.message
|
|
10269
|
-
},
|
|
10270
|
-
"Codex config finding"
|
|
10271
|
-
);
|
|
10272
|
-
}
|
|
10273
|
-
} catch (err) {
|
|
10274
|
-
logger.warn({ err }, "Codex config audit failed (non-fatal)");
|
|
10275
|
-
}
|
|
10276
|
-
}
|
|
10277
10759
|
async function createServer(configOverrides) {
|
|
10278
10760
|
const config = parseServerConfig(configOverrides);
|
|
10279
10761
|
ensureDataDir(config);
|
|
@@ -10281,14 +10763,45 @@ async function createServer(configOverrides) {
|
|
|
10281
10763
|
const eventBus = new EventBus();
|
|
10282
10764
|
const fencingMgr = new FencingManager();
|
|
10283
10765
|
const wsHub = new WsHub({ eventBus, commandContext: null, config, fencingMgr });
|
|
10766
|
+
let workspaceMgr;
|
|
10767
|
+
let commandContext;
|
|
10284
10768
|
const terminalMgr = new TerminalManager({
|
|
10285
10769
|
ptyHost: createPtyHost(),
|
|
10286
10770
|
eventBus,
|
|
10287
10771
|
db: createTerminalDatabase(db)
|
|
10288
10772
|
});
|
|
10773
|
+
const settingsRepo = new SettingsRepo(db);
|
|
10774
|
+
const autoFetch = new AutoFetchScheduler({
|
|
10775
|
+
workspaceMgr: { get: (workspaceId) => workspaceMgr.get(workspaceId) },
|
|
10776
|
+
eventBus,
|
|
10777
|
+
settingsRepo,
|
|
10778
|
+
runFetch: async (workspaceId) => {
|
|
10779
|
+
if (!workspaceMgr.get(workspaceId)) {
|
|
10780
|
+
return;
|
|
10781
|
+
}
|
|
10782
|
+
const result = await dispatch(
|
|
10783
|
+
{
|
|
10784
|
+
kind: "command",
|
|
10785
|
+
id: `auto-fetch:${workspaceId}:${Date.now()}`,
|
|
10786
|
+
op: "git.fetch",
|
|
10787
|
+
args: {
|
|
10788
|
+
workspaceId,
|
|
10789
|
+
background: true
|
|
10790
|
+
}
|
|
10791
|
+
},
|
|
10792
|
+
commandContext
|
|
10793
|
+
);
|
|
10794
|
+
if (!result.ok) {
|
|
10795
|
+
throw new Error(result.error?.message ?? "Background fetch failed");
|
|
10796
|
+
}
|
|
10797
|
+
const data = result.data;
|
|
10798
|
+
if (data.success === false) {
|
|
10799
|
+
throw new Error(data.message ?? "Background fetch failed");
|
|
10800
|
+
}
|
|
10801
|
+
}
|
|
10802
|
+
});
|
|
10289
10803
|
const sessionDb = createSessionDatabase(db);
|
|
10290
10804
|
const providerConfigRepo = new ProviderConfigRepo(db);
|
|
10291
|
-
const settingsRepo = new SettingsRepo(db);
|
|
10292
10805
|
const sessionMgr = new SessionManager({
|
|
10293
10806
|
terminalMgr,
|
|
10294
10807
|
eventBus,
|
|
@@ -10298,10 +10811,11 @@ async function createServer(configOverrides) {
|
|
|
10298
10811
|
providerConfigRepo
|
|
10299
10812
|
});
|
|
10300
10813
|
let supervisorMgr;
|
|
10301
|
-
|
|
10814
|
+
workspaceMgr = new WorkspaceManager({
|
|
10302
10815
|
db,
|
|
10303
10816
|
eventBus,
|
|
10304
10817
|
broadcaster: wsHub,
|
|
10818
|
+
autoFetch,
|
|
10305
10819
|
teardown: async (workspaceId) => {
|
|
10306
10820
|
await supervisorMgr?.deleteForWorkspace(workspaceId);
|
|
10307
10821
|
await sessionMgr.stopForWorkspace(workspaceId);
|
|
@@ -10312,9 +10826,9 @@ async function createServer(configOverrides) {
|
|
|
10312
10826
|
(err) => console.warn("[uploads] cascade cleanup failed", { wsId: workspaceId, err })
|
|
10313
10827
|
)
|
|
10314
10828
|
});
|
|
10829
|
+
workspaceMgr.hydrateWatchers();
|
|
10315
10830
|
const authSessionRepo = new AuthSessionRepo(db);
|
|
10316
10831
|
const authLoginBlockRepo = new AuthLoginBlockRepo(db);
|
|
10317
|
-
const codexConfigAudit = createCodexConfigAuditApi();
|
|
10318
10832
|
const app = await buildFastifyApp({
|
|
10319
10833
|
wsHub,
|
|
10320
10834
|
db,
|
|
@@ -10335,7 +10849,6 @@ async function createServer(configOverrides) {
|
|
|
10335
10849
|
}
|
|
10336
10850
|
});
|
|
10337
10851
|
wsHub.setLogger(app.log);
|
|
10338
|
-
await logCodexConfigFindings(codexConfigAudit, app.log);
|
|
10339
10852
|
const supervisorRepo = new SupervisorRepo(db);
|
|
10340
10853
|
const cycleRepo = new SupervisorCycleRepo(db);
|
|
10341
10854
|
supervisorMgr = new SupervisorManager({
|
|
@@ -10353,12 +10866,15 @@ async function createServer(configOverrides) {
|
|
|
10353
10866
|
});
|
|
10354
10867
|
await sessionMgr.hydrate();
|
|
10355
10868
|
await supervisorMgr.hydrate();
|
|
10356
|
-
const
|
|
10869
|
+
const providerMockOverrides = createE2EProviderMockOverrides();
|
|
10870
|
+
const providerRuntimeDeps = providerMockOverrides ? {
|
|
10871
|
+
commandExists: providerMockOverrides.commandExists
|
|
10872
|
+
} : {};
|
|
10357
10873
|
const providerInstallMgr = new ProviderInstallManager(providerRegistry, {
|
|
10358
10874
|
...providerRuntimeDeps,
|
|
10359
|
-
runCommand: runCommandAsString
|
|
10875
|
+
runCommand: providerMockOverrides?.runCommand ?? runCommandAsString
|
|
10360
10876
|
});
|
|
10361
|
-
|
|
10877
|
+
commandContext = {
|
|
10362
10878
|
workspaceMgr,
|
|
10363
10879
|
sessionMgr,
|
|
10364
10880
|
terminalMgr,
|
|
@@ -10368,9 +10884,9 @@ async function createServer(configOverrides) {
|
|
|
10368
10884
|
providerRegistry,
|
|
10369
10885
|
fencingMgr,
|
|
10370
10886
|
supervisorMgr,
|
|
10887
|
+
autoFetch,
|
|
10371
10888
|
providerRuntimeDeps,
|
|
10372
|
-
providerInstallMgr
|
|
10373
|
-
codexConfigAudit
|
|
10889
|
+
providerInstallMgr
|
|
10374
10890
|
};
|
|
10375
10891
|
wsHub.setCommandContext(commandContext);
|
|
10376
10892
|
await app.listen({
|
|
@@ -10401,6 +10917,7 @@ async function createServer(configOverrides) {
|
|
|
10401
10917
|
stopped = true;
|
|
10402
10918
|
clearTimeout(gcTimer);
|
|
10403
10919
|
await app.close();
|
|
10920
|
+
autoFetch.stop();
|
|
10404
10921
|
supervisorMgr.stop();
|
|
10405
10922
|
terminalMgr.shutdown();
|
|
10406
10923
|
wsHub.destroy();
|
|
@@ -10522,9 +11039,10 @@ var init_server = __esm({
|
|
|
10522
11039
|
init_src2();
|
|
10523
11040
|
init_app();
|
|
10524
11041
|
init_event_bus();
|
|
10525
|
-
init_codex_config_audit();
|
|
10526
11042
|
init_config();
|
|
11043
|
+
init_auto_fetch();
|
|
10527
11044
|
init_command_runner();
|
|
11045
|
+
init_e2e_provider_mock();
|
|
10528
11046
|
init_install_manager();
|
|
10529
11047
|
init_manager();
|
|
10530
11048
|
init_db();
|
|
@@ -10541,6 +11059,7 @@ var init_server = __esm({
|
|
|
10541
11059
|
init_cleanup();
|
|
10542
11060
|
init_constants();
|
|
10543
11061
|
init_manager4();
|
|
11062
|
+
init_dispatch();
|
|
10544
11063
|
init_fencing();
|
|
10545
11064
|
init_hub();
|
|
10546
11065
|
init_commands();
|
|
@@ -10694,8 +11213,8 @@ var init_workspace_repo = __esm({
|
|
|
10694
11213
|
/**
|
|
10695
11214
|
* Finds a workspace by path
|
|
10696
11215
|
*/
|
|
10697
|
-
findByPath(
|
|
10698
|
-
const row = this.db.prepare("SELECT * FROM workspaces WHERE path = ?").get(
|
|
11216
|
+
findByPath(path10) {
|
|
11217
|
+
const row = this.db.prepare("SELECT * FROM workspaces WHERE path = ?").get(path10);
|
|
10699
11218
|
return row ? this.rowToWorkspace(row) : void 0;
|
|
10700
11219
|
}
|
|
10701
11220
|
/**
|
|
@@ -10840,12 +11359,12 @@ function getCliConfigPath() {
|
|
|
10840
11359
|
return join(homedir(), ".coder-studio", "config.json");
|
|
10841
11360
|
}
|
|
10842
11361
|
function readCliConfig() {
|
|
10843
|
-
const
|
|
10844
|
-
if (!existsSync(
|
|
11362
|
+
const path10 = getCliConfigPath();
|
|
11363
|
+
if (!existsSync(path10)) {
|
|
10845
11364
|
return null;
|
|
10846
11365
|
}
|
|
10847
11366
|
try {
|
|
10848
|
-
const parsed = JSON.parse(readFileSync(
|
|
11367
|
+
const parsed = JSON.parse(readFileSync(path10, "utf-8"));
|
|
10849
11368
|
if (parsed.host !== void 0 && typeof parsed.host !== "string" || parsed.port !== void 0 && typeof parsed.port !== "number" || parsed.dataDir !== void 0 && typeof parsed.dataDir !== "string" || parsed.password !== void 0 && typeof parsed.password !== "string") {
|
|
10850
11369
|
return null;
|
|
10851
11370
|
}
|