@spencer-kit/coder-studio 0.3.3 → 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 +6 -0
- package/dist/esm/bin.mjs +279 -91
- package/dist/esm/bin.mjs.map +4 -4
- package/dist/esm/server-runner.mjs +247 -59
- 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-tpaaY-08.js +0 -111
- package/dist/web/assets/index-tpaaY-08.js.map +0 -1
- package/dist/web/assets/index-yz1r6Fe0.css +0 -1
|
@@ -863,11 +863,11 @@ function resolveSpawnArgv(argv, deps = {}) {
|
|
|
863
863
|
return [];
|
|
864
864
|
}
|
|
865
865
|
const restArgs = argv.slice(1);
|
|
866
|
-
const
|
|
867
|
-
const
|
|
866
|
+
const readFileSync9 = deps.readFileSync ?? ((file) => fs2.readFileSync(file, "utf8"));
|
|
867
|
+
const existsSync10 = deps.existsSync ?? fs2.existsSync;
|
|
868
868
|
const pathEnv = deps.pathEnv ?? process.env.Path ?? process.env.PATH ?? "";
|
|
869
869
|
const pathExt = deps.pathExt ?? process.env.PATHEXT ?? DEFAULT_PATHEXT;
|
|
870
|
-
const resolved = resolveExecutablePath(command, pathEnv, pathExt,
|
|
870
|
+
const resolved = resolveExecutablePath(command, pathEnv, pathExt, existsSync10);
|
|
871
871
|
if (!resolved) {
|
|
872
872
|
return [...argv];
|
|
873
873
|
}
|
|
@@ -878,7 +878,7 @@ function resolveSpawnArgv(argv, deps = {}) {
|
|
|
878
878
|
if (ext === ".cmd" || ext === ".bat") {
|
|
879
879
|
let content;
|
|
880
880
|
try {
|
|
881
|
-
content =
|
|
881
|
+
content = readFileSync9(resolved);
|
|
882
882
|
} catch {
|
|
883
883
|
return ["cmd.exe", "/d", "/s", "/c", resolved, ...restArgs];
|
|
884
884
|
}
|
|
@@ -916,17 +916,17 @@ function expandShimVars(value, dp0Dir) {
|
|
|
916
916
|
function parsePathExt(pathExt) {
|
|
917
917
|
return pathExt.split(";").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
|
|
918
918
|
}
|
|
919
|
-
function resolveExecutablePath(command, pathEnv, pathExt,
|
|
919
|
+
function resolveExecutablePath(command, pathEnv, pathExt, existsSync10) {
|
|
920
920
|
const hasExt = path2.win32.extname(command).length > 0;
|
|
921
921
|
const extensions = parsePathExt(pathExt);
|
|
922
922
|
if (path2.win32.isAbsolute(command)) {
|
|
923
|
-
if (
|
|
923
|
+
if (existsSync10(command)) {
|
|
924
924
|
return command;
|
|
925
925
|
}
|
|
926
926
|
if (!hasExt) {
|
|
927
927
|
for (const ext of extensions) {
|
|
928
928
|
const candidate = command + ext;
|
|
929
|
-
if (
|
|
929
|
+
if (existsSync10(candidate)) {
|
|
930
930
|
return candidate;
|
|
931
931
|
}
|
|
932
932
|
}
|
|
@@ -937,14 +937,14 @@ function resolveExecutablePath(command, pathEnv, pathExt, existsSync9) {
|
|
|
937
937
|
for (const dir of dirs) {
|
|
938
938
|
if (hasExt) {
|
|
939
939
|
const candidate = path2.win32.join(dir, command);
|
|
940
|
-
if (
|
|
940
|
+
if (existsSync10(candidate)) {
|
|
941
941
|
return candidate;
|
|
942
942
|
}
|
|
943
943
|
continue;
|
|
944
944
|
}
|
|
945
945
|
for (const ext of extensions) {
|
|
946
946
|
const candidate = path2.win32.join(dir, command + ext);
|
|
947
|
-
if (
|
|
947
|
+
if (existsSync10(candidate)) {
|
|
948
948
|
return candidate;
|
|
949
949
|
}
|
|
950
950
|
}
|
|
@@ -2107,6 +2107,157 @@ var init_command_check = __esm({
|
|
|
2107
2107
|
}
|
|
2108
2108
|
});
|
|
2109
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
|
+
|
|
2110
2261
|
// packages/server/src/provider-runtime/install-manager.ts
|
|
2111
2262
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2112
2263
|
function getErrorDetails(error) {
|
|
@@ -3589,8 +3740,8 @@ var init_database = __esm({
|
|
|
3589
3740
|
|
|
3590
3741
|
// packages/server/src/storage/db.ts
|
|
3591
3742
|
import { DatabaseSync } from "node:sqlite";
|
|
3592
|
-
import { readFileSync as
|
|
3593
|
-
import { join as
|
|
3743
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
3744
|
+
import { join as join4 } from "path";
|
|
3594
3745
|
function normalizeSql(sql) {
|
|
3595
3746
|
return (sql ?? "").replace(/\s+/g, " ").trim();
|
|
3596
3747
|
}
|
|
@@ -3737,8 +3888,8 @@ var init_db = __esm({
|
|
|
3737
3888
|
"packages/server/src/storage/db.ts"() {
|
|
3738
3889
|
"use strict";
|
|
3739
3890
|
init_database();
|
|
3740
|
-
SCHEMA_PATH =
|
|
3741
|
-
SCHEMA_SQL =
|
|
3891
|
+
SCHEMA_PATH = join4(import.meta.dirname, "migrations", "001_init.sql");
|
|
3892
|
+
SCHEMA_SQL = readFileSync6(SCHEMA_PATH, "utf-8");
|
|
3742
3893
|
LEGACY_TABLES = ["hook_registrations", "_migrations"];
|
|
3743
3894
|
LEGACY_SESSION_COLUMNS = ["resume_id", "transcript_path"];
|
|
3744
3895
|
EXPECTED_SCHEMA_ENTRIES = buildExpectedSchemaEntries();
|
|
@@ -4670,6 +4821,7 @@ function parseFetchUpdatedRefs(stderr) {
|
|
|
4670
4821
|
}
|
|
4671
4822
|
async function runGitCheckout(cwd, ref, options) {
|
|
4672
4823
|
const args = ["checkout"];
|
|
4824
|
+
const formatCheckoutError = (error, fallbackMessage) => error instanceof GitError ? error.stderr.trim() || error.message || fallbackMessage : fallbackMessage;
|
|
4673
4825
|
let isRemoteRef = false;
|
|
4674
4826
|
try {
|
|
4675
4827
|
const { stdout: remoteList } = await runGit(cwd, ["remote"]);
|
|
@@ -4681,15 +4833,22 @@ async function runGitCheckout(cwd, ref, options) {
|
|
|
4681
4833
|
if (isRemoteRef && !options?.createBranch) {
|
|
4682
4834
|
const remoteSeparatorIndex = ref.indexOf("/");
|
|
4683
4835
|
const branchName = remoteSeparatorIndex >= 0 ? ref.slice(remoteSeparatorIndex + 1) : ref;
|
|
4684
|
-
|
|
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
|
+
}
|
|
4685
4844
|
try {
|
|
4686
4845
|
const { stdout, stderr } = await runGit(cwd, args);
|
|
4687
4846
|
const message = stdout || stderr || `Checkout to ${ref} completed`;
|
|
4688
4847
|
return { success: true, message, branch: branchName };
|
|
4689
|
-
} catch {
|
|
4848
|
+
} catch (error) {
|
|
4690
4849
|
return {
|
|
4691
4850
|
success: false,
|
|
4692
|
-
message: `Failed to checkout remote branch '${ref}'`
|
|
4851
|
+
message: formatCheckoutError(error, `Failed to checkout remote branch '${ref}'`)
|
|
4693
4852
|
};
|
|
4694
4853
|
}
|
|
4695
4854
|
} else {
|
|
@@ -4703,10 +4862,10 @@ async function runGitCheckout(cwd, ref, options) {
|
|
|
4703
4862
|
const branch = branchMatch?.[1] ?? ref;
|
|
4704
4863
|
const message = stdout || stderr || `Checkout to ${ref} completed`;
|
|
4705
4864
|
return { success: true, message, branch };
|
|
4706
|
-
} catch {
|
|
4865
|
+
} catch (error) {
|
|
4707
4866
|
return {
|
|
4708
4867
|
success: false,
|
|
4709
|
-
message: `Failed to checkout '${ref}'`
|
|
4868
|
+
message: formatCheckoutError(error, `Failed to checkout '${ref}'`)
|
|
4710
4869
|
};
|
|
4711
4870
|
}
|
|
4712
4871
|
}
|
|
@@ -4721,23 +4880,42 @@ async function runGitCreateBranch(cwd, branchName, options) {
|
|
|
4721
4880
|
}
|
|
4722
4881
|
async function runGitListBranches(cwd) {
|
|
4723
4882
|
const { stdout: localOutput } = await runGit(cwd, ["branch", "--list"]);
|
|
4883
|
+
const { stdout: localVerboseOutput } = await runGit(cwd, ["branch", "--list", "-vv"]);
|
|
4724
4884
|
const { stdout: remoteOutput } = await runGit(cwd, ["branch", "-r"]);
|
|
4725
4885
|
const branches = [];
|
|
4726
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
|
+
}
|
|
4727
4901
|
const localLines = localOutput.split("\n").filter((line) => line.trim());
|
|
4728
4902
|
for (const line of localLines) {
|
|
4729
4903
|
const isCurrent = line.startsWith("*");
|
|
4730
|
-
const name = line.replace(
|
|
4904
|
+
const name = line.replace(/^[*+ ]\s+/, "").trim();
|
|
4731
4905
|
if (name.startsWith("(HEAD detached")) {
|
|
4732
4906
|
if (isCurrent) {
|
|
4733
4907
|
current = "";
|
|
4734
4908
|
}
|
|
4735
4909
|
continue;
|
|
4736
4910
|
}
|
|
4911
|
+
if (linkedWorktreePathsByBranch.has(name) && !isCurrent) {
|
|
4912
|
+
continue;
|
|
4913
|
+
}
|
|
4737
4914
|
branches.push({
|
|
4738
4915
|
name,
|
|
4739
4916
|
isRemote: false,
|
|
4740
|
-
isCurrent
|
|
4917
|
+
isCurrent,
|
|
4918
|
+
linkedWorktreePath: linkedWorktreePathsByBranch.get(name)
|
|
4741
4919
|
});
|
|
4742
4920
|
if (isCurrent) {
|
|
4743
4921
|
current = name;
|
|
@@ -5186,7 +5364,7 @@ var init_context_builder = __esm({
|
|
|
5186
5364
|
});
|
|
5187
5365
|
|
|
5188
5366
|
// packages/server/src/terminal/pty-host.ts
|
|
5189
|
-
import { chmodSync, existsSync as
|
|
5367
|
+
import { chmodSync as chmodSync2, existsSync as existsSync7, statSync } from "node:fs";
|
|
5190
5368
|
import { createRequire } from "node:module";
|
|
5191
5369
|
import path6 from "node:path";
|
|
5192
5370
|
function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
@@ -5196,9 +5374,9 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
5196
5374
|
}
|
|
5197
5375
|
const arch = deps.arch ?? process.arch;
|
|
5198
5376
|
const resolve4 = deps.resolve ?? ((id) => require2.resolve(id));
|
|
5199
|
-
const fileExists = deps.existsSync ??
|
|
5377
|
+
const fileExists = deps.existsSync ?? existsSync7;
|
|
5200
5378
|
const stat7 = deps.statSync ?? statSync;
|
|
5201
|
-
const chmod = deps.chmodSync ??
|
|
5379
|
+
const chmod = deps.chmodSync ?? chmodSync2;
|
|
5202
5380
|
let packageJsonPath;
|
|
5203
5381
|
try {
|
|
5204
5382
|
packageJsonPath = resolve4(NODE_PTY_PKG);
|
|
@@ -7268,9 +7446,9 @@ var init_validator = __esm({
|
|
|
7268
7446
|
});
|
|
7269
7447
|
|
|
7270
7448
|
// packages/server/src/fs/gitignore.ts
|
|
7271
|
-
import { existsSync as
|
|
7449
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
|
|
7272
7450
|
import ignore from "ignore";
|
|
7273
|
-
import { join as
|
|
7451
|
+
import { join as join5, relative as relative3 } from "path";
|
|
7274
7452
|
function normalizePath(path10) {
|
|
7275
7453
|
return path10.replace(/\\/g, "/");
|
|
7276
7454
|
}
|
|
@@ -7290,26 +7468,26 @@ function isIgnoredByGitignore(ig, path10) {
|
|
|
7290
7468
|
return ig.ignores(path10) || ig.ignores(`${path10}/`);
|
|
7291
7469
|
}
|
|
7292
7470
|
function createGitignoreFilter(rootPath, dirPath) {
|
|
7293
|
-
const gitignorePath =
|
|
7294
|
-
if (!
|
|
7471
|
+
const gitignorePath = join5(rootPath, ".gitignore");
|
|
7472
|
+
if (!existsSync8(gitignorePath)) {
|
|
7295
7473
|
return (name) => !isDefaultTreeIgnored(name);
|
|
7296
7474
|
}
|
|
7297
|
-
const gitignoreContent =
|
|
7475
|
+
const gitignoreContent = readFileSync7(gitignorePath, "utf-8");
|
|
7298
7476
|
const ig = ignore().add(gitignoreContent);
|
|
7299
7477
|
return (name) => {
|
|
7300
7478
|
if (isAlwaysTreeIgnored(name)) {
|
|
7301
7479
|
return false;
|
|
7302
7480
|
}
|
|
7303
|
-
const relativePath = relativeToRoot(rootPath,
|
|
7481
|
+
const relativePath = relativeToRoot(rootPath, join5(dirPath, name));
|
|
7304
7482
|
return !isIgnoredByGitignore(ig, relativePath);
|
|
7305
7483
|
};
|
|
7306
7484
|
}
|
|
7307
7485
|
function createWatcherIgnoreFilter(rootPath) {
|
|
7308
|
-
const gitignorePath =
|
|
7309
|
-
if (!
|
|
7486
|
+
const gitignorePath = join5(rootPath, ".gitignore");
|
|
7487
|
+
if (!existsSync8(gitignorePath)) {
|
|
7310
7488
|
return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
|
|
7311
7489
|
}
|
|
7312
|
-
const gitignoreContent =
|
|
7490
|
+
const gitignoreContent = readFileSync7(gitignorePath, "utf-8");
|
|
7313
7491
|
const ig = ignore().add(gitignoreContent);
|
|
7314
7492
|
return (path10) => {
|
|
7315
7493
|
const normalizedPath = normalizePath(path10);
|
|
@@ -7436,6 +7614,11 @@ var init_manager4 = __esm({
|
|
|
7436
7614
|
new WorkspaceWatcher(workspaceId, rootPath, this.deps.broadcaster)
|
|
7437
7615
|
);
|
|
7438
7616
|
}
|
|
7617
|
+
hydrateWatchers() {
|
|
7618
|
+
for (const workspace of this.list()) {
|
|
7619
|
+
this.startWatcher(workspace.id, workspace.path);
|
|
7620
|
+
}
|
|
7621
|
+
}
|
|
7439
7622
|
updateUiState(workspaceId, uiState) {
|
|
7440
7623
|
const workspace = this.get(workspaceId);
|
|
7441
7624
|
if (!workspace) {
|
|
@@ -8911,7 +9094,7 @@ var init_hub = __esm({
|
|
|
8911
9094
|
// packages/server/src/commands/workspace.ts
|
|
8912
9095
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
8913
9096
|
import { homedir as homedir3 } from "node:os";
|
|
8914
|
-
import { join as
|
|
9097
|
+
import { join as join6 } from "node:path";
|
|
8915
9098
|
import { z as z6 } from "zod";
|
|
8916
9099
|
var init_workspace = __esm({
|
|
8917
9100
|
"packages/server/src/commands/workspace.ts"() {
|
|
@@ -8930,11 +9113,11 @@ var init_workspace = __esm({
|
|
|
8930
9113
|
const entries = await readdir2(basePath, { withFileTypes: true });
|
|
8931
9114
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
8932
9115
|
name: entry.name,
|
|
8933
|
-
path:
|
|
9116
|
+
path: join6(basePath, entry.name)
|
|
8934
9117
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
8935
9118
|
return {
|
|
8936
9119
|
currentPath: basePath,
|
|
8937
|
-
parentPath: basePath !== "/" ?
|
|
9120
|
+
parentPath: basePath !== "/" ? join6(basePath, "..") : null,
|
|
8938
9121
|
directories
|
|
8939
9122
|
};
|
|
8940
9123
|
}
|
|
@@ -9207,9 +9390,9 @@ var init_session = __esm({
|
|
|
9207
9390
|
|
|
9208
9391
|
// packages/server/src/fs/tree.ts
|
|
9209
9392
|
import { readdir as readdir3, stat as stat6 } from "fs/promises";
|
|
9210
|
-
import { join as
|
|
9393
|
+
import { join as join7, relative as relative4 } from "path";
|
|
9211
9394
|
async function readTree(rootPath, subdir) {
|
|
9212
|
-
const targetPath = subdir ?
|
|
9395
|
+
const targetPath = subdir ? join7(rootPath, subdir) : rootPath;
|
|
9213
9396
|
const filter = createGitignoreFilter(rootPath, targetPath);
|
|
9214
9397
|
const entries = await readdir3(targetPath, { withFileTypes: true });
|
|
9215
9398
|
const nodes = [];
|
|
@@ -9217,7 +9400,7 @@ async function readTree(rootPath, subdir) {
|
|
|
9217
9400
|
if (!filter(entry.name)) {
|
|
9218
9401
|
continue;
|
|
9219
9402
|
}
|
|
9220
|
-
const fullPath =
|
|
9403
|
+
const fullPath = join7(targetPath, entry.name);
|
|
9221
9404
|
const relPath = relative4(rootPath, fullPath);
|
|
9222
9405
|
if (entry.isDirectory()) {
|
|
9223
9406
|
nodes.push({
|
|
@@ -9261,7 +9444,7 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
9261
9444
|
const filteredEntries = entries.filter((entry) => filter(entry.name));
|
|
9262
9445
|
filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
9263
9446
|
for (const entry of filteredEntries) {
|
|
9264
|
-
const fullPath =
|
|
9447
|
+
const fullPath = join7(dirPath, entry.name);
|
|
9265
9448
|
const relPath = relative4(rootPath, fullPath);
|
|
9266
9449
|
if (entry.isDirectory()) {
|
|
9267
9450
|
await walk(fullPath);
|
|
@@ -9873,37 +10056,37 @@ var init_git2 = __esm({
|
|
|
9873
10056
|
});
|
|
9874
10057
|
|
|
9875
10058
|
// packages/server/src/config/config-io.ts
|
|
9876
|
-
import { existsSync as
|
|
10059
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
9877
10060
|
import { homedir as homedir4 } from "node:os";
|
|
9878
|
-
import { basename as basename3, dirname as
|
|
10061
|
+
import { basename as basename3, dirname as dirname5, join as join8 } from "node:path";
|
|
9879
10062
|
function resolveConfigPath(configType) {
|
|
9880
10063
|
if (configType === "codex") {
|
|
9881
10064
|
const testHome = process.env.CODER_STUDIO_CODEX_HOME;
|
|
9882
10065
|
if (testHome && testHome.trim()) {
|
|
9883
|
-
return
|
|
10066
|
+
return join8(testHome, "config.toml");
|
|
9884
10067
|
}
|
|
9885
10068
|
const codexHome = process.env.CODEX_HOME;
|
|
9886
10069
|
if (codexHome && codexHome.trim()) {
|
|
9887
|
-
return
|
|
10070
|
+
return join8(codexHome, "config.toml");
|
|
9888
10071
|
}
|
|
9889
|
-
return
|
|
10072
|
+
return join8(homedir4(), ".codex", "config.toml");
|
|
9890
10073
|
}
|
|
9891
10074
|
if (configType === "claude") {
|
|
9892
10075
|
const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
|
|
9893
10076
|
if (testHome && testHome.trim()) {
|
|
9894
|
-
return
|
|
10077
|
+
return join8(testHome, "settings.json");
|
|
9895
10078
|
}
|
|
9896
|
-
return
|
|
10079
|
+
return join8(homedir4(), ".claude", "settings.json");
|
|
9897
10080
|
}
|
|
9898
10081
|
throw new Error(`Unknown config type: ${configType}`);
|
|
9899
10082
|
}
|
|
9900
10083
|
function readConfigFile(configType) {
|
|
9901
10084
|
const configPath = resolveConfigPath(configType);
|
|
9902
|
-
if (!
|
|
10085
|
+
if (!existsSync9(configPath)) {
|
|
9903
10086
|
return { configPath, content: "", exists: false };
|
|
9904
10087
|
}
|
|
9905
10088
|
try {
|
|
9906
|
-
const content =
|
|
10089
|
+
const content = readFileSync8(configPath, "utf-8");
|
|
9907
10090
|
return { configPath, content, exists: true };
|
|
9908
10091
|
} catch {
|
|
9909
10092
|
return { configPath, content: "", exists: false };
|
|
@@ -9912,16 +10095,16 @@ function readConfigFile(configType) {
|
|
|
9912
10095
|
function writeConfigFile(configType, content) {
|
|
9913
10096
|
try {
|
|
9914
10097
|
const configPath = resolveConfigPath(configType);
|
|
9915
|
-
const parentDir =
|
|
9916
|
-
if (!
|
|
9917
|
-
|
|
10098
|
+
const parentDir = dirname5(configPath);
|
|
10099
|
+
if (!existsSync9(parentDir)) {
|
|
10100
|
+
mkdirSync4(parentDir, { recursive: true });
|
|
9918
10101
|
}
|
|
9919
10102
|
let backupPath = null;
|
|
9920
|
-
if (
|
|
10103
|
+
if (existsSync9(configPath)) {
|
|
9921
10104
|
backupPath = createBackup(configPath);
|
|
9922
10105
|
}
|
|
9923
10106
|
const tempPath = `${configPath}.tmp`;
|
|
9924
|
-
|
|
10107
|
+
writeFileSync4(tempPath, content, "utf-8");
|
|
9925
10108
|
renameSync(tempPath, configPath);
|
|
9926
10109
|
return { success: true, backupPath };
|
|
9927
10110
|
} catch (error) {
|
|
@@ -9933,13 +10116,13 @@ function writeConfigFile(configType, content) {
|
|
|
9933
10116
|
}
|
|
9934
10117
|
}
|
|
9935
10118
|
function createBackup(filePath) {
|
|
9936
|
-
const original =
|
|
10119
|
+
const original = readFileSync8(filePath, "utf-8");
|
|
9937
10120
|
const ext = filePath.split(".").pop() ?? "";
|
|
9938
10121
|
const base = basename3(filePath, `.${ext}`);
|
|
9939
|
-
const dir =
|
|
10122
|
+
const dir = dirname5(filePath);
|
|
9940
10123
|
const ts = formatTimestamp(/* @__PURE__ */ new Date());
|
|
9941
|
-
const backupPath =
|
|
9942
|
-
|
|
10124
|
+
const backupPath = join8(dir, `${base}.bak.${ts}.${ext}`);
|
|
10125
|
+
writeFileSync4(backupPath, original, "utf-8");
|
|
9943
10126
|
return backupPath;
|
|
9944
10127
|
}
|
|
9945
10128
|
function formatTimestamp(d) {
|
|
@@ -10643,6 +10826,7 @@ async function createServer(configOverrides) {
|
|
|
10643
10826
|
(err) => console.warn("[uploads] cascade cleanup failed", { wsId: workspaceId, err })
|
|
10644
10827
|
)
|
|
10645
10828
|
});
|
|
10829
|
+
workspaceMgr.hydrateWatchers();
|
|
10646
10830
|
const authSessionRepo = new AuthSessionRepo(db);
|
|
10647
10831
|
const authLoginBlockRepo = new AuthLoginBlockRepo(db);
|
|
10648
10832
|
const app = await buildFastifyApp({
|
|
@@ -10682,10 +10866,13 @@ async function createServer(configOverrides) {
|
|
|
10682
10866
|
});
|
|
10683
10867
|
await sessionMgr.hydrate();
|
|
10684
10868
|
await supervisorMgr.hydrate();
|
|
10685
|
-
const
|
|
10869
|
+
const providerMockOverrides = createE2EProviderMockOverrides();
|
|
10870
|
+
const providerRuntimeDeps = providerMockOverrides ? {
|
|
10871
|
+
commandExists: providerMockOverrides.commandExists
|
|
10872
|
+
} : {};
|
|
10686
10873
|
const providerInstallMgr = new ProviderInstallManager(providerRegistry, {
|
|
10687
10874
|
...providerRuntimeDeps,
|
|
10688
|
-
runCommand: runCommandAsString
|
|
10875
|
+
runCommand: providerMockOverrides?.runCommand ?? runCommandAsString
|
|
10689
10876
|
});
|
|
10690
10877
|
commandContext = {
|
|
10691
10878
|
workspaceMgr,
|
|
@@ -10855,6 +11042,7 @@ var init_server = __esm({
|
|
|
10855
11042
|
init_config();
|
|
10856
11043
|
init_auto_fetch();
|
|
10857
11044
|
init_command_runner();
|
|
11045
|
+
init_e2e_provider_mock();
|
|
10858
11046
|
init_install_manager();
|
|
10859
11047
|
init_manager();
|
|
10860
11048
|
init_db();
|