@spencer-kit/coder-studio 0.4.2 → 0.4.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 +16 -0
- package/dist/esm/bin.mjs +460 -91
- package/dist/esm/bin.mjs.map +4 -4
- package/dist/esm/server-runner.mjs +406 -67
- package/dist/esm/server-runner.mjs.map +4 -4
- package/dist/esm/update-worker.mjs +145 -6
- package/dist/esm/update-worker.mjs.map +2 -2
- package/dist/web/assets/components-C4SKshs2.js +110 -0
- package/dist/web/assets/components-C4SKshs2.js.map +1 -0
- package/dist/web/assets/{components-AKM1pxhf.css → components-CMahvybm.css} +1 -1
- package/dist/web/assets/{main-D3dXqSaA.js → main-CZuF2VZA.js} +2 -2
- package/dist/web/assets/{main-D3dXqSaA.js.map → main-CZuF2VZA.js.map} +1 -1
- package/dist/web/assets/{ui-preview-BGZz053-.js → ui-preview-DCeC0YmD.js} +3 -3
- package/dist/web/assets/{ui-preview-BGZz053-.js.map → ui-preview-DCeC0YmD.js.map} +1 -1
- package/dist/web/index.html +3 -3
- package/dist/web/ui-preview.html +3 -3
- package/package.json +1 -1
- package/src/pm2-control.test.ts +48 -6
- package/src/pm2-control.ts +43 -2
- package/src/update-worker.test.ts +113 -12
- package/src/update-worker.ts +195 -7
- package/dist/web/assets/components-omWbMLvf.js +0 -110
- package/dist/web/assets/components-omWbMLvf.js.map +0 -1
package/dist/esm/bin.mjs
CHANGED
|
@@ -953,10 +953,10 @@ function resolveSpawnArgv(argv, deps = {}) {
|
|
|
953
953
|
}
|
|
954
954
|
const restArgs = argv.slice(1);
|
|
955
955
|
const readFileSync10 = deps.readFileSync ?? ((file) => fs2.readFileSync(file, "utf8"));
|
|
956
|
-
const
|
|
956
|
+
const existsSync16 = deps.existsSync ?? fs2.existsSync;
|
|
957
957
|
const pathEnv = deps.pathEnv ?? process.env.Path ?? process.env.PATH ?? "";
|
|
958
958
|
const pathExt = deps.pathExt ?? process.env.PATHEXT ?? DEFAULT_PATHEXT;
|
|
959
|
-
const resolved = resolveExecutablePath(command, pathEnv, pathExt,
|
|
959
|
+
const resolved = resolveExecutablePath(command, pathEnv, pathExt, existsSync16);
|
|
960
960
|
if (!resolved) {
|
|
961
961
|
return [...argv];
|
|
962
962
|
}
|
|
@@ -1005,17 +1005,17 @@ function expandShimVars(value, dp0Dir) {
|
|
|
1005
1005
|
function parsePathExt(pathExt) {
|
|
1006
1006
|
return pathExt.split(";").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
|
|
1007
1007
|
}
|
|
1008
|
-
function resolveExecutablePath(command, pathEnv, pathExt,
|
|
1008
|
+
function resolveExecutablePath(command, pathEnv, pathExt, existsSync16) {
|
|
1009
1009
|
const hasExt = path3.win32.extname(command).length > 0;
|
|
1010
1010
|
const extensions = parsePathExt(pathExt);
|
|
1011
1011
|
if (path3.win32.isAbsolute(command)) {
|
|
1012
|
-
if (
|
|
1012
|
+
if (existsSync16(command)) {
|
|
1013
1013
|
return command;
|
|
1014
1014
|
}
|
|
1015
1015
|
if (!hasExt) {
|
|
1016
1016
|
for (const ext of extensions) {
|
|
1017
1017
|
const candidate = command + ext;
|
|
1018
|
-
if (
|
|
1018
|
+
if (existsSync16(candidate)) {
|
|
1019
1019
|
return candidate;
|
|
1020
1020
|
}
|
|
1021
1021
|
}
|
|
@@ -1026,14 +1026,14 @@ function resolveExecutablePath(command, pathEnv, pathExt, existsSync15) {
|
|
|
1026
1026
|
for (const dir of dirs) {
|
|
1027
1027
|
if (hasExt) {
|
|
1028
1028
|
const candidate = path3.win32.join(dir, command);
|
|
1029
|
-
if (
|
|
1029
|
+
if (existsSync16(candidate)) {
|
|
1030
1030
|
return candidate;
|
|
1031
1031
|
}
|
|
1032
1032
|
continue;
|
|
1033
1033
|
}
|
|
1034
1034
|
for (const ext of extensions) {
|
|
1035
1035
|
const candidate = path3.win32.join(dir, command + ext);
|
|
1036
|
-
if (
|
|
1036
|
+
if (existsSync16(candidate)) {
|
|
1037
1037
|
return candidate;
|
|
1038
1038
|
}
|
|
1039
1039
|
}
|
|
@@ -2554,12 +2554,12 @@ async function ensureSafeUploadDir(rootDir, targetDir2) {
|
|
|
2554
2554
|
await mkdir3(resolvedRoot, { recursive: true });
|
|
2555
2555
|
await assertDirectorySegmentSafe(resolvedRoot);
|
|
2556
2556
|
}
|
|
2557
|
-
const
|
|
2558
|
-
if (!
|
|
2557
|
+
const relative4 = path7.relative(resolvedRoot, resolvedTarget);
|
|
2558
|
+
if (!relative4) {
|
|
2559
2559
|
return;
|
|
2560
2560
|
}
|
|
2561
2561
|
let current = resolvedRoot;
|
|
2562
|
-
for (const segment of
|
|
2562
|
+
for (const segment of relative4.split(path7.sep)) {
|
|
2563
2563
|
current = path7.join(current, segment);
|
|
2564
2564
|
try {
|
|
2565
2565
|
await assertDirectorySegmentSafe(current);
|
|
@@ -8077,7 +8077,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
8077
8077
|
const arch = deps.arch ?? process.arch;
|
|
8078
8078
|
const resolve4 = deps.resolve ?? ((id) => require4.resolve(id));
|
|
8079
8079
|
const fileExists = deps.existsSync ?? existsSync6;
|
|
8080
|
-
const
|
|
8080
|
+
const stat10 = deps.statSync ?? statSync;
|
|
8081
8081
|
const chmod = deps.chmodSync ?? chmodSync2;
|
|
8082
8082
|
let packageJsonPath;
|
|
8083
8083
|
try {
|
|
@@ -8095,7 +8095,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
8095
8095
|
if (!fileExists(helperPath)) {
|
|
8096
8096
|
return;
|
|
8097
8097
|
}
|
|
8098
|
-
const currentMode =
|
|
8098
|
+
const currentMode = stat10(helperPath).mode;
|
|
8099
8099
|
const executableMode = currentMode | 73;
|
|
8100
8100
|
if (executableMode === currentMode) {
|
|
8101
8101
|
return;
|
|
@@ -8301,13 +8301,19 @@ import { spawn as spawn3 } from "node:child_process";
|
|
|
8301
8301
|
function buildPrompt(context, mode) {
|
|
8302
8302
|
if (mode === "decompose") {
|
|
8303
8303
|
return [
|
|
8304
|
-
"You are an autonomous supervisor for
|
|
8304
|
+
"You are an autonomous planner-supervisor for this target-scoped software task.",
|
|
8305
|
+
"Your purpose is to drive the work from objective to high-quality delivery with minimal babysitting.",
|
|
8306
|
+
'Do not optimize for merely reaching "done"; optimize for a result that is correct, verified, coherent, and not obviously low-quality or rushed.',
|
|
8305
8307
|
"Your first job is to decompose the target into a supervision structure before evaluation begins.",
|
|
8306
8308
|
"",
|
|
8307
8309
|
"Return JSON only.",
|
|
8308
8310
|
"No prose before or after the JSON.",
|
|
8309
8311
|
"",
|
|
8310
8312
|
"Decomposition policy:",
|
|
8313
|
+
"- Create an execution plan, not just a task list.",
|
|
8314
|
+
"- Break the objective into the smallest reasonable set of milestones that maximize clarity, reduce uncertainty, and preserve steady forward progress.",
|
|
8315
|
+
"- Order milestones by dependency, risk reduction, and delivery leverage.",
|
|
8316
|
+
"- Prefer a plan structure that makes execution easier, verification clearer, and replanning cheaper.",
|
|
8311
8317
|
"- Do not ask the user any questions.",
|
|
8312
8318
|
"- Do not ask for clarification, confirmation, or approval.",
|
|
8313
8319
|
"- Do not propose options for the user to choose from.",
|
|
@@ -8321,6 +8327,30 @@ function buildPrompt(context, mode) {
|
|
|
8321
8327
|
"- Each item must be concrete, milestone-sized, and useful for subsequent evaluation.",
|
|
8322
8328
|
"- Do not leave the structure empty.",
|
|
8323
8329
|
"",
|
|
8330
|
+
"Decomposition principles:",
|
|
8331
|
+
"- Prefer milestones that produce a concrete artifact, observable behavior change, test result, or verification result.",
|
|
8332
|
+
"- Make dependencies explicit.",
|
|
8333
|
+
"- Separate implementation, verification, integration, and cleanup when that improves delivery reliability.",
|
|
8334
|
+
"- If a step is too vague to verify independently, split it further.",
|
|
8335
|
+
"- Prefer plans that keep the agent moving with minimal ambiguity between milestones.",
|
|
8336
|
+
"- Use stage-based planning by default unless there are clearly independent deliverables that justify subtargets.",
|
|
8337
|
+
"- Build the plan so it can recover from failed attempts: prefer decompositions that allow narrowing scope, isolating failures, checking assumptions, and restoring a working baseline when needed.",
|
|
8338
|
+
"- Keep the decomposition practical for execution, not merely neat on paper.",
|
|
8339
|
+
"",
|
|
8340
|
+
"Planning quality bar:",
|
|
8341
|
+
"- Prefer fewer, stronger milestones over many thin or vague ones.",
|
|
8342
|
+
"- Every item should imply a concrete deliverable and observable acceptance criteria.",
|
|
8343
|
+
'- Avoid vague items such as "improve", "clean up", or "refactor" unless tied to a specific delivery or verification target.',
|
|
8344
|
+
"- Include quality and verification checkpoints where they materially improve the final result.",
|
|
8345
|
+
"- Do not decompose in a way that encourages superficial completion.",
|
|
8346
|
+
"",
|
|
8347
|
+
"Planning boundary:",
|
|
8348
|
+
"- You are responsible for execution structure, sequencing, quality control, and verification structure.",
|
|
8349
|
+
"- Do not hard-code unnecessary implementation detail too early.",
|
|
8350
|
+
"- If multiple implementation paths exist, prefer a plan that keeps execution adaptable until evidence makes one path clearly better.",
|
|
8351
|
+
"- Do not hide assumptions inside the plan.",
|
|
8352
|
+
"- Do not create a brittle plan that depends on perfect execution.",
|
|
8353
|
+
"",
|
|
8324
8354
|
"Item requirements:",
|
|
8325
8355
|
'- Each item must include "id", "kind", "title", "objective", "deliverable", "acceptanceCriteria", and "status".',
|
|
8326
8356
|
'- "kind" must match the selected decompositionMode: all "stage" or all "subtarget".',
|
|
@@ -8353,8 +8383,13 @@ function buildPrompt(context, mode) {
|
|
|
8353
8383
|
].join("\n");
|
|
8354
8384
|
}
|
|
8355
8385
|
const lines = [
|
|
8356
|
-
"You are an autonomous supervisor for
|
|
8357
|
-
"Your
|
|
8386
|
+
"You are an autonomous planner-supervisor for this target-scoped software task.",
|
|
8387
|
+
"Your purpose is to drive the work from objective to high-quality delivery with minimal babysitting.",
|
|
8388
|
+
'Do not optimize for merely reaching "done"; optimize for a result that is correct, verified, coherent, and not obviously low-quality or rushed.',
|
|
8389
|
+
"Act as an autonomous execution supervisor.",
|
|
8390
|
+
"Your job is to keep the agent moving toward the objective, maintain delivery quality, detect low-yield paths early, and redirect work when needed.",
|
|
8391
|
+
"Do not passively observe progress; actively steer it toward successful, high-quality completion.",
|
|
8392
|
+
"Drive execution through the supervised agent rather than by independently performing the work yourself.",
|
|
8358
8393
|
"",
|
|
8359
8394
|
"Return JSON only.",
|
|
8360
8395
|
"No prose before or after the JSON.",
|
|
@@ -8385,7 +8420,12 @@ function buildPrompt(context, mode) {
|
|
|
8385
8420
|
'- When advancing to the next item, mark the previous item as "done" and set activeItemId to the next item explicitly.',
|
|
8386
8421
|
"- If the active item is blocked, give guidance that is most likely to unblock it.",
|
|
8387
8422
|
"- If the active item is obsolete, explain the reason briefly and move to the next useful item.",
|
|
8388
|
-
"- If the
|
|
8423
|
+
"- If the current path is low-yield, brittle, repetitive, or producing low-quality output, redirect early.",
|
|
8424
|
+
"- Diagnose stalls precisely: implementation failure, verification failure, environment failure, scope misframing, weak solution quality, or missing evidence.",
|
|
8425
|
+
"- Choose the next action that most improves objective-level progress, not merely the most local continuation.",
|
|
8426
|
+
"- Do not repeat the same tactic after failure unless new evidence justifies retrying it.",
|
|
8427
|
+
"- Maintain commitment to the objective, not blind commitment to the current tactic.",
|
|
8428
|
+
"- Replan locally when needed, but keep the overall execution coherent and objective-driven.",
|
|
8389
8429
|
"- Do not rewrite the decomposition structure during normal evaluation cycles.",
|
|
8390
8430
|
"",
|
|
8391
8431
|
"Allowed statuses:",
|
|
@@ -8410,6 +8450,21 @@ function buildPrompt(context, mode) {
|
|
|
8410
8450
|
"- If implementation is needed, point to the likely area, behavior, or file/module based on available evidence.",
|
|
8411
8451
|
"- If the agent asked a question, answer it directly in the guidance and continue with a concrete next action.",
|
|
8412
8452
|
"",
|
|
8453
|
+
"Delivery quality bar:",
|
|
8454
|
+
"- Do not accept shallow, brittle, or obviously rushed solutions.",
|
|
8455
|
+
"- Do not optimize for the smallest change if it leads to poor maintainability, weak verification, or fragile behavior.",
|
|
8456
|
+
"- Prefer solutions that are robust, coherent with the existing codebase, and likely to hold up beyond the happy path.",
|
|
8457
|
+
"- Require appropriate verification for the kind of work being done.",
|
|
8458
|
+
"- Consider edge cases, integration impact, regressions, and maintainability where relevant.",
|
|
8459
|
+
"- If a solution technically works but is low-quality, incomplete, poorly verified, or obviously a shortcut, treat the milestone as not yet complete.",
|
|
8460
|
+
"- Do not let superficial progress masquerade as real delivery.",
|
|
8461
|
+
"",
|
|
8462
|
+
"Completion standard:",
|
|
8463
|
+
"- A milestone is complete only when its deliverable and acceptanceCriteria are supported by observable evidence and the result meets a reasonable quality bar.",
|
|
8464
|
+
"- The objective is complete only when the final result is implemented, verified, and not obviously compromised in quality.",
|
|
8465
|
+
"- Do not mark work complete merely because code was changed, a command passed once, or a minimal patch exists.",
|
|
8466
|
+
"- Optimize for finished, verified, and defensible delivery.",
|
|
8467
|
+
"",
|
|
8413
8468
|
"Evaluation policy:",
|
|
8414
8469
|
"- Update progress incrementally against the existing decomposition.",
|
|
8415
8470
|
"- Use itemUpdates to reflect evidence-backed status changes only.",
|
|
@@ -14894,20 +14949,260 @@ var init_session2 = __esm({
|
|
|
14894
14949
|
}
|
|
14895
14950
|
});
|
|
14896
14951
|
|
|
14952
|
+
// packages/server/src/fs/content-search.ts
|
|
14953
|
+
import { spawn as spawn5 } from "child_process";
|
|
14954
|
+
import { existsSync as existsSync8 } from "fs";
|
|
14955
|
+
import { readdir as readdir4, readFile as readFile4, stat as stat8 } from "fs/promises";
|
|
14956
|
+
import { basename as basename2, join as join10, relative as relative2 } from "path";
|
|
14957
|
+
import { createInterface } from "readline";
|
|
14958
|
+
async function searchFileContents(rootPath, options) {
|
|
14959
|
+
const query = options.query.trim();
|
|
14960
|
+
if (!query) {
|
|
14961
|
+
return {
|
|
14962
|
+
files: [],
|
|
14963
|
+
totalMatchCount: 0,
|
|
14964
|
+
hasMoreFiles: false,
|
|
14965
|
+
truncatedMatchFileCount: 0
|
|
14966
|
+
};
|
|
14967
|
+
}
|
|
14968
|
+
const result = await searchWithRipgrep(rootPath, query, options.maxFiles).catch(
|
|
14969
|
+
async (error) => {
|
|
14970
|
+
if (error.code === "ENOENT") {
|
|
14971
|
+
return searchWithNode(rootPath, query, options.maxFiles);
|
|
14972
|
+
}
|
|
14973
|
+
throw error;
|
|
14974
|
+
}
|
|
14975
|
+
);
|
|
14976
|
+
return finalizeResults(result, options.maxFiles, options.maxMatchesPerFile);
|
|
14977
|
+
}
|
|
14978
|
+
async function searchWithRipgrep(rootPath, query, maxFiles) {
|
|
14979
|
+
const hasGitignore = existsSync8(join10(rootPath, ".gitignore"));
|
|
14980
|
+
const args = [
|
|
14981
|
+
"--json",
|
|
14982
|
+
"--line-number",
|
|
14983
|
+
"--column",
|
|
14984
|
+
"--fixed-strings",
|
|
14985
|
+
"--sort",
|
|
14986
|
+
"path",
|
|
14987
|
+
"--with-filename",
|
|
14988
|
+
"--glob",
|
|
14989
|
+
"!**/.git/**",
|
|
14990
|
+
"--glob",
|
|
14991
|
+
"!**/node_modules/**"
|
|
14992
|
+
];
|
|
14993
|
+
if (hasGitignore) {
|
|
14994
|
+
args.push("--hidden");
|
|
14995
|
+
args.push("--no-require-git");
|
|
14996
|
+
}
|
|
14997
|
+
args.push(query, ".");
|
|
14998
|
+
return new Promise((resolve4, reject) => {
|
|
14999
|
+
const child = spawn5("rg", args, { cwd: rootPath, stdio: ["ignore", "pipe", "pipe"] });
|
|
15000
|
+
const stdout = createInterface({ input: child.stdout });
|
|
15001
|
+
const files = /* @__PURE__ */ new Map();
|
|
15002
|
+
let totalMatchCount = 0;
|
|
15003
|
+
let hasMoreFiles = false;
|
|
15004
|
+
let stderr = "";
|
|
15005
|
+
stdout.on("line", (line) => {
|
|
15006
|
+
if (!line.trim()) {
|
|
15007
|
+
return;
|
|
15008
|
+
}
|
|
15009
|
+
const event = JSON.parse(line);
|
|
15010
|
+
if (event.type !== "match") {
|
|
15011
|
+
return;
|
|
15012
|
+
}
|
|
15013
|
+
const rawPath = event.data?.path?.text;
|
|
15014
|
+
if (!rawPath) {
|
|
15015
|
+
return;
|
|
15016
|
+
}
|
|
15017
|
+
const relativePath = normalizeRelativePath(relative2(rootPath, join10(rootPath, rawPath)));
|
|
15018
|
+
const preview = (event.data?.lines?.text ?? "").replace(/\r?\n$/, "");
|
|
15019
|
+
const lineNumber = event.data?.line_number ?? 1;
|
|
15020
|
+
const submatches = event.data?.submatches ?? [];
|
|
15021
|
+
totalMatchCount += submatches.length;
|
|
15022
|
+
if (!files.has(relativePath) && files.size >= maxFiles) {
|
|
15023
|
+
hasMoreFiles = true;
|
|
15024
|
+
return;
|
|
15025
|
+
}
|
|
15026
|
+
for (const submatch of submatches) {
|
|
15027
|
+
pushMatch(files, relativePath, {
|
|
15028
|
+
line: lineNumber,
|
|
15029
|
+
column: byteOffsetToColumn(preview, submatch.start),
|
|
15030
|
+
endColumn: byteOffsetToColumn(preview, submatch.end),
|
|
15031
|
+
preview,
|
|
15032
|
+
previewColumnStart: byteOffsetToColumn(preview, submatch.start),
|
|
15033
|
+
previewColumnEnd: byteOffsetToColumn(preview, submatch.end)
|
|
15034
|
+
});
|
|
15035
|
+
}
|
|
15036
|
+
});
|
|
15037
|
+
child.stderr.on("data", (chunk) => {
|
|
15038
|
+
stderr += chunk.toString();
|
|
15039
|
+
});
|
|
15040
|
+
child.on("error", (error) => {
|
|
15041
|
+
void stdout.close();
|
|
15042
|
+
reject(error);
|
|
15043
|
+
});
|
|
15044
|
+
child.on("close", (code) => {
|
|
15045
|
+
void stdout.close();
|
|
15046
|
+
if (code === 0 || code === 1) {
|
|
15047
|
+
resolve4({
|
|
15048
|
+
files: sortAccumulators(files),
|
|
15049
|
+
totalMatchCount,
|
|
15050
|
+
hasMoreFiles
|
|
15051
|
+
});
|
|
15052
|
+
return;
|
|
15053
|
+
}
|
|
15054
|
+
reject(
|
|
15055
|
+
Object.assign(new Error(stderr || `rg exited with code ${code ?? "unknown"}`), { code })
|
|
15056
|
+
);
|
|
15057
|
+
});
|
|
15058
|
+
});
|
|
15059
|
+
}
|
|
15060
|
+
async function searchWithNode(rootPath, query, maxFiles) {
|
|
15061
|
+
const files = /* @__PURE__ */ new Map();
|
|
15062
|
+
let totalMatchCount = 0;
|
|
15063
|
+
let hasMoreFiles = false;
|
|
15064
|
+
async function walk(dirPath) {
|
|
15065
|
+
const filter = createGitignoreFilter(rootPath, dirPath);
|
|
15066
|
+
const entries = await readdir4(dirPath, { withFileTypes: true });
|
|
15067
|
+
const filteredEntries = entries.filter((entry) => filter(entry.name));
|
|
15068
|
+
filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
15069
|
+
for (const entry of filteredEntries) {
|
|
15070
|
+
const fullPath = join10(dirPath, entry.name);
|
|
15071
|
+
if (entry.isDirectory()) {
|
|
15072
|
+
await walk(fullPath);
|
|
15073
|
+
continue;
|
|
15074
|
+
}
|
|
15075
|
+
if (!entry.isFile()) {
|
|
15076
|
+
continue;
|
|
15077
|
+
}
|
|
15078
|
+
const fileStat = await stat8(fullPath);
|
|
15079
|
+
if (fileStat.size > FALLBACK_MAX_FILE_BYTES) {
|
|
15080
|
+
continue;
|
|
15081
|
+
}
|
|
15082
|
+
const buffer = await readFile4(fullPath);
|
|
15083
|
+
if (isBinaryFile(buffer)) {
|
|
15084
|
+
continue;
|
|
15085
|
+
}
|
|
15086
|
+
const relativePath = normalizeRelativePath(relative2(rootPath, fullPath));
|
|
15087
|
+
const file = collectMatchesFromText(relativePath, buffer.toString("utf-8"), query);
|
|
15088
|
+
if (!file) {
|
|
15089
|
+
continue;
|
|
15090
|
+
}
|
|
15091
|
+
totalMatchCount += file.matchCount;
|
|
15092
|
+
if (files.size >= maxFiles) {
|
|
15093
|
+
hasMoreFiles = true;
|
|
15094
|
+
continue;
|
|
15095
|
+
}
|
|
15096
|
+
files.set(relativePath, file);
|
|
15097
|
+
}
|
|
15098
|
+
}
|
|
15099
|
+
await walk(rootPath);
|
|
15100
|
+
return {
|
|
15101
|
+
files: sortAccumulators(files),
|
|
15102
|
+
totalMatchCount,
|
|
15103
|
+
hasMoreFiles
|
|
15104
|
+
};
|
|
15105
|
+
}
|
|
15106
|
+
function collectMatchesFromText(relativePath, content, query) {
|
|
15107
|
+
const file = {
|
|
15108
|
+
path: relativePath,
|
|
15109
|
+
name: basename2(relativePath),
|
|
15110
|
+
matches: [],
|
|
15111
|
+
matchCount: 0
|
|
15112
|
+
};
|
|
15113
|
+
const lines = content.split(/\r?\n/);
|
|
15114
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
15115
|
+
const preview = lines[lineIndex] ?? "";
|
|
15116
|
+
if (!preview) {
|
|
15117
|
+
continue;
|
|
15118
|
+
}
|
|
15119
|
+
let fromIndex = 0;
|
|
15120
|
+
while (fromIndex <= preview.length) {
|
|
15121
|
+
const matchIndex = preview.indexOf(query, fromIndex);
|
|
15122
|
+
if (matchIndex === -1) {
|
|
15123
|
+
break;
|
|
15124
|
+
}
|
|
15125
|
+
const startColumn = matchIndex + 1;
|
|
15126
|
+
const endColumn = startColumn + query.length;
|
|
15127
|
+
file.matches.push({
|
|
15128
|
+
line: lineIndex + 1,
|
|
15129
|
+
column: startColumn,
|
|
15130
|
+
endColumn,
|
|
15131
|
+
preview,
|
|
15132
|
+
previewColumnStart: startColumn,
|
|
15133
|
+
previewColumnEnd: endColumn
|
|
15134
|
+
});
|
|
15135
|
+
file.matchCount += 1;
|
|
15136
|
+
fromIndex = matchIndex + Math.max(query.length, 1);
|
|
15137
|
+
}
|
|
15138
|
+
}
|
|
15139
|
+
return file.matchCount > 0 ? file : null;
|
|
15140
|
+
}
|
|
15141
|
+
function pushMatch(files, relativePath, match) {
|
|
15142
|
+
let file = files.get(relativePath);
|
|
15143
|
+
if (!file) {
|
|
15144
|
+
file = {
|
|
15145
|
+
path: relativePath,
|
|
15146
|
+
name: basename2(relativePath),
|
|
15147
|
+
matches: [],
|
|
15148
|
+
matchCount: 0
|
|
15149
|
+
};
|
|
15150
|
+
files.set(relativePath, file);
|
|
15151
|
+
}
|
|
15152
|
+
file.matches.push(match);
|
|
15153
|
+
file.matchCount += 1;
|
|
15154
|
+
}
|
|
15155
|
+
function sortAccumulators(files) {
|
|
15156
|
+
return Array.from(files.values()).sort((a, b) => a.path.localeCompare(b.path));
|
|
15157
|
+
}
|
|
15158
|
+
function finalizeResults(result, maxFiles, maxMatchesPerFile) {
|
|
15159
|
+
const visibleFiles = result.files.slice(0, maxFiles).map((file) => ({
|
|
15160
|
+
path: file.path,
|
|
15161
|
+
name: file.name,
|
|
15162
|
+
matchCount: file.matchCount,
|
|
15163
|
+
hasMoreMatches: file.matchCount > maxMatchesPerFile,
|
|
15164
|
+
matches: file.matches.slice(0, maxMatchesPerFile)
|
|
15165
|
+
}));
|
|
15166
|
+
return {
|
|
15167
|
+
files: visibleFiles,
|
|
15168
|
+
totalMatchCount: result.totalMatchCount,
|
|
15169
|
+
hasMoreFiles: result.hasMoreFiles || result.files.length > maxFiles,
|
|
15170
|
+
truncatedMatchFileCount: visibleFiles.filter((file) => file.hasMoreMatches).length
|
|
15171
|
+
};
|
|
15172
|
+
}
|
|
15173
|
+
function normalizeRelativePath(path14) {
|
|
15174
|
+
return path14.replace(/\\/g, "/");
|
|
15175
|
+
}
|
|
15176
|
+
function byteOffsetToColumn(preview, byteOffset) {
|
|
15177
|
+
return Buffer.from(preview, "utf8").subarray(0, byteOffset).toString("utf8").length + 1;
|
|
15178
|
+
}
|
|
15179
|
+
function isBinaryFile(buffer) {
|
|
15180
|
+
const sample = buffer.subarray(0, 8e3);
|
|
15181
|
+
return sample.includes(0);
|
|
15182
|
+
}
|
|
15183
|
+
var FALLBACK_MAX_FILE_BYTES;
|
|
15184
|
+
var init_content_search = __esm({
|
|
15185
|
+
"packages/server/src/fs/content-search.ts"() {
|
|
15186
|
+
"use strict";
|
|
15187
|
+
init_gitignore();
|
|
15188
|
+
FALLBACK_MAX_FILE_BYTES = 1e6;
|
|
15189
|
+
}
|
|
15190
|
+
});
|
|
15191
|
+
|
|
14897
15192
|
// packages/server/src/fs/tree.ts
|
|
14898
|
-
import { readdir as
|
|
14899
|
-
import { join as
|
|
15193
|
+
import { readdir as readdir5, stat as stat9 } from "fs/promises";
|
|
15194
|
+
import { join as join11, relative as relative3 } from "path";
|
|
14900
15195
|
async function readTree(rootPath, subdir) {
|
|
14901
|
-
const targetPath = subdir ?
|
|
15196
|
+
const targetPath = subdir ? join11(rootPath, subdir) : rootPath;
|
|
14902
15197
|
const filter = createTreeVisibilityFilter();
|
|
14903
|
-
const entries = await
|
|
15198
|
+
const entries = await readdir5(targetPath, { withFileTypes: true });
|
|
14904
15199
|
const nodes = [];
|
|
14905
15200
|
for (const entry of entries) {
|
|
14906
15201
|
if (!filter(entry.name)) {
|
|
14907
15202
|
continue;
|
|
14908
15203
|
}
|
|
14909
|
-
const fullPath =
|
|
14910
|
-
const relPath =
|
|
15204
|
+
const fullPath = join11(targetPath, entry.name);
|
|
15205
|
+
const relPath = relative3(rootPath, fullPath);
|
|
14911
15206
|
if (entry.isDirectory()) {
|
|
14912
15207
|
nodes.push({
|
|
14913
15208
|
name: entry.name,
|
|
@@ -14917,7 +15212,7 @@ async function readTree(rootPath, subdir) {
|
|
|
14917
15212
|
// Not loaded yet - client will request on expand
|
|
14918
15213
|
});
|
|
14919
15214
|
} else if (entry.isFile()) {
|
|
14920
|
-
const stats = await
|
|
15215
|
+
const stats = await stat9(fullPath);
|
|
14921
15216
|
nodes.push({
|
|
14922
15217
|
name: entry.name,
|
|
14923
15218
|
path: relPath,
|
|
@@ -14946,18 +15241,18 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
14946
15241
|
const matches = [];
|
|
14947
15242
|
async function walk(dirPath) {
|
|
14948
15243
|
const filter = createGitignoreFilter(rootPath, dirPath);
|
|
14949
|
-
const entries = await
|
|
15244
|
+
const entries = await readdir5(dirPath, { withFileTypes: true });
|
|
14950
15245
|
const filteredEntries = entries.filter((entry) => filter(entry.name));
|
|
14951
15246
|
filteredEntries.sort((a, b) => a.name.localeCompare(b.name));
|
|
14952
15247
|
for (const entry of filteredEntries) {
|
|
14953
|
-
const fullPath =
|
|
14954
|
-
const relPath =
|
|
15248
|
+
const fullPath = join11(dirPath, entry.name);
|
|
15249
|
+
const relPath = relative3(rootPath, fullPath);
|
|
14955
15250
|
if (entry.isDirectory()) {
|
|
14956
15251
|
await walk(fullPath);
|
|
14957
15252
|
continue;
|
|
14958
15253
|
}
|
|
14959
15254
|
if (entry.isFile()) {
|
|
14960
|
-
const rank =
|
|
15255
|
+
const rank = scoreFileMatch(relPath, entry.name, normalizedQuery);
|
|
14961
15256
|
if (rank === null) {
|
|
14962
15257
|
continue;
|
|
14963
15258
|
}
|
|
@@ -14986,7 +15281,7 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
14986
15281
|
}
|
|
14987
15282
|
return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
|
|
14988
15283
|
}).slice(0, limit)) {
|
|
14989
|
-
const stats = await
|
|
15284
|
+
const stats = await stat9(match.fullPath);
|
|
14990
15285
|
files.push({
|
|
14991
15286
|
name: match.name,
|
|
14992
15287
|
path: match.path,
|
|
@@ -14997,6 +15292,13 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
14997
15292
|
}
|
|
14998
15293
|
return { files };
|
|
14999
15294
|
}
|
|
15295
|
+
function scoreFileMatch(path14, name, query) {
|
|
15296
|
+
const filenameRank = scoreFilenameMatch(name, query);
|
|
15297
|
+
if (filenameRank !== null) {
|
|
15298
|
+
return filenameRank;
|
|
15299
|
+
}
|
|
15300
|
+
return scorePathMatch(path14, query);
|
|
15301
|
+
}
|
|
15000
15302
|
function scoreFilenameMatch(name, query) {
|
|
15001
15303
|
const normalizedName = name.toLowerCase();
|
|
15002
15304
|
const baseName = normalizedName.replace(/\.[^.]+$/, "");
|
|
@@ -15023,6 +15325,22 @@ function scoreFilenameMatch(name, query) {
|
|
|
15023
15325
|
}
|
|
15024
15326
|
return null;
|
|
15025
15327
|
}
|
|
15328
|
+
function scorePathMatch(path14, query) {
|
|
15329
|
+
const normalizedPath = path14.toLowerCase();
|
|
15330
|
+
if (normalizedPath === query) {
|
|
15331
|
+
return 7;
|
|
15332
|
+
}
|
|
15333
|
+
if (normalizedPath.startsWith(query)) {
|
|
15334
|
+
return 8;
|
|
15335
|
+
}
|
|
15336
|
+
if (normalizedPath.includes(query)) {
|
|
15337
|
+
return 9;
|
|
15338
|
+
}
|
|
15339
|
+
if (isSubsequence(query, normalizedPath)) {
|
|
15340
|
+
return 10;
|
|
15341
|
+
}
|
|
15342
|
+
return null;
|
|
15343
|
+
}
|
|
15026
15344
|
function isSubsequence(query, candidate) {
|
|
15027
15345
|
let index = 0;
|
|
15028
15346
|
for (const char of candidate) {
|
|
@@ -15047,6 +15365,7 @@ import { z as z13 } from "zod";
|
|
|
15047
15365
|
var init_file = __esm({
|
|
15048
15366
|
"packages/server/src/commands/file.ts"() {
|
|
15049
15367
|
"use strict";
|
|
15368
|
+
init_content_search();
|
|
15050
15369
|
init_file_io();
|
|
15051
15370
|
init_tree();
|
|
15052
15371
|
init_dispatch();
|
|
@@ -15079,6 +15398,26 @@ var init_file = __esm({
|
|
|
15079
15398
|
return searchFiles(workspace.path, args.query, args.limit ?? 10);
|
|
15080
15399
|
}
|
|
15081
15400
|
);
|
|
15401
|
+
registerCommand(
|
|
15402
|
+
"file.searchContent",
|
|
15403
|
+
z13.object({
|
|
15404
|
+
workspaceId: z13.string(),
|
|
15405
|
+
query: z13.string(),
|
|
15406
|
+
maxFiles: z13.number().int().positive().max(100),
|
|
15407
|
+
maxMatchesPerFile: z13.number().int().positive().max(100)
|
|
15408
|
+
}),
|
|
15409
|
+
async (args, ctx) => {
|
|
15410
|
+
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
15411
|
+
if (!workspace) {
|
|
15412
|
+
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
15413
|
+
}
|
|
15414
|
+
return searchFileContents(workspace.path, {
|
|
15415
|
+
query: args.query,
|
|
15416
|
+
maxFiles: args.maxFiles,
|
|
15417
|
+
maxMatchesPerFile: args.maxMatchesPerFile
|
|
15418
|
+
});
|
|
15419
|
+
}
|
|
15420
|
+
);
|
|
15082
15421
|
registerCommand(
|
|
15083
15422
|
"file.read",
|
|
15084
15423
|
z13.object({
|
|
@@ -15201,7 +15540,7 @@ var init_file = __esm({
|
|
|
15201
15540
|
});
|
|
15202
15541
|
|
|
15203
15542
|
// packages/server/src/git/diff.ts
|
|
15204
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
15543
|
+
import { mkdtemp as mkdtemp3, readFile as readFile5, rm as rm6 } from "fs/promises";
|
|
15205
15544
|
import os3 from "os";
|
|
15206
15545
|
import path11 from "path";
|
|
15207
15546
|
async function isTrackedPath(cwd, filePath) {
|
|
@@ -15241,7 +15580,7 @@ async function getUntrackedFileDiff(cwd, filePath) {
|
|
|
15241
15580
|
}
|
|
15242
15581
|
async function pathExists(cwd, filePath) {
|
|
15243
15582
|
try {
|
|
15244
|
-
await
|
|
15583
|
+
await readFile5(resolveSafe(cwd, filePath));
|
|
15245
15584
|
return true;
|
|
15246
15585
|
} catch {
|
|
15247
15586
|
return false;
|
|
@@ -15249,7 +15588,7 @@ async function pathExists(cwd, filePath) {
|
|
|
15249
15588
|
}
|
|
15250
15589
|
async function readTextAtRevision(cwd, revision, filePath) {
|
|
15251
15590
|
if (revision === "WORKTREE") {
|
|
15252
|
-
return
|
|
15591
|
+
return readFile5(resolveSafe(cwd, filePath), "utf-8");
|
|
15253
15592
|
}
|
|
15254
15593
|
try {
|
|
15255
15594
|
const gitSpec = revision === "INDEX" ? `:${filePath}` : `${revision}:${filePath}`;
|
|
@@ -15667,33 +16006,33 @@ var init_git2 = __esm({
|
|
|
15667
16006
|
});
|
|
15668
16007
|
|
|
15669
16008
|
// packages/server/src/config/config-io.ts
|
|
15670
|
-
import { existsSync as
|
|
16009
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "node:fs";
|
|
15671
16010
|
import { homedir as homedir3 } from "node:os";
|
|
15672
|
-
import { basename as
|
|
16011
|
+
import { basename as basename3, dirname as dirname7, join as join12 } from "node:path";
|
|
15673
16012
|
function resolveConfigPath(configType) {
|
|
15674
16013
|
if (configType === "codex") {
|
|
15675
16014
|
const testHome = process.env.CODER_STUDIO_CODEX_HOME;
|
|
15676
16015
|
if (testHome && testHome.trim()) {
|
|
15677
|
-
return
|
|
16016
|
+
return join12(testHome, "config.toml");
|
|
15678
16017
|
}
|
|
15679
16018
|
const codexHome = process.env.CODEX_HOME;
|
|
15680
16019
|
if (codexHome && codexHome.trim()) {
|
|
15681
|
-
return
|
|
16020
|
+
return join12(codexHome, "config.toml");
|
|
15682
16021
|
}
|
|
15683
|
-
return
|
|
16022
|
+
return join12(homedir3(), ".codex", "config.toml");
|
|
15684
16023
|
}
|
|
15685
16024
|
if (configType === "claude") {
|
|
15686
16025
|
const testHome = process.env.CODER_STUDIO_CLAUDE_HOME;
|
|
15687
16026
|
if (testHome && testHome.trim()) {
|
|
15688
|
-
return
|
|
16027
|
+
return join12(testHome, "settings.json");
|
|
15689
16028
|
}
|
|
15690
|
-
return
|
|
16029
|
+
return join12(homedir3(), ".claude", "settings.json");
|
|
15691
16030
|
}
|
|
15692
16031
|
throw new Error(`Unknown config type: ${configType}`);
|
|
15693
16032
|
}
|
|
15694
16033
|
function readConfigFile(configType) {
|
|
15695
16034
|
const configPath = resolveConfigPath(configType);
|
|
15696
|
-
if (!
|
|
16035
|
+
if (!existsSync9(configPath)) {
|
|
15697
16036
|
return { configPath, content: "", exists: false };
|
|
15698
16037
|
}
|
|
15699
16038
|
try {
|
|
@@ -15707,11 +16046,11 @@ function writeConfigFile(configType, content) {
|
|
|
15707
16046
|
try {
|
|
15708
16047
|
const configPath = resolveConfigPath(configType);
|
|
15709
16048
|
const parentDir = dirname7(configPath);
|
|
15710
|
-
if (!
|
|
16049
|
+
if (!existsSync9(parentDir)) {
|
|
15711
16050
|
mkdirSync7(parentDir, { recursive: true });
|
|
15712
16051
|
}
|
|
15713
16052
|
let backupPath = null;
|
|
15714
|
-
if (
|
|
16053
|
+
if (existsSync9(configPath)) {
|
|
15715
16054
|
backupPath = createBackup(configPath);
|
|
15716
16055
|
}
|
|
15717
16056
|
const tempPath = `${configPath}.tmp`;
|
|
@@ -15729,10 +16068,10 @@ function writeConfigFile(configType, content) {
|
|
|
15729
16068
|
function createBackup(filePath) {
|
|
15730
16069
|
const original = readFileSync7(filePath, "utf-8");
|
|
15731
16070
|
const ext = filePath.split(".").pop() ?? "";
|
|
15732
|
-
const base =
|
|
16071
|
+
const base = basename3(filePath, `.${ext}`);
|
|
15733
16072
|
const dir = dirname7(filePath);
|
|
15734
16073
|
const ts = formatTimestamp(/* @__PURE__ */ new Date());
|
|
15735
|
-
const backupPath =
|
|
16074
|
+
const backupPath = join12(dir, `${base}.bak.${ts}.${ext}`);
|
|
15736
16075
|
writeFileSync5(backupPath, original, "utf-8");
|
|
15737
16076
|
return backupPath;
|
|
15738
16077
|
}
|
|
@@ -17092,12 +17431,12 @@ var init_commands = __esm({
|
|
|
17092
17431
|
// packages/server/src/server.ts
|
|
17093
17432
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
17094
17433
|
import { tmpdir } from "node:os";
|
|
17095
|
-
import { join as
|
|
17434
|
+
import { join as join13 } from "node:path";
|
|
17096
17435
|
async function createServer(configOverrides) {
|
|
17097
17436
|
const config = parseServerConfig(configOverrides);
|
|
17098
17437
|
const configuredStateDir = resolveConfiguredStateDir(config);
|
|
17099
17438
|
const shouldCleanupStateRoot = configuredStateDir === IN_MEMORY_STATE_DIR;
|
|
17100
|
-
const stateRoot = shouldCleanupStateRoot ? mkdtempSync(
|
|
17439
|
+
const stateRoot = shouldCleanupStateRoot ? mkdtempSync(join13(tmpdir(), "coder-studio-state-")) : configuredStateDir;
|
|
17101
17440
|
ensureStateDir(config);
|
|
17102
17441
|
const eventBus = new EventBus();
|
|
17103
17442
|
const activationMgr = new ActivationManager();
|
|
@@ -17107,10 +17446,10 @@ async function createServer(configOverrides) {
|
|
|
17107
17446
|
let commandContext;
|
|
17108
17447
|
let lspMgr = null;
|
|
17109
17448
|
const terminalRepo = new TerminalRepo({
|
|
17110
|
-
filePath:
|
|
17449
|
+
filePath: join13(stateRoot, "state", "terminals.json")
|
|
17111
17450
|
});
|
|
17112
17451
|
const sessionRepo = new SessionRepo({
|
|
17113
|
-
filePath:
|
|
17452
|
+
filePath: join13(stateRoot, "state", "sessions.json")
|
|
17114
17453
|
});
|
|
17115
17454
|
const terminalMgr = new TerminalManager({
|
|
17116
17455
|
ptyHost: createPtyHost(),
|
|
@@ -17118,10 +17457,10 @@ async function createServer(configOverrides) {
|
|
|
17118
17457
|
db: terminalRepo
|
|
17119
17458
|
});
|
|
17120
17459
|
const settingsRepo = new SettingsRepo({
|
|
17121
|
-
filePath:
|
|
17460
|
+
filePath: join13(stateRoot, "state", "settings.json")
|
|
17122
17461
|
});
|
|
17123
17462
|
const updateStateRepo = new UpdateStateRepo({
|
|
17124
|
-
filePath:
|
|
17463
|
+
filePath: join13(stateRoot, "state", "update-state.json"),
|
|
17125
17464
|
currentVersion: config.appVersion ?? "0.0.0"
|
|
17126
17465
|
});
|
|
17127
17466
|
const autoFetch = new AutoFetchScheduler({
|
|
@@ -17154,10 +17493,10 @@ async function createServer(configOverrides) {
|
|
|
17154
17493
|
}
|
|
17155
17494
|
});
|
|
17156
17495
|
const providerConfigRepo = new ProviderConfigRepo({
|
|
17157
|
-
filePath:
|
|
17496
|
+
filePath: join13(stateRoot, "state", "provider-configs.json")
|
|
17158
17497
|
});
|
|
17159
17498
|
const workspaceRepo = new WorkspaceRepo({
|
|
17160
|
-
filePath:
|
|
17499
|
+
filePath: join13(stateRoot, "state", "workspaces.json")
|
|
17161
17500
|
});
|
|
17162
17501
|
const sessionMgr = new SessionManager({
|
|
17163
17502
|
terminalMgr,
|
|
@@ -17192,10 +17531,10 @@ async function createServer(configOverrides) {
|
|
|
17192
17531
|
)
|
|
17193
17532
|
});
|
|
17194
17533
|
const authSessionRepo = new AuthSessionRepo({
|
|
17195
|
-
filePath:
|
|
17534
|
+
filePath: join13(stateRoot, "state", "auth-sessions.json")
|
|
17196
17535
|
});
|
|
17197
17536
|
const authLoginBlockRepo = new AuthLoginBlockRepo({
|
|
17198
|
-
filePath:
|
|
17537
|
+
filePath: join13(stateRoot, "state", "auth-login-blocks.json")
|
|
17199
17538
|
});
|
|
17200
17539
|
const app = await buildFastifyApp({
|
|
17201
17540
|
wsHub,
|
|
@@ -17270,7 +17609,7 @@ async function createServer(configOverrides) {
|
|
|
17270
17609
|
...config.update,
|
|
17271
17610
|
currentVersion: config.appVersion ?? "0.0.0"
|
|
17272
17611
|
},
|
|
17273
|
-
updateWorkerLogFilePath:
|
|
17612
|
+
updateWorkerLogFilePath: join13(stateRoot, "logs", "update-worker.log"),
|
|
17274
17613
|
countRunningTerminals: () => terminalMgr.getAll().filter((terminal) => terminal.alive).length,
|
|
17275
17614
|
countRunningSessions: () => sessionMgr.getAll().filter((session) => session.state === "starting" || session.state === "running").length,
|
|
17276
17615
|
countActiveSupervisors: () => supervisorMgr?.countActive() ?? 0
|
|
@@ -17492,28 +17831,28 @@ var init_src4 = __esm({
|
|
|
17492
17831
|
});
|
|
17493
17832
|
|
|
17494
17833
|
// packages/cli/src/cli.ts
|
|
17495
|
-
import { existsSync as
|
|
17496
|
-
import { dirname as dirname10, join as
|
|
17834
|
+
import { existsSync as existsSync15 } from "fs";
|
|
17835
|
+
import { dirname as dirname10, join as join18 } from "path";
|
|
17497
17836
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
17498
17837
|
|
|
17499
17838
|
// packages/cli/src/auth-control.ts
|
|
17500
17839
|
await init_src4();
|
|
17501
|
-
import { join as
|
|
17840
|
+
import { join as join15 } from "node:path";
|
|
17502
17841
|
|
|
17503
17842
|
// packages/cli/src/config-store.ts
|
|
17504
17843
|
init_state_paths();
|
|
17505
|
-
import { existsSync as
|
|
17844
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
17506
17845
|
import { homedir as homedir4 } from "os";
|
|
17507
|
-
import { join as
|
|
17846
|
+
import { join as join14 } from "path";
|
|
17508
17847
|
function getCliConfigPath() {
|
|
17509
|
-
return
|
|
17848
|
+
return join14(homedir4(), ".coder-studio", "config.json");
|
|
17510
17849
|
}
|
|
17511
17850
|
function normalizeLegacyDataDir(input2) {
|
|
17512
17851
|
return normalizeLegacyStateDir(input2);
|
|
17513
17852
|
}
|
|
17514
17853
|
function readCliConfig() {
|
|
17515
17854
|
const path14 = getCliConfigPath();
|
|
17516
|
-
if (!
|
|
17855
|
+
if (!existsSync10(path14)) {
|
|
17517
17856
|
return null;
|
|
17518
17857
|
}
|
|
17519
17858
|
try {
|
|
@@ -17533,14 +17872,14 @@ function readCliConfig() {
|
|
|
17533
17872
|
}
|
|
17534
17873
|
function writeCliConfig(config) {
|
|
17535
17874
|
const path14 = getCliConfigPath();
|
|
17536
|
-
const dir =
|
|
17875
|
+
const dir = join14(homedir4(), ".coder-studio");
|
|
17537
17876
|
const normalizedConfig = {
|
|
17538
17877
|
...config.host !== void 0 ? { host: config.host } : {},
|
|
17539
17878
|
...config.port !== void 0 && config.port > 0 ? { port: config.port } : {},
|
|
17540
17879
|
...config.stateDir !== void 0 ? { stateDir: normalizeStateDir(config.stateDir) } : {},
|
|
17541
17880
|
...config.password !== void 0 ? { password: config.password } : {}
|
|
17542
17881
|
};
|
|
17543
|
-
if (!
|
|
17882
|
+
if (!existsSync10(dir)) {
|
|
17544
17883
|
mkdirSync8(dir, { recursive: true });
|
|
17545
17884
|
}
|
|
17546
17885
|
writeFileSync6(path14, JSON.stringify(normalizedConfig, null, 2), "utf-8");
|
|
@@ -17555,7 +17894,7 @@ function resolveStateDir() {
|
|
|
17555
17894
|
}
|
|
17556
17895
|
async function listAuthBlocks(now = Date.now()) {
|
|
17557
17896
|
const repo = new AuthLoginBlockRepo({
|
|
17558
|
-
filePath:
|
|
17897
|
+
filePath: join15(resolveStateDir(), "state", "auth-login-blocks.json")
|
|
17559
17898
|
});
|
|
17560
17899
|
return repo.listActiveBlocks(now).map((record) => ({
|
|
17561
17900
|
ip: record.ip,
|
|
@@ -17567,13 +17906,13 @@ async function listAuthBlocks(now = Date.now()) {
|
|
|
17567
17906
|
}
|
|
17568
17907
|
async function clearAuthBlockByIp(ip) {
|
|
17569
17908
|
const repo = new AuthLoginBlockRepo({
|
|
17570
|
-
filePath:
|
|
17909
|
+
filePath: join15(resolveStateDir(), "state", "auth-login-blocks.json")
|
|
17571
17910
|
});
|
|
17572
17911
|
return repo.delete(ip);
|
|
17573
17912
|
}
|
|
17574
17913
|
|
|
17575
17914
|
// packages/cli/src/browser.ts
|
|
17576
|
-
import { spawn as
|
|
17915
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
17577
17916
|
function getOpenCommand(url) {
|
|
17578
17917
|
switch (process.platform) {
|
|
17579
17918
|
case "darwin":
|
|
@@ -17587,7 +17926,7 @@ function getOpenCommand(url) {
|
|
|
17587
17926
|
async function openBrowser(url) {
|
|
17588
17927
|
const { command, args } = getOpenCommand(url);
|
|
17589
17928
|
await new Promise((resolve4, reject) => {
|
|
17590
|
-
const child =
|
|
17929
|
+
const child = spawn6(command, args, {
|
|
17591
17930
|
detached: true,
|
|
17592
17931
|
stdio: "ignore",
|
|
17593
17932
|
windowsHide: true
|
|
@@ -17601,12 +17940,12 @@ async function openBrowser(url) {
|
|
|
17601
17940
|
}
|
|
17602
17941
|
|
|
17603
17942
|
// packages/cli/src/log-excerpt.ts
|
|
17604
|
-
import { closeSync, existsSync as
|
|
17943
|
+
import { closeSync, existsSync as existsSync11, openSync, readSync, statSync as statSync2 } from "fs";
|
|
17605
17944
|
var DEFAULT_MAX_LINES = 40;
|
|
17606
17945
|
var DEFAULT_MAX_CHARS = 4e3;
|
|
17607
17946
|
var DEFAULT_MAX_BYTES = 16 * 1024;
|
|
17608
17947
|
var getFileSize = (path14) => {
|
|
17609
|
-
if (!
|
|
17948
|
+
if (!existsSync11(path14)) {
|
|
17610
17949
|
return 0;
|
|
17611
17950
|
}
|
|
17612
17951
|
try {
|
|
@@ -17621,7 +17960,7 @@ var readLogExcerpt = (path14, {
|
|
|
17621
17960
|
maxLines = DEFAULT_MAX_LINES,
|
|
17622
17961
|
maxChars = DEFAULT_MAX_CHARS
|
|
17623
17962
|
} = {}) => {
|
|
17624
|
-
if (!
|
|
17963
|
+
if (!existsSync11(path14)) {
|
|
17625
17964
|
return null;
|
|
17626
17965
|
}
|
|
17627
17966
|
const fileSize = getFileSize(path14);
|
|
@@ -17700,12 +18039,12 @@ function assertSupportedNodeVersion(version = process.versions.node) {
|
|
|
17700
18039
|
}
|
|
17701
18040
|
|
|
17702
18041
|
// packages/cli/src/package-manifest.ts
|
|
17703
|
-
import { existsSync as
|
|
18042
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
17704
18043
|
function resolveCliPackageManifestUrl(importMetaUrl) {
|
|
17705
18044
|
const manifestUrl = [
|
|
17706
18045
|
new URL("../package.json", importMetaUrl),
|
|
17707
18046
|
new URL("../../package.json", importMetaUrl)
|
|
17708
|
-
].find((candidate) =>
|
|
18047
|
+
].find((candidate) => existsSync12(candidate));
|
|
17709
18048
|
if (!manifestUrl) {
|
|
17710
18049
|
throw new Error("Unable to locate CLI package.json");
|
|
17711
18050
|
}
|
|
@@ -17928,7 +18267,7 @@ function parseArgs(argv) {
|
|
|
17928
18267
|
init_runtime();
|
|
17929
18268
|
import { mkdirSync as mkdirSync9 } from "fs";
|
|
17930
18269
|
import { homedir as homedir5 } from "os";
|
|
17931
|
-
import { join as
|
|
18270
|
+
import { join as join16 } from "path";
|
|
17932
18271
|
var MANAGED_SERVER_NAME = "coder-studio-server";
|
|
17933
18272
|
var PM2_RESTART_DELAY_MS = 2e3;
|
|
17934
18273
|
var PM2_MIN_UPTIME = "5s";
|
|
@@ -18099,6 +18438,28 @@ var waitForManagedServerDeletion = async (pm2, waitMs) => {
|
|
|
18099
18438
|
}
|
|
18100
18439
|
throw new Error(`Timed out waiting for the managed server to stop after ${waitMs}ms.`);
|
|
18101
18440
|
};
|
|
18441
|
+
var isMissingProcessError = (error) => Boolean(
|
|
18442
|
+
error && typeof error === "object" && "code" in error && error.code === "ESRCH"
|
|
18443
|
+
);
|
|
18444
|
+
var waitForProcessExit = async (pid, waitMs) => {
|
|
18445
|
+
const deadline = Date.now() + waitMs;
|
|
18446
|
+
while (Date.now() <= deadline) {
|
|
18447
|
+
try {
|
|
18448
|
+
process.kill(pid, 0);
|
|
18449
|
+
} catch (error) {
|
|
18450
|
+
if (isMissingProcessError(error)) {
|
|
18451
|
+
return;
|
|
18452
|
+
}
|
|
18453
|
+
throw error;
|
|
18454
|
+
}
|
|
18455
|
+
const remainingMs = deadline - Date.now();
|
|
18456
|
+
if (remainingMs <= 0) {
|
|
18457
|
+
break;
|
|
18458
|
+
}
|
|
18459
|
+
await sleep(Math.min(STARTUP_POLL_INTERVAL_MS, remainingMs));
|
|
18460
|
+
}
|
|
18461
|
+
throw new Error(`Timed out waiting for the managed server pid ${pid} to exit after ${waitMs}ms.`);
|
|
18462
|
+
};
|
|
18102
18463
|
var deleteManagedServerInSession = async (pm2, {
|
|
18103
18464
|
ignoreMissing = false
|
|
18104
18465
|
} = {}) => {
|
|
@@ -18106,24 +18467,32 @@ var deleteManagedServerInSession = async (pm2, {
|
|
|
18106
18467
|
if (processes.length === 0) {
|
|
18107
18468
|
return false;
|
|
18108
18469
|
}
|
|
18470
|
+
const previousPid = processes[0]?.pid;
|
|
18471
|
+
const deadline = Date.now() + PM2_DELETE_WAIT_MS;
|
|
18109
18472
|
try {
|
|
18110
18473
|
await removeManagedServer(pm2);
|
|
18111
18474
|
} catch (error) {
|
|
18112
18475
|
if (ignoreMissing && isMissingManagedServerError(error)) {
|
|
18113
|
-
await waitForManagedServerDeletion(pm2,
|
|
18476
|
+
await waitForManagedServerDeletion(pm2, Math.max(0, deadline - Date.now()));
|
|
18477
|
+
if (typeof previousPid === "number" && previousPid > 0) {
|
|
18478
|
+
await waitForProcessExit(previousPid, Math.max(0, deadline - Date.now()));
|
|
18479
|
+
}
|
|
18114
18480
|
return false;
|
|
18115
18481
|
}
|
|
18116
18482
|
throw error;
|
|
18117
18483
|
}
|
|
18118
|
-
await waitForManagedServerDeletion(pm2,
|
|
18484
|
+
await waitForManagedServerDeletion(pm2, Math.max(0, deadline - Date.now()));
|
|
18485
|
+
if (typeof previousPid === "number" && previousPid > 0) {
|
|
18486
|
+
await waitForProcessExit(previousPid, Math.max(0, deadline - Date.now()));
|
|
18487
|
+
}
|
|
18119
18488
|
return true;
|
|
18120
18489
|
};
|
|
18121
18490
|
var ensureLogDirectory = () => {
|
|
18122
|
-
mkdirSync9(
|
|
18491
|
+
mkdirSync9(join16(homedir5(), ".coder-studio", "logs"), { recursive: true });
|
|
18123
18492
|
};
|
|
18124
18493
|
var getLogPaths = () => ({
|
|
18125
|
-
outFile:
|
|
18126
|
-
errFile:
|
|
18494
|
+
outFile: join16(homedir5(), ".coder-studio", "logs", "server.out.log"),
|
|
18495
|
+
errFile: join16(homedir5(), ".coder-studio", "logs", "server.err.log")
|
|
18127
18496
|
});
|
|
18128
18497
|
var captureStartupLogOffsets = () => {
|
|
18129
18498
|
const { outFile, errFile } = getLogPaths();
|
|
@@ -18251,12 +18620,12 @@ var getManagedServerStatus = async () => withPm2Connection(async (pm2) => {
|
|
|
18251
18620
|
|
|
18252
18621
|
// packages/cli/src/prompts.ts
|
|
18253
18622
|
import { stdin as input, stdout as output } from "node:process";
|
|
18254
|
-
import { createInterface } from "node:readline/promises";
|
|
18623
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
18255
18624
|
function isInteractiveSession() {
|
|
18256
18625
|
return Boolean(input.isTTY && output.isTTY);
|
|
18257
18626
|
}
|
|
18258
18627
|
async function confirmYesNo(prompt) {
|
|
18259
|
-
const rl =
|
|
18628
|
+
const rl = createInterface2({ input, output });
|
|
18260
18629
|
try {
|
|
18261
18630
|
const answer = (await rl.question(prompt)).trim().toLowerCase();
|
|
18262
18631
|
return answer === "y" || answer === "yes";
|
|
@@ -18311,7 +18680,7 @@ import { mkdirSync as mkdirSync10 } from "fs";
|
|
|
18311
18680
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
18312
18681
|
|
|
18313
18682
|
// packages/cli/src/embed.ts
|
|
18314
|
-
import { existsSync as
|
|
18683
|
+
import { existsSync as existsSync13 } from "fs";
|
|
18315
18684
|
import { dirname as dirname8, resolve as resolve3 } from "path";
|
|
18316
18685
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18317
18686
|
var __filename = fileURLToPath2(import.meta.url);
|
|
@@ -18321,20 +18690,20 @@ function getStaticAssetsDir() {
|
|
|
18321
18690
|
return WEB_ASSETS_DIR;
|
|
18322
18691
|
}
|
|
18323
18692
|
function hasWebAssets() {
|
|
18324
|
-
return
|
|
18693
|
+
return existsSync13(WEB_ASSETS_DIR);
|
|
18325
18694
|
}
|
|
18326
18695
|
|
|
18327
18696
|
// packages/cli/src/update-runtime.ts
|
|
18328
|
-
import { existsSync as
|
|
18329
|
-
import { dirname as dirname9, join as
|
|
18697
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
18698
|
+
import { dirname as dirname9, join as join17 } from "node:path";
|
|
18330
18699
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
18331
18700
|
function resolveWorkerEntryPath(importMetaUrl) {
|
|
18332
18701
|
const currentDir = dirname9(fileURLToPath3(importMetaUrl));
|
|
18333
18702
|
const candidates = [
|
|
18334
|
-
|
|
18335
|
-
|
|
18703
|
+
join17(currentDir, "update-worker.mjs"),
|
|
18704
|
+
join17(currentDir, "../src/update-worker.ts")
|
|
18336
18705
|
];
|
|
18337
|
-
return candidates.find((candidate) =>
|
|
18706
|
+
return candidates.find((candidate) => existsSync14(candidate));
|
|
18338
18707
|
}
|
|
18339
18708
|
function getUpdateRuntimeInfo(importMetaUrl) {
|
|
18340
18709
|
const workerEntryPath = resolveWorkerEntryPath(importMetaUrl);
|
|
@@ -18561,11 +18930,11 @@ function resolveManagedScriptPath() {
|
|
|
18561
18930
|
const currentFile = fileURLToPath5(import.meta.url);
|
|
18562
18931
|
const currentDir = dirname10(currentFile);
|
|
18563
18932
|
const candidates = [
|
|
18564
|
-
|
|
18565
|
-
|
|
18566
|
-
|
|
18933
|
+
join18(currentDir, "server-runner.js"),
|
|
18934
|
+
join18(currentDir, "server-runner.mjs"),
|
|
18935
|
+
join18(currentDir, "../src/server-runner.ts")
|
|
18567
18936
|
];
|
|
18568
|
-
const scriptPath = candidates.find((candidate) =>
|
|
18937
|
+
const scriptPath = candidates.find((candidate) => existsSync15(candidate));
|
|
18569
18938
|
if (!scriptPath) {
|
|
18570
18939
|
throw new Error("Unable to locate the managed server entry script");
|
|
18571
18940
|
}
|