@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
package/dist/esm/bin.mjs
CHANGED
|
@@ -885,11 +885,11 @@ function resolveSpawnArgv(argv, deps = {}) {
|
|
|
885
885
|
return [];
|
|
886
886
|
}
|
|
887
887
|
const restArgs = argv.slice(1);
|
|
888
|
-
const
|
|
889
|
-
const
|
|
888
|
+
const readFileSync9 = deps.readFileSync ?? ((file) => fs2.readFileSync(file, "utf8"));
|
|
889
|
+
const existsSync12 = deps.existsSync ?? fs2.existsSync;
|
|
890
890
|
const pathEnv = deps.pathEnv ?? process.env.Path ?? process.env.PATH ?? "";
|
|
891
891
|
const pathExt = deps.pathExt ?? process.env.PATHEXT ?? DEFAULT_PATHEXT;
|
|
892
|
-
const resolved = resolveExecutablePath(command, pathEnv, pathExt,
|
|
892
|
+
const resolved = resolveExecutablePath(command, pathEnv, pathExt, existsSync12);
|
|
893
893
|
if (!resolved) {
|
|
894
894
|
return [...argv];
|
|
895
895
|
}
|
|
@@ -900,7 +900,7 @@ function resolveSpawnArgv(argv, deps = {}) {
|
|
|
900
900
|
if (ext === ".cmd" || ext === ".bat") {
|
|
901
901
|
let content;
|
|
902
902
|
try {
|
|
903
|
-
content =
|
|
903
|
+
content = readFileSync9(resolved);
|
|
904
904
|
} catch {
|
|
905
905
|
return ["cmd.exe", "/d", "/s", "/c", resolved, ...restArgs];
|
|
906
906
|
}
|
|
@@ -938,17 +938,17 @@ function expandShimVars(value, dp0Dir) {
|
|
|
938
938
|
function parsePathExt(pathExt) {
|
|
939
939
|
return pathExt.split(";").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
|
|
940
940
|
}
|
|
941
|
-
function resolveExecutablePath(command, pathEnv, pathExt,
|
|
941
|
+
function resolveExecutablePath(command, pathEnv, pathExt, existsSync12) {
|
|
942
942
|
const hasExt = path2.win32.extname(command).length > 0;
|
|
943
943
|
const extensions = parsePathExt(pathExt);
|
|
944
944
|
if (path2.win32.isAbsolute(command)) {
|
|
945
|
-
if (
|
|
945
|
+
if (existsSync12(command)) {
|
|
946
946
|
return command;
|
|
947
947
|
}
|
|
948
948
|
if (!hasExt) {
|
|
949
949
|
for (const ext of extensions) {
|
|
950
950
|
const candidate = command + ext;
|
|
951
|
-
if (
|
|
951
|
+
if (existsSync12(candidate)) {
|
|
952
952
|
return candidate;
|
|
953
953
|
}
|
|
954
954
|
}
|
|
@@ -959,14 +959,14 @@ function resolveExecutablePath(command, pathEnv, pathExt, existsSync11) {
|
|
|
959
959
|
for (const dir of dirs) {
|
|
960
960
|
if (hasExt) {
|
|
961
961
|
const candidate = path2.win32.join(dir, command);
|
|
962
|
-
if (
|
|
962
|
+
if (existsSync12(candidate)) {
|
|
963
963
|
return candidate;
|
|
964
964
|
}
|
|
965
965
|
continue;
|
|
966
966
|
}
|
|
967
967
|
for (const ext of extensions) {
|
|
968
968
|
const candidate = path2.win32.join(dir, command + ext);
|
|
969
|
-
if (
|
|
969
|
+
if (existsSync12(candidate)) {
|
|
970
970
|
return candidate;
|
|
971
971
|
}
|
|
972
972
|
}
|
|
@@ -2129,6 +2129,157 @@ var init_command_check = __esm({
|
|
|
2129
2129
|
}
|
|
2130
2130
|
});
|
|
2131
2131
|
|
|
2132
|
+
// packages/server/src/provider-runtime/e2e-provider-mock.ts
|
|
2133
|
+
import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2134
|
+
import { dirname as dirname3, join as join2 } from "node:path";
|
|
2135
|
+
function createE2EProviderMockOverrides(env = process.env) {
|
|
2136
|
+
const statePath = env.CODER_STUDIO_E2E_PROVIDER_STATE_PATH;
|
|
2137
|
+
if (!statePath) {
|
|
2138
|
+
return null;
|
|
2139
|
+
}
|
|
2140
|
+
const binDir = env.CODER_STUDIO_E2E_PROVIDER_BIN_DIR;
|
|
2141
|
+
const debugLogPath = env.CODER_STUDIO_E2E_PROVIDER_DEBUG_LOG_PATH;
|
|
2142
|
+
appendDebugLog(debugLogPath, `init statePath=${statePath} binDir=${binDir ?? ""}`);
|
|
2143
|
+
const commandExists = async (command) => {
|
|
2144
|
+
const state = readMockState(statePath);
|
|
2145
|
+
const override = state.commands?.[command];
|
|
2146
|
+
appendDebugLog(
|
|
2147
|
+
debugLogPath,
|
|
2148
|
+
`commandExists ${command} override=${String(override)} state=${JSON.stringify(state.commands ?? {})}`
|
|
2149
|
+
);
|
|
2150
|
+
if (typeof override === "boolean") {
|
|
2151
|
+
return override;
|
|
2152
|
+
}
|
|
2153
|
+
return checkCommandAvailable(command);
|
|
2154
|
+
};
|
|
2155
|
+
const runCommand2 = async (file, args, options) => {
|
|
2156
|
+
const providerId = getInstallProviderId(file, args);
|
|
2157
|
+
appendDebugLog(
|
|
2158
|
+
debugLogPath,
|
|
2159
|
+
`runCommand ${file} ${args.join(" ")} provider=${providerId ?? "none"}`
|
|
2160
|
+
);
|
|
2161
|
+
if (!providerId) {
|
|
2162
|
+
return runCommandAsString(file, args, options);
|
|
2163
|
+
}
|
|
2164
|
+
const state = readMockState(statePath);
|
|
2165
|
+
const behavior = state.installBehavior?.[providerId];
|
|
2166
|
+
appendDebugLog(
|
|
2167
|
+
debugLogPath,
|
|
2168
|
+
`behavior ${providerId} ${JSON.stringify(behavior)} state=${JSON.stringify(state)}`
|
|
2169
|
+
);
|
|
2170
|
+
if (!behavior) {
|
|
2171
|
+
return runCommandAsString(file, args, options);
|
|
2172
|
+
}
|
|
2173
|
+
if (behavior.result === "success") {
|
|
2174
|
+
writeMockState(statePath, (draft) => {
|
|
2175
|
+
draft.commands ??= {};
|
|
2176
|
+
draft.commands[providerId] = true;
|
|
2177
|
+
});
|
|
2178
|
+
if (binDir) {
|
|
2179
|
+
ensureProviderCommand(binDir, providerId);
|
|
2180
|
+
}
|
|
2181
|
+
appendDebugLog(debugLogPath, `install success ${providerId}`);
|
|
2182
|
+
return {
|
|
2183
|
+
stdout: `installed ${providerId}`,
|
|
2184
|
+
stderr: ""
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
const message = behavior.message ?? (behavior.result === "permission_denied" ? "permission denied" : "command not found");
|
|
2188
|
+
throw Object.assign(new Error(message), {
|
|
2189
|
+
exitCode: 1,
|
|
2190
|
+
stdout: "",
|
|
2191
|
+
stderr: message
|
|
2192
|
+
});
|
|
2193
|
+
};
|
|
2194
|
+
return {
|
|
2195
|
+
commandExists,
|
|
2196
|
+
runCommand: runCommand2
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
function getInstallProviderId(file, args) {
|
|
2200
|
+
if (file !== "npm" || args.length !== 3) {
|
|
2201
|
+
return null;
|
|
2202
|
+
}
|
|
2203
|
+
if (args[0] !== "install" || args[1] !== "-g") {
|
|
2204
|
+
return null;
|
|
2205
|
+
}
|
|
2206
|
+
const packageName = args[2];
|
|
2207
|
+
if (packageName === PROVIDER_INSTALL_PACKAGES.claude) {
|
|
2208
|
+
return "claude";
|
|
2209
|
+
}
|
|
2210
|
+
if (packageName === PROVIDER_INSTALL_PACKAGES.codex) {
|
|
2211
|
+
return "codex";
|
|
2212
|
+
}
|
|
2213
|
+
return null;
|
|
2214
|
+
}
|
|
2215
|
+
function readMockState(statePath) {
|
|
2216
|
+
if (!existsSync3(statePath)) {
|
|
2217
|
+
return {};
|
|
2218
|
+
}
|
|
2219
|
+
const raw = readFileSync3(statePath, "utf8");
|
|
2220
|
+
if (!raw.trim()) {
|
|
2221
|
+
return {};
|
|
2222
|
+
}
|
|
2223
|
+
try {
|
|
2224
|
+
return JSON.parse(raw);
|
|
2225
|
+
} catch (error) {
|
|
2226
|
+
throw new Error(
|
|
2227
|
+
`Invalid provider mock state at ${statePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
function writeMockState(statePath, updater) {
|
|
2232
|
+
const nextState = readMockState(statePath);
|
|
2233
|
+
updater(nextState);
|
|
2234
|
+
mkdirSync2(dirname3(statePath), { recursive: true });
|
|
2235
|
+
writeFileSync2(statePath, JSON.stringify(nextState, null, 2));
|
|
2236
|
+
return nextState;
|
|
2237
|
+
}
|
|
2238
|
+
function ensureProviderCommand(binDir, providerId) {
|
|
2239
|
+
mkdirSync2(binDir, { recursive: true });
|
|
2240
|
+
const scriptPath = join2(binDir, providerId);
|
|
2241
|
+
writeFileSync2(scriptPath, PROVIDER_COMMAND_SCRIPTS[providerId], "utf8");
|
|
2242
|
+
chmodSync(scriptPath, 493);
|
|
2243
|
+
}
|
|
2244
|
+
function appendDebugLog(path10, line) {
|
|
2245
|
+
if (!path10) {
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
mkdirSync2(dirname3(path10), { recursive: true });
|
|
2249
|
+
writeFileSync2(path10, `${line}
|
|
2250
|
+
`, { flag: "a" });
|
|
2251
|
+
}
|
|
2252
|
+
var PROVIDER_INSTALL_PACKAGES, PROVIDER_COMMAND_SCRIPTS;
|
|
2253
|
+
var init_e2e_provider_mock = __esm({
|
|
2254
|
+
"packages/server/src/provider-runtime/e2e-provider-mock.ts"() {
|
|
2255
|
+
"use strict";
|
|
2256
|
+
init_command_check();
|
|
2257
|
+
init_command_runner();
|
|
2258
|
+
PROVIDER_INSTALL_PACKAGES = {
|
|
2259
|
+
claude: "@anthropic-ai/claude-code",
|
|
2260
|
+
codex: "@openai/codex"
|
|
2261
|
+
};
|
|
2262
|
+
PROVIDER_COMMAND_SCRIPTS = {
|
|
2263
|
+
claude: `#!/usr/bin/env bash
|
|
2264
|
+
set -euo pipefail
|
|
2265
|
+
trap 'exit 0' TERM INT
|
|
2266
|
+
printf 'Mock Claude ready\\n'
|
|
2267
|
+
while true; do
|
|
2268
|
+
sleep 1
|
|
2269
|
+
done
|
|
2270
|
+
`,
|
|
2271
|
+
codex: `#!/usr/bin/env bash
|
|
2272
|
+
set -euo pipefail
|
|
2273
|
+
trap 'exit 0' TERM INT
|
|
2274
|
+
printf 'Session ID: abcdef-123456\\n> '
|
|
2275
|
+
while true; do
|
|
2276
|
+
sleep 1
|
|
2277
|
+
done
|
|
2278
|
+
`
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
});
|
|
2282
|
+
|
|
2132
2283
|
// packages/server/src/provider-runtime/install-manager.ts
|
|
2133
2284
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2134
2285
|
function getErrorDetails(error) {
|
|
@@ -3611,8 +3762,8 @@ var init_database = __esm({
|
|
|
3611
3762
|
|
|
3612
3763
|
// packages/server/src/storage/db.ts
|
|
3613
3764
|
import { DatabaseSync } from "node:sqlite";
|
|
3614
|
-
import { readFileSync as
|
|
3615
|
-
import { join as
|
|
3765
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
3766
|
+
import { join as join3 } from "path";
|
|
3616
3767
|
function normalizeSql(sql) {
|
|
3617
3768
|
return (sql ?? "").replace(/\s+/g, " ").trim();
|
|
3618
3769
|
}
|
|
@@ -3759,8 +3910,8 @@ var init_db = __esm({
|
|
|
3759
3910
|
"packages/server/src/storage/db.ts"() {
|
|
3760
3911
|
"use strict";
|
|
3761
3912
|
init_database();
|
|
3762
|
-
SCHEMA_PATH =
|
|
3763
|
-
SCHEMA_SQL =
|
|
3913
|
+
SCHEMA_PATH = join3(import.meta.dirname, "migrations", "001_init.sql");
|
|
3914
|
+
SCHEMA_SQL = readFileSync4(SCHEMA_PATH, "utf-8");
|
|
3764
3915
|
LEGACY_TABLES = ["hook_registrations", "_migrations"];
|
|
3765
3916
|
LEGACY_SESSION_COLUMNS = ["resume_id", "transcript_path"];
|
|
3766
3917
|
EXPECTED_SCHEMA_ENTRIES = buildExpectedSchemaEntries();
|
|
@@ -4692,6 +4843,7 @@ function parseFetchUpdatedRefs(stderr) {
|
|
|
4692
4843
|
}
|
|
4693
4844
|
async function runGitCheckout(cwd, ref, options) {
|
|
4694
4845
|
const args = ["checkout"];
|
|
4846
|
+
const formatCheckoutError = (error, fallbackMessage) => error instanceof GitError ? error.stderr.trim() || error.message || fallbackMessage : fallbackMessage;
|
|
4695
4847
|
let isRemoteRef = false;
|
|
4696
4848
|
try {
|
|
4697
4849
|
const { stdout: remoteList } = await runGit(cwd, ["remote"]);
|
|
@@ -4703,15 +4855,22 @@ async function runGitCheckout(cwd, ref, options) {
|
|
|
4703
4855
|
if (isRemoteRef && !options?.createBranch) {
|
|
4704
4856
|
const remoteSeparatorIndex = ref.indexOf("/");
|
|
4705
4857
|
const branchName = remoteSeparatorIndex >= 0 ? ref.slice(remoteSeparatorIndex + 1) : ref;
|
|
4706
|
-
|
|
4858
|
+
try {
|
|
4859
|
+
await runGit(cwd, ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`]);
|
|
4860
|
+
const { stdout, stderr } = await runGit(cwd, ["checkout", branchName]);
|
|
4861
|
+
const message = stdout || stderr || `Checkout to ${branchName} completed`;
|
|
4862
|
+
return { success: true, message, branch: branchName };
|
|
4863
|
+
} catch {
|
|
4864
|
+
args.push("-b", branchName, ref);
|
|
4865
|
+
}
|
|
4707
4866
|
try {
|
|
4708
4867
|
const { stdout, stderr } = await runGit(cwd, args);
|
|
4709
4868
|
const message = stdout || stderr || `Checkout to ${ref} completed`;
|
|
4710
4869
|
return { success: true, message, branch: branchName };
|
|
4711
|
-
} catch {
|
|
4870
|
+
} catch (error) {
|
|
4712
4871
|
return {
|
|
4713
4872
|
success: false,
|
|
4714
|
-
message: `Failed to checkout remote branch '${ref}'`
|
|
4873
|
+
message: formatCheckoutError(error, `Failed to checkout remote branch '${ref}'`)
|
|
4715
4874
|
};
|
|
4716
4875
|
}
|
|
4717
4876
|
} else {
|
|
@@ -4725,10 +4884,10 @@ async function runGitCheckout(cwd, ref, options) {
|
|
|
4725
4884
|
const branch = branchMatch?.[1] ?? ref;
|
|
4726
4885
|
const message = stdout || stderr || `Checkout to ${ref} completed`;
|
|
4727
4886
|
return { success: true, message, branch };
|
|
4728
|
-
} catch {
|
|
4887
|
+
} catch (error) {
|
|
4729
4888
|
return {
|
|
4730
4889
|
success: false,
|
|
4731
|
-
message: `Failed to checkout '${ref}'`
|
|
4890
|
+
message: formatCheckoutError(error, `Failed to checkout '${ref}'`)
|
|
4732
4891
|
};
|
|
4733
4892
|
}
|
|
4734
4893
|
}
|
|
@@ -4743,23 +4902,42 @@ async function runGitCreateBranch(cwd, branchName, options) {
|
|
|
4743
4902
|
}
|
|
4744
4903
|
async function runGitListBranches(cwd) {
|
|
4745
4904
|
const { stdout: localOutput } = await runGit(cwd, ["branch", "--list"]);
|
|
4905
|
+
const { stdout: localVerboseOutput } = await runGit(cwd, ["branch", "--list", "-vv"]);
|
|
4746
4906
|
const { stdout: remoteOutput } = await runGit(cwd, ["branch", "-r"]);
|
|
4747
4907
|
const branches = [];
|
|
4748
4908
|
let current = "";
|
|
4909
|
+
const linkedWorktreePathsByBranch = /* @__PURE__ */ new Map();
|
|
4910
|
+
const localVerboseLines = localVerboseOutput.split("\n").filter((line) => line.trim());
|
|
4911
|
+
for (const line of localVerboseLines) {
|
|
4912
|
+
const normalizedLine = line.replace(/^[*+ ]\s+/, "");
|
|
4913
|
+
const branchMatch = normalizedLine.match(/^([^\s]+)\s+/);
|
|
4914
|
+
const worktreeMatch = line.match(/\((.+?)\)\s/);
|
|
4915
|
+
if (!branchMatch?.[1] || !worktreeMatch?.[1]) {
|
|
4916
|
+
continue;
|
|
4917
|
+
}
|
|
4918
|
+
const worktreePath = worktreeMatch[1];
|
|
4919
|
+
if (worktreePath.startsWith("/") || worktreePath.startsWith("~")) {
|
|
4920
|
+
linkedWorktreePathsByBranch.set(branchMatch[1], worktreePath);
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4749
4923
|
const localLines = localOutput.split("\n").filter((line) => line.trim());
|
|
4750
4924
|
for (const line of localLines) {
|
|
4751
4925
|
const isCurrent = line.startsWith("*");
|
|
4752
|
-
const name = line.replace(
|
|
4926
|
+
const name = line.replace(/^[*+ ]\s+/, "").trim();
|
|
4753
4927
|
if (name.startsWith("(HEAD detached")) {
|
|
4754
4928
|
if (isCurrent) {
|
|
4755
4929
|
current = "";
|
|
4756
4930
|
}
|
|
4757
4931
|
continue;
|
|
4758
4932
|
}
|
|
4933
|
+
if (linkedWorktreePathsByBranch.has(name) && !isCurrent) {
|
|
4934
|
+
continue;
|
|
4935
|
+
}
|
|
4759
4936
|
branches.push({
|
|
4760
4937
|
name,
|
|
4761
4938
|
isRemote: false,
|
|
4762
|
-
isCurrent
|
|
4939
|
+
isCurrent,
|
|
4940
|
+
linkedWorktreePath: linkedWorktreePathsByBranch.get(name)
|
|
4763
4941
|
});
|
|
4764
4942
|
if (isCurrent) {
|
|
4765
4943
|
current = name;
|
|
@@ -5208,7 +5386,7 @@ var init_context_builder = __esm({
|
|
|
5208
5386
|
});
|
|
5209
5387
|
|
|
5210
5388
|
// packages/server/src/terminal/pty-host.ts
|
|
5211
|
-
import { chmodSync, existsSync as
|
|
5389
|
+
import { chmodSync as chmodSync2, existsSync as existsSync4, statSync } from "node:fs";
|
|
5212
5390
|
import { createRequire } from "node:module";
|
|
5213
5391
|
import path6 from "node:path";
|
|
5214
5392
|
function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
@@ -5218,9 +5396,9 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
5218
5396
|
}
|
|
5219
5397
|
const arch = deps.arch ?? process.arch;
|
|
5220
5398
|
const resolve4 = deps.resolve ?? ((id) => require2.resolve(id));
|
|
5221
|
-
const fileExists = deps.existsSync ??
|
|
5399
|
+
const fileExists = deps.existsSync ?? existsSync4;
|
|
5222
5400
|
const stat7 = deps.statSync ?? statSync;
|
|
5223
|
-
const chmod = deps.chmodSync ??
|
|
5401
|
+
const chmod = deps.chmodSync ?? chmodSync2;
|
|
5224
5402
|
let packageJsonPath;
|
|
5225
5403
|
try {
|
|
5226
5404
|
packageJsonPath = resolve4(NODE_PTY_PKG);
|
|
@@ -7290,9 +7468,9 @@ var init_validator = __esm({
|
|
|
7290
7468
|
});
|
|
7291
7469
|
|
|
7292
7470
|
// packages/server/src/fs/gitignore.ts
|
|
7293
|
-
import { existsSync as
|
|
7471
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
7294
7472
|
import ignore from "ignore";
|
|
7295
|
-
import { join as
|
|
7473
|
+
import { join as join4, relative as relative3 } from "path";
|
|
7296
7474
|
function normalizePath(path10) {
|
|
7297
7475
|
return path10.replace(/\\/g, "/");
|
|
7298
7476
|
}
|
|
@@ -7312,26 +7490,26 @@ function isIgnoredByGitignore(ig, path10) {
|
|
|
7312
7490
|
return ig.ignores(path10) || ig.ignores(`${path10}/`);
|
|
7313
7491
|
}
|
|
7314
7492
|
function createGitignoreFilter(rootPath, dirPath) {
|
|
7315
|
-
const gitignorePath =
|
|
7316
|
-
if (!
|
|
7493
|
+
const gitignorePath = join4(rootPath, ".gitignore");
|
|
7494
|
+
if (!existsSync5(gitignorePath)) {
|
|
7317
7495
|
return (name) => !isDefaultTreeIgnored(name);
|
|
7318
7496
|
}
|
|
7319
|
-
const gitignoreContent =
|
|
7497
|
+
const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
|
|
7320
7498
|
const ig = ignore().add(gitignoreContent);
|
|
7321
7499
|
return (name) => {
|
|
7322
7500
|
if (isAlwaysTreeIgnored(name)) {
|
|
7323
7501
|
return false;
|
|
7324
7502
|
}
|
|
7325
|
-
const relativePath = relativeToRoot(rootPath,
|
|
7503
|
+
const relativePath = relativeToRoot(rootPath, join4(dirPath, name));
|
|
7326
7504
|
return !isIgnoredByGitignore(ig, relativePath);
|
|
7327
7505
|
};
|
|
7328
7506
|
}
|
|
7329
7507
|
function createWatcherIgnoreFilter(rootPath) {
|
|
7330
|
-
const gitignorePath =
|
|
7331
|
-
if (!
|
|
7508
|
+
const gitignorePath = join4(rootPath, ".gitignore");
|
|
7509
|
+
if (!existsSync5(gitignorePath)) {
|
|
7332
7510
|
return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
|
|
7333
7511
|
}
|
|
7334
|
-
const gitignoreContent =
|
|
7512
|
+
const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
|
|
7335
7513
|
const ig = ignore().add(gitignoreContent);
|
|
7336
7514
|
return (path10) => {
|
|
7337
7515
|
const normalizedPath = normalizePath(path10);
|
|
@@ -7458,6 +7636,11 @@ var init_manager4 = __esm({
|
|
|
7458
7636
|
new WorkspaceWatcher(workspaceId, rootPath, this.deps.broadcaster)
|
|
7459
7637
|
);
|
|
7460
7638
|
}
|
|
7639
|
+
hydrateWatchers() {
|
|
7640
|
+
for (const workspace of this.list()) {
|
|
7641
|
+
this.startWatcher(workspace.id, workspace.path);
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
7461
7644
|
updateUiState(workspaceId, uiState) {
|
|
7462
7645
|
const workspace = this.get(workspaceId);
|
|
7463
7646
|
if (!workspace) {
|
|
@@ -8933,7 +9116,7 @@ var init_hub = __esm({
|
|
|
8933
9116
|
// packages/server/src/commands/workspace.ts
|
|
8934
9117
|
import { readdir as readdir2 } from "node:fs/promises";
|
|
8935
9118
|
import { homedir as homedir2 } from "node:os";
|
|
8936
|
-
import { join as
|
|
9119
|
+
import { join as join5 } from "node:path";
|
|
8937
9120
|
import { z as z6 } from "zod";
|
|
8938
9121
|
var init_workspace = __esm({
|
|
8939
9122
|
"packages/server/src/commands/workspace.ts"() {
|
|
@@ -8952,11 +9135,11 @@ var init_workspace = __esm({
|
|
|
8952
9135
|
const entries = await readdir2(basePath, { withFileTypes: true });
|
|
8953
9136
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
8954
9137
|
name: entry.name,
|
|
8955
|
-
path:
|
|
9138
|
+
path: join5(basePath, entry.name)
|
|
8956
9139
|
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
8957
9140
|
return {
|
|
8958
9141
|
currentPath: basePath,
|
|
8959
|
-
parentPath: basePath !== "/" ?
|
|
9142
|
+
parentPath: basePath !== "/" ? join5(basePath, "..") : null,
|
|
8960
9143
|
directories
|
|
8961
9144
|
};
|
|
8962
9145
|
}
|
|
@@ -9229,9 +9412,9 @@ var init_session = __esm({
|
|
|
9229
9412
|
|
|
9230
9413
|
// packages/server/src/fs/tree.ts
|
|
9231
9414
|
import { readdir as readdir3, stat as stat6 } from "fs/promises";
|
|
9232
|
-
import { join as
|
|
9415
|
+
import { join as join6, relative as relative4 } from "path";
|
|
9233
9416
|
async function readTree(rootPath, subdir) {
|
|
9234
|
-
const targetPath = subdir ?
|
|
9417
|
+
const targetPath = subdir ? join6(rootPath, subdir) : rootPath;
|
|
9235
9418
|
const filter = createGitignoreFilter(rootPath, targetPath);
|
|
9236
9419
|
const entries = await readdir3(targetPath, { withFileTypes: true });
|
|
9237
9420
|
const nodes = [];
|
|
@@ -9239,7 +9422,7 @@ async function readTree(rootPath, subdir) {
|
|
|
9239
9422
|
if (!filter(entry.name)) {
|
|
9240
9423
|
continue;
|
|
9241
9424
|
}
|
|
9242
|
-
const fullPath =
|
|
9425
|
+
const fullPath = join6(targetPath, entry.name);
|
|
9243
9426
|
const relPath = relative4(rootPath, fullPath);
|
|
9244
9427
|
if (entry.isDirectory()) {
|
|
9245
9428
|
nodes.push({
|
|
@@ -9283,7 +9466,7 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
9283
9466
|
const filteredEntries = entries.filter((entry) => filter(entry.name));
|
|
9284
9467
|
filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
9285
9468
|
for (const entry of filteredEntries) {
|
|
9286
|
-
const fullPath =
|
|
9469
|
+
const fullPath = join6(dirPath, entry.name);
|
|
9287
9470
|
const relPath = relative4(rootPath, fullPath);
|
|
9288
9471
|
if (entry.isDirectory()) {
|
|
9289
9472
|
await walk(fullPath);
|
|
@@ -9895,37 +10078,37 @@ var init_git2 = __esm({
|
|
|
9895
10078
|
});
|
|
9896
10079
|
|
|
9897
10080
|
// packages/server/src/config/config-io.ts
|
|
9898
|
-
import { existsSync as
|
|
10081
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
9899
10082
|
import { homedir as homedir3 } from "node:os";
|
|
9900
|
-
import { basename as basename2, dirname as
|
|
10083
|
+
import { basename as basename2, dirname as dirname4, join as join7 } from "node:path";
|
|
9901
10084
|
function resolveConfigPath(configType) {
|
|
9902
10085
|
if (configType === "codex") {
|
|
9903
10086
|
const testHome = process.env.CODER_STUDIO_CODEX_HOME;
|
|
9904
10087
|
if (testHome && testHome.trim()) {
|
|
9905
|
-
return
|
|
10088
|
+
return join7(testHome, "config.toml");
|
|
9906
10089
|
}
|
|
9907
10090
|
const codexHome = process.env.CODEX_HOME;
|
|
9908
10091
|
if (codexHome && codexHome.trim()) {
|
|
9909
|
-
return
|
|
10092
|
+
return join7(codexHome, "config.toml");
|
|
9910
10093
|
}
|
|
9911
|
-
return
|
|
10094
|
+
return join7(homedir3(), ".codex", "config.toml");
|
|
9912
10095
|
}
|
|
9913
10096
|
if (configType === "claude") {
|
|
9914
10097
|
const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
|
|
9915
10098
|
if (testHome && testHome.trim()) {
|
|
9916
|
-
return
|
|
10099
|
+
return join7(testHome, "settings.json");
|
|
9917
10100
|
}
|
|
9918
|
-
return
|
|
10101
|
+
return join7(homedir3(), ".claude", "settings.json");
|
|
9919
10102
|
}
|
|
9920
10103
|
throw new Error(`Unknown config type: ${configType}`);
|
|
9921
10104
|
}
|
|
9922
10105
|
function readConfigFile(configType) {
|
|
9923
10106
|
const configPath = resolveConfigPath(configType);
|
|
9924
|
-
if (!
|
|
10107
|
+
if (!existsSync6(configPath)) {
|
|
9925
10108
|
return { configPath, content: "", exists: false };
|
|
9926
10109
|
}
|
|
9927
10110
|
try {
|
|
9928
|
-
const content =
|
|
10111
|
+
const content = readFileSync6(configPath, "utf-8");
|
|
9929
10112
|
return { configPath, content, exists: true };
|
|
9930
10113
|
} catch {
|
|
9931
10114
|
return { configPath, content: "", exists: false };
|
|
@@ -9934,16 +10117,16 @@ function readConfigFile(configType) {
|
|
|
9934
10117
|
function writeConfigFile(configType, content) {
|
|
9935
10118
|
try {
|
|
9936
10119
|
const configPath = resolveConfigPath(configType);
|
|
9937
|
-
const parentDir =
|
|
9938
|
-
if (!
|
|
9939
|
-
|
|
10120
|
+
const parentDir = dirname4(configPath);
|
|
10121
|
+
if (!existsSync6(parentDir)) {
|
|
10122
|
+
mkdirSync3(parentDir, { recursive: true });
|
|
9940
10123
|
}
|
|
9941
10124
|
let backupPath = null;
|
|
9942
|
-
if (
|
|
10125
|
+
if (existsSync6(configPath)) {
|
|
9943
10126
|
backupPath = createBackup(configPath);
|
|
9944
10127
|
}
|
|
9945
10128
|
const tempPath = `${configPath}.tmp`;
|
|
9946
|
-
|
|
10129
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
9947
10130
|
renameSync(tempPath, configPath);
|
|
9948
10131
|
return { success: true, backupPath };
|
|
9949
10132
|
} catch (error) {
|
|
@@ -9955,13 +10138,13 @@ function writeConfigFile(configType, content) {
|
|
|
9955
10138
|
}
|
|
9956
10139
|
}
|
|
9957
10140
|
function createBackup(filePath) {
|
|
9958
|
-
const original =
|
|
10141
|
+
const original = readFileSync6(filePath, "utf-8");
|
|
9959
10142
|
const ext = filePath.split(".").pop() ?? "";
|
|
9960
10143
|
const base = basename2(filePath, `.${ext}`);
|
|
9961
|
-
const dir =
|
|
10144
|
+
const dir = dirname4(filePath);
|
|
9962
10145
|
const ts = formatTimestamp(/* @__PURE__ */ new Date());
|
|
9963
|
-
const backupPath =
|
|
9964
|
-
|
|
10146
|
+
const backupPath = join7(dir, `${base}.bak.${ts}.${ext}`);
|
|
10147
|
+
writeFileSync3(backupPath, original, "utf-8");
|
|
9965
10148
|
return backupPath;
|
|
9966
10149
|
}
|
|
9967
10150
|
function formatTimestamp(d) {
|
|
@@ -10665,6 +10848,7 @@ async function createServer(configOverrides) {
|
|
|
10665
10848
|
(err) => console.warn("[uploads] cascade cleanup failed", { wsId: workspaceId, err })
|
|
10666
10849
|
)
|
|
10667
10850
|
});
|
|
10851
|
+
workspaceMgr.hydrateWatchers();
|
|
10668
10852
|
const authSessionRepo = new AuthSessionRepo(db);
|
|
10669
10853
|
const authLoginBlockRepo = new AuthLoginBlockRepo(db);
|
|
10670
10854
|
const app = await buildFastifyApp({
|
|
@@ -10704,10 +10888,13 @@ async function createServer(configOverrides) {
|
|
|
10704
10888
|
});
|
|
10705
10889
|
await sessionMgr.hydrate();
|
|
10706
10890
|
await supervisorMgr.hydrate();
|
|
10707
|
-
const
|
|
10891
|
+
const providerMockOverrides = createE2EProviderMockOverrides();
|
|
10892
|
+
const providerRuntimeDeps = providerMockOverrides ? {
|
|
10893
|
+
commandExists: providerMockOverrides.commandExists
|
|
10894
|
+
} : {};
|
|
10708
10895
|
const providerInstallMgr = new ProviderInstallManager(providerRegistry, {
|
|
10709
10896
|
...providerRuntimeDeps,
|
|
10710
|
-
runCommand: runCommandAsString
|
|
10897
|
+
runCommand: providerMockOverrides?.runCommand ?? runCommandAsString
|
|
10711
10898
|
});
|
|
10712
10899
|
commandContext = {
|
|
10713
10900
|
workspaceMgr,
|
|
@@ -10877,6 +11064,7 @@ var init_server = __esm({
|
|
|
10877
11064
|
init_config();
|
|
10878
11065
|
init_auto_fetch();
|
|
10879
11066
|
init_command_runner();
|
|
11067
|
+
init_e2e_provider_mock();
|
|
10880
11068
|
init_install_manager();
|
|
10881
11069
|
init_manager();
|
|
10882
11070
|
init_db();
|
|
@@ -11183,20 +11371,20 @@ var init_src4 = __esm({
|
|
|
11183
11371
|
});
|
|
11184
11372
|
|
|
11185
11373
|
// packages/cli/src/cli.ts
|
|
11186
|
-
import { existsSync as
|
|
11187
|
-
import { dirname as
|
|
11374
|
+
import { existsSync as existsSync11 } from "fs";
|
|
11375
|
+
import { dirname as dirname6, join as join10 } from "path";
|
|
11188
11376
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
11189
11377
|
|
|
11190
11378
|
// packages/cli/src/auth-control.ts
|
|
11191
11379
|
await init_src4();
|
|
11192
11380
|
|
|
11193
11381
|
// packages/cli/src/config-store.ts
|
|
11194
|
-
import { existsSync as
|
|
11382
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
11195
11383
|
import { homedir as homedir4 } from "os";
|
|
11196
|
-
import { basename as basename3, join as
|
|
11384
|
+
import { basename as basename3, join as join8 } from "path";
|
|
11197
11385
|
var DEFAULT_DB_FILE = "coder-studio.db";
|
|
11198
11386
|
function getCliConfigPath() {
|
|
11199
|
-
return
|
|
11387
|
+
return join8(homedir4(), ".coder-studio", "config.json");
|
|
11200
11388
|
}
|
|
11201
11389
|
function normalizeDataDir(input2) {
|
|
11202
11390
|
if (input2.endsWith(".db")) {
|
|
@@ -11205,15 +11393,15 @@ function normalizeDataDir(input2) {
|
|
|
11205
11393
|
if (basename3(input2).includes(".")) {
|
|
11206
11394
|
return input2;
|
|
11207
11395
|
}
|
|
11208
|
-
return
|
|
11396
|
+
return join8(input2, DEFAULT_DB_FILE);
|
|
11209
11397
|
}
|
|
11210
11398
|
function readCliConfig() {
|
|
11211
11399
|
const path10 = getCliConfigPath();
|
|
11212
|
-
if (!
|
|
11400
|
+
if (!existsSync7(path10)) {
|
|
11213
11401
|
return null;
|
|
11214
11402
|
}
|
|
11215
11403
|
try {
|
|
11216
|
-
const parsed = JSON.parse(
|
|
11404
|
+
const parsed = JSON.parse(readFileSync7(path10, "utf-8"));
|
|
11217
11405
|
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") {
|
|
11218
11406
|
return null;
|
|
11219
11407
|
}
|
|
@@ -11224,17 +11412,17 @@ function readCliConfig() {
|
|
|
11224
11412
|
}
|
|
11225
11413
|
function writeCliConfig(config) {
|
|
11226
11414
|
const path10 = getCliConfigPath();
|
|
11227
|
-
const dir =
|
|
11415
|
+
const dir = join8(homedir4(), ".coder-studio");
|
|
11228
11416
|
const normalizedConfig = {
|
|
11229
11417
|
...config.host !== void 0 ? { host: config.host } : {},
|
|
11230
11418
|
...config.port !== void 0 && config.port > 0 ? { port: config.port } : {},
|
|
11231
11419
|
...config.dataDir !== void 0 ? { dataDir: normalizeDataDir(config.dataDir) } : {},
|
|
11232
11420
|
...config.password !== void 0 ? { password: config.password } : {}
|
|
11233
11421
|
};
|
|
11234
|
-
if (!
|
|
11235
|
-
|
|
11422
|
+
if (!existsSync7(dir)) {
|
|
11423
|
+
mkdirSync4(dir, { recursive: true });
|
|
11236
11424
|
}
|
|
11237
|
-
|
|
11425
|
+
writeFileSync4(path10, JSON.stringify(normalizedConfig, null, 2), "utf-8");
|
|
11238
11426
|
}
|
|
11239
11427
|
|
|
11240
11428
|
// packages/cli/src/auth-control.ts
|
|
@@ -11298,12 +11486,12 @@ async function openBrowser(url) {
|
|
|
11298
11486
|
}
|
|
11299
11487
|
|
|
11300
11488
|
// packages/cli/src/log-excerpt.ts
|
|
11301
|
-
import { closeSync, existsSync as
|
|
11489
|
+
import { closeSync, existsSync as existsSync8, openSync, readSync, statSync as statSync2 } from "fs";
|
|
11302
11490
|
var DEFAULT_MAX_LINES = 40;
|
|
11303
11491
|
var DEFAULT_MAX_CHARS = 4e3;
|
|
11304
11492
|
var DEFAULT_MAX_BYTES = 16 * 1024;
|
|
11305
11493
|
var getFileSize = (path10) => {
|
|
11306
|
-
if (!
|
|
11494
|
+
if (!existsSync8(path10)) {
|
|
11307
11495
|
return 0;
|
|
11308
11496
|
}
|
|
11309
11497
|
try {
|
|
@@ -11318,7 +11506,7 @@ var readLogExcerpt = (path10, {
|
|
|
11318
11506
|
maxLines = DEFAULT_MAX_LINES,
|
|
11319
11507
|
maxChars = DEFAULT_MAX_CHARS
|
|
11320
11508
|
} = {}) => {
|
|
11321
|
-
if (!
|
|
11509
|
+
if (!existsSync8(path10)) {
|
|
11322
11510
|
return null;
|
|
11323
11511
|
}
|
|
11324
11512
|
const fileSize = getFileSize(path10);
|
|
@@ -11397,12 +11585,12 @@ function assertSupportedNodeVersion(version = process.versions.node) {
|
|
|
11397
11585
|
}
|
|
11398
11586
|
|
|
11399
11587
|
// packages/cli/src/package-manifest.ts
|
|
11400
|
-
import { existsSync as
|
|
11588
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
|
|
11401
11589
|
function resolveCliPackageManifestUrl(importMetaUrl) {
|
|
11402
11590
|
const manifestUrl = [
|
|
11403
11591
|
new URL("../package.json", importMetaUrl),
|
|
11404
11592
|
new URL("../../package.json", importMetaUrl)
|
|
11405
|
-
].find((candidate) =>
|
|
11593
|
+
].find((candidate) => existsSync9(candidate));
|
|
11406
11594
|
if (!manifestUrl) {
|
|
11407
11595
|
throw new Error("Unable to locate CLI package.json");
|
|
11408
11596
|
}
|
|
@@ -11410,7 +11598,7 @@ function resolveCliPackageManifestUrl(importMetaUrl) {
|
|
|
11410
11598
|
}
|
|
11411
11599
|
function getCliPackageManifest(importMetaUrl) {
|
|
11412
11600
|
return JSON.parse(
|
|
11413
|
-
|
|
11601
|
+
readFileSync8(resolveCliPackageManifestUrl(importMetaUrl), "utf-8")
|
|
11414
11602
|
);
|
|
11415
11603
|
}
|
|
11416
11604
|
function getCliVersion(importMetaUrl) {
|
|
@@ -11619,9 +11807,9 @@ function parseArgs(argv) {
|
|
|
11619
11807
|
|
|
11620
11808
|
// packages/cli/src/pm2-control.ts
|
|
11621
11809
|
init_runtime();
|
|
11622
|
-
import { mkdirSync as
|
|
11810
|
+
import { mkdirSync as mkdirSync5 } from "fs";
|
|
11623
11811
|
import { homedir as homedir5 } from "os";
|
|
11624
|
-
import { join as
|
|
11812
|
+
import { join as join9 } from "path";
|
|
11625
11813
|
var MANAGED_SERVER_NAME = "coder-studio-server";
|
|
11626
11814
|
var PM2_RESTART_DELAY_MS = 2e3;
|
|
11627
11815
|
var PM2_MIN_UPTIME = "5s";
|
|
@@ -11812,11 +12000,11 @@ var deleteManagedServerInSession = async (pm2, {
|
|
|
11812
12000
|
return true;
|
|
11813
12001
|
};
|
|
11814
12002
|
var ensureLogDirectory = () => {
|
|
11815
|
-
|
|
12003
|
+
mkdirSync5(join9(homedir5(), ".coder-studio", "logs"), { recursive: true });
|
|
11816
12004
|
};
|
|
11817
12005
|
var getLogPaths = () => ({
|
|
11818
|
-
outFile:
|
|
11819
|
-
errFile:
|
|
12006
|
+
outFile: join9(homedir5(), ".coder-studio", "logs", "server.out.log"),
|
|
12007
|
+
errFile: join9(homedir5(), ".coder-studio", "logs", "server.err.log")
|
|
11820
12008
|
});
|
|
11821
12009
|
var captureStartupLogOffsets = () => {
|
|
11822
12010
|
const { outFile, errFile } = getLogPaths();
|
|
@@ -12002,17 +12190,17 @@ async function getServerStatus() {
|
|
|
12002
12190
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12003
12191
|
|
|
12004
12192
|
// packages/cli/src/embed.ts
|
|
12005
|
-
import { existsSync as
|
|
12006
|
-
import { dirname as
|
|
12193
|
+
import { existsSync as existsSync10 } from "fs";
|
|
12194
|
+
import { dirname as dirname5, resolve as resolve3 } from "path";
|
|
12007
12195
|
import { fileURLToPath } from "url";
|
|
12008
12196
|
var __filename = fileURLToPath(import.meta.url);
|
|
12009
|
-
var __dirname =
|
|
12197
|
+
var __dirname = dirname5(__filename);
|
|
12010
12198
|
var WEB_ASSETS_DIR = resolve3(__dirname, "../web");
|
|
12011
12199
|
function getStaticAssetsDir() {
|
|
12012
12200
|
return WEB_ASSETS_DIR;
|
|
12013
12201
|
}
|
|
12014
12202
|
function hasWebAssets() {
|
|
12015
|
-
return
|
|
12203
|
+
return existsSync10(WEB_ASSETS_DIR);
|
|
12016
12204
|
}
|
|
12017
12205
|
|
|
12018
12206
|
// packages/cli/src/server-runner.ts
|
|
@@ -12214,13 +12402,13 @@ function formatAuthBlocks(blocks) {
|
|
|
12214
12402
|
}
|
|
12215
12403
|
function resolveManagedScriptPath() {
|
|
12216
12404
|
const currentFile = fileURLToPath3(import.meta.url);
|
|
12217
|
-
const currentDir =
|
|
12405
|
+
const currentDir = dirname6(currentFile);
|
|
12218
12406
|
const candidates = [
|
|
12219
|
-
|
|
12220
|
-
|
|
12221
|
-
|
|
12407
|
+
join10(currentDir, "server-runner.js"),
|
|
12408
|
+
join10(currentDir, "server-runner.mjs"),
|
|
12409
|
+
join10(currentDir, "../src/server-runner.ts")
|
|
12222
12410
|
];
|
|
12223
|
-
const scriptPath = candidates.find((candidate) =>
|
|
12411
|
+
const scriptPath = candidates.find((candidate) => existsSync11(candidate));
|
|
12224
12412
|
if (!scriptPath) {
|
|
12225
12413
|
throw new Error("Unable to locate the managed server entry script");
|
|
12226
12414
|
}
|