chatroom-cli 1.65.0 → 1.65.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1109 -899
- package/dist/index.js.map +20 -17
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -84704,765 +84704,6 @@ var init_daemon_services = __esm(() => {
|
|
|
84704
84704
|
};
|
|
84705
84705
|
});
|
|
84706
84706
|
|
|
84707
|
-
// src/commands/machine/daemon-start/utils.ts
|
|
84708
|
-
function formatTimestamp() {
|
|
84709
|
-
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
84710
|
-
}
|
|
84711
|
-
|
|
84712
|
-
// src/infrastructure/services/workspace/dir-listing-content-hash.ts
|
|
84713
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
84714
|
-
function computeDirListingContentHash(listing) {
|
|
84715
|
-
const payload = {
|
|
84716
|
-
entries: listing.entries,
|
|
84717
|
-
truncated: listing.truncated,
|
|
84718
|
-
totalCount: listing.totalCount
|
|
84719
|
-
};
|
|
84720
|
-
return createHash2("md5").update(JSON.stringify(payload)).digest("hex");
|
|
84721
|
-
}
|
|
84722
|
-
var init_dir_listing_content_hash = () => {};
|
|
84723
|
-
|
|
84724
|
-
// src/infrastructure/services/workspace/workspace-path-security.ts
|
|
84725
|
-
import { realpath as realpath2 } from "node:fs/promises";
|
|
84726
|
-
import { basename, dirname as dirname8, isAbsolute, relative, resolve as resolve4, sep } from "node:path";
|
|
84727
|
-
import { gunzipSync } from "node:zlib";
|
|
84728
|
-
function validateRelativePathSegments(filePath) {
|
|
84729
|
-
if (filePath.includes("\x00"))
|
|
84730
|
-
return { ok: false, error: "Invalid file path" };
|
|
84731
|
-
if (filePath.includes(".."))
|
|
84732
|
-
return { ok: false, error: "Invalid file path" };
|
|
84733
|
-
if (filePath.startsWith("/"))
|
|
84734
|
-
return { ok: false, error: "Invalid file path" };
|
|
84735
|
-
return { ok: true };
|
|
84736
|
-
}
|
|
84737
|
-
function isPathInsideRoot(workspaceRoot, targetPath) {
|
|
84738
|
-
const rel = relative(workspaceRoot, targetPath);
|
|
84739
|
-
if (rel === "")
|
|
84740
|
-
return true;
|
|
84741
|
-
if (rel.startsWith("..") || rel.includes(`..${sep}`))
|
|
84742
|
-
return false;
|
|
84743
|
-
if (isAbsolute(rel))
|
|
84744
|
-
return false;
|
|
84745
|
-
return true;
|
|
84746
|
-
}
|
|
84747
|
-
async function resolvePathWithinWorkspace(workingDir, filePath) {
|
|
84748
|
-
const basic = validateRelativePathSegments(filePath);
|
|
84749
|
-
if (!basic.ok)
|
|
84750
|
-
return basic;
|
|
84751
|
-
let workspaceRoot;
|
|
84752
|
-
try {
|
|
84753
|
-
workspaceRoot = await realpath2(resolve4(workingDir));
|
|
84754
|
-
} catch {
|
|
84755
|
-
return { ok: false, error: "Working directory not found" };
|
|
84756
|
-
}
|
|
84757
|
-
const candidate = resolve4(workspaceRoot, filePath);
|
|
84758
|
-
if (!isPathInsideRoot(workspaceRoot, candidate)) {
|
|
84759
|
-
return { ok: false, error: "Path escapes workspace" };
|
|
84760
|
-
}
|
|
84761
|
-
try {
|
|
84762
|
-
const resolved = await realpath2(candidate);
|
|
84763
|
-
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
84764
|
-
return { ok: false, error: "Path escapes workspace" };
|
|
84765
|
-
}
|
|
84766
|
-
return { ok: true, absolutePath: resolved };
|
|
84767
|
-
} catch (err) {
|
|
84768
|
-
const code2 = err?.code;
|
|
84769
|
-
if (code2 !== "ENOENT") {
|
|
84770
|
-
return { ok: false, error: "Invalid file path" };
|
|
84771
|
-
}
|
|
84772
|
-
const parent = dirname8(candidate);
|
|
84773
|
-
if (parent === workspaceRoot || isPathInsideRoot(workspaceRoot, parent)) {
|
|
84774
|
-
try {
|
|
84775
|
-
const parentReal = await realpath2(parent);
|
|
84776
|
-
if (!isPathInsideRoot(workspaceRoot, parentReal)) {
|
|
84777
|
-
return { ok: false, error: "Path escapes workspace" };
|
|
84778
|
-
}
|
|
84779
|
-
const resolved = resolve4(parentReal, basename(candidate));
|
|
84780
|
-
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
84781
|
-
return { ok: false, error: "Path escapes workspace" };
|
|
84782
|
-
}
|
|
84783
|
-
return { ok: true, absolutePath: resolved };
|
|
84784
|
-
} catch {
|
|
84785
|
-
return { ok: true, absolutePath: candidate };
|
|
84786
|
-
}
|
|
84787
|
-
}
|
|
84788
|
-
return { ok: false, error: "Path escapes workspace" };
|
|
84789
|
-
}
|
|
84790
|
-
}
|
|
84791
|
-
function gunzipBase64Payload(base64, maxBytes) {
|
|
84792
|
-
let compressed;
|
|
84793
|
-
try {
|
|
84794
|
-
compressed = Buffer.from(base64, "base64");
|
|
84795
|
-
} catch {
|
|
84796
|
-
return { ok: false, errorMessage: "Missing file data" };
|
|
84797
|
-
}
|
|
84798
|
-
if (compressed.length > maxBytes * 10) {
|
|
84799
|
-
return { ok: false, errorMessage: "File content too large" };
|
|
84800
|
-
}
|
|
84801
|
-
try {
|
|
84802
|
-
const content = gunzipSync(compressed, { maxOutputLength: maxBytes });
|
|
84803
|
-
if (content.length > maxBytes) {
|
|
84804
|
-
return { ok: false, errorMessage: "File content too large" };
|
|
84805
|
-
}
|
|
84806
|
-
return { ok: true, content };
|
|
84807
|
-
} catch {
|
|
84808
|
-
return { ok: false, errorMessage: "File content too large" };
|
|
84809
|
-
}
|
|
84810
|
-
}
|
|
84811
|
-
var init_workspace_path_security = () => {};
|
|
84812
|
-
|
|
84813
|
-
// src/infrastructure/services/workspace/workspace-visibility-policy.ts
|
|
84814
|
-
import { exec as exec2, spawn as spawn4 } from "node:child_process";
|
|
84815
|
-
import { promisify as promisify2 } from "node:util";
|
|
84816
|
-
function isAlwaysExcludedDirName(name) {
|
|
84817
|
-
return ALWAYS_EXCLUDE_DIR_NAMES.has(name);
|
|
84818
|
-
}
|
|
84819
|
-
function isSecretPath(relativePath) {
|
|
84820
|
-
const normalized = relativePath.replace(/\\/g, "/");
|
|
84821
|
-
return SECRET_PATH_PATTERNS.some((pattern2) => pattern2.test(normalized));
|
|
84822
|
-
}
|
|
84823
|
-
function hasExcludedDirSegment(relativePath) {
|
|
84824
|
-
const segments = relativePath.split("/");
|
|
84825
|
-
return segments.some((segment) => isAlwaysExcludedDirName(segment));
|
|
84826
|
-
}
|
|
84827
|
-
function isPathVisible(relativePath) {
|
|
84828
|
-
if (!relativePath)
|
|
84829
|
-
return true;
|
|
84830
|
-
return !isSecretPath(relativePath) && !hasExcludedDirSegment(relativePath);
|
|
84831
|
-
}
|
|
84832
|
-
function isPathContentReadable(relativePath) {
|
|
84833
|
-
return isPathVisible(relativePath);
|
|
84834
|
-
}
|
|
84835
|
-
async function isGitRepo2(rootDir) {
|
|
84836
|
-
try {
|
|
84837
|
-
const { stdout } = await execAsync2("git rev-parse --is-inside-work-tree", {
|
|
84838
|
-
cwd: rootDir,
|
|
84839
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" },
|
|
84840
|
-
maxBuffer: 1024 * 1024
|
|
84841
|
-
});
|
|
84842
|
-
return stdout.trim() === "true";
|
|
84843
|
-
} catch {
|
|
84844
|
-
return false;
|
|
84845
|
-
}
|
|
84846
|
-
}
|
|
84847
|
-
async function filterGitIgnored(rootDir, relativePaths) {
|
|
84848
|
-
if (relativePaths.length === 0)
|
|
84849
|
-
return new Set;
|
|
84850
|
-
const inRepo = await isGitRepo2(rootDir);
|
|
84851
|
-
if (!inRepo)
|
|
84852
|
-
return new Set;
|
|
84853
|
-
try {
|
|
84854
|
-
const stdout = await new Promise((resolve5, reject) => {
|
|
84855
|
-
const child = spawn4("git", ["check-ignore", "--stdin", "-z"], {
|
|
84856
|
-
cwd: rootDir,
|
|
84857
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" }
|
|
84858
|
-
});
|
|
84859
|
-
let output = "";
|
|
84860
|
-
child.stdout.on("data", (chunk2) => {
|
|
84861
|
-
output += chunk2.toString();
|
|
84862
|
-
});
|
|
84863
|
-
child.on("error", reject);
|
|
84864
|
-
child.on("close", () => resolve5(output));
|
|
84865
|
-
child.stdin.write(relativePaths.join(`
|
|
84866
|
-
`));
|
|
84867
|
-
child.stdin.end();
|
|
84868
|
-
});
|
|
84869
|
-
const ignored = new Set;
|
|
84870
|
-
if (!stdout)
|
|
84871
|
-
return ignored;
|
|
84872
|
-
for (const entry of stdout.split("\x00")) {
|
|
84873
|
-
const trimmed = entry.trim();
|
|
84874
|
-
if (trimmed)
|
|
84875
|
-
ignored.add(trimmed);
|
|
84876
|
-
}
|
|
84877
|
-
return ignored;
|
|
84878
|
-
} catch {
|
|
84879
|
-
return new Set;
|
|
84880
|
-
}
|
|
84881
|
-
}
|
|
84882
|
-
var execAsync2, ALWAYS_EXCLUDE_DIR_NAMES, SECRET_PATH_PATTERNS;
|
|
84883
|
-
var init_workspace_visibility_policy = __esm(() => {
|
|
84884
|
-
execAsync2 = promisify2(exec2);
|
|
84885
|
-
ALWAYS_EXCLUDE_DIR_NAMES = new Set([
|
|
84886
|
-
"node_modules",
|
|
84887
|
-
".git",
|
|
84888
|
-
"dist",
|
|
84889
|
-
"build",
|
|
84890
|
-
".next",
|
|
84891
|
-
"coverage",
|
|
84892
|
-
"__pycache__",
|
|
84893
|
-
".turbo",
|
|
84894
|
-
".cache",
|
|
84895
|
-
".tmp",
|
|
84896
|
-
"tmp",
|
|
84897
|
-
"_generated",
|
|
84898
|
-
".vercel"
|
|
84899
|
-
]);
|
|
84900
|
-
SECRET_PATH_PATTERNS = [
|
|
84901
|
-
/^\.env$/,
|
|
84902
|
-
/^\.env\./,
|
|
84903
|
-
/\.pem$/,
|
|
84904
|
-
/\.key$/,
|
|
84905
|
-
/id_rsa$/,
|
|
84906
|
-
/credentials\.json$/,
|
|
84907
|
-
/^secrets(\/|$)/,
|
|
84908
|
-
/^\.aws(\/|$)/
|
|
84909
|
-
];
|
|
84910
|
-
});
|
|
84911
|
-
|
|
84912
|
-
// src/infrastructure/services/workspace/dir-listing-scanner.ts
|
|
84913
|
-
import { promises as fsPromises } from "node:fs";
|
|
84914
|
-
import path3 from "node:path";
|
|
84915
|
-
async function listDirectory(rootDir, dirPath, options) {
|
|
84916
|
-
const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
84917
|
-
const scannedAt = Date.now();
|
|
84918
|
-
const absDir = dirPath ? path3.join(rootDir, dirPath) : rootDir;
|
|
84919
|
-
const resolvedRoot = path3.resolve(rootDir);
|
|
84920
|
-
const resolvedDir = path3.resolve(absDir);
|
|
84921
|
-
if (!isPathInsideRoot(resolvedRoot, resolvedDir)) {
|
|
84922
|
-
return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
|
|
84923
|
-
}
|
|
84924
|
-
let dirents;
|
|
84925
|
-
try {
|
|
84926
|
-
dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
|
|
84927
|
-
} catch {
|
|
84928
|
-
return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
|
|
84929
|
-
}
|
|
84930
|
-
const candidates = [];
|
|
84931
|
-
for (const ent of dirents) {
|
|
84932
|
-
if (isAlwaysExcludedDirName(ent.name))
|
|
84933
|
-
continue;
|
|
84934
|
-
const relativePath = dirPath ? `${dirPath}/${ent.name}` : ent.name;
|
|
84935
|
-
if (!isPathVisible(relativePath))
|
|
84936
|
-
continue;
|
|
84937
|
-
if (ent.isDirectory()) {
|
|
84938
|
-
candidates.push({ name: ent.name, path: relativePath, type: "directory" });
|
|
84939
|
-
} else if (ent.isFile()) {
|
|
84940
|
-
let size11;
|
|
84941
|
-
try {
|
|
84942
|
-
const st = await fsPromises.stat(path3.join(absDir, ent.name));
|
|
84943
|
-
size11 = st.size;
|
|
84944
|
-
} catch {}
|
|
84945
|
-
candidates.push({ name: ent.name, path: relativePath, type: "file", size: size11 });
|
|
84946
|
-
}
|
|
84947
|
-
}
|
|
84948
|
-
const ignored = await filterGitIgnored(rootDir, candidates.map((c) => c.path));
|
|
84949
|
-
const visible = candidates.filter((c) => !ignored.has(c.path));
|
|
84950
|
-
visible.sort((a, b) => {
|
|
84951
|
-
if (a.type === "directory" && b.type === "file")
|
|
84952
|
-
return -1;
|
|
84953
|
-
if (a.type === "file" && b.type === "directory")
|
|
84954
|
-
return 1;
|
|
84955
|
-
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
84956
|
-
});
|
|
84957
|
-
const totalCount = visible.length;
|
|
84958
|
-
const truncated = totalCount > maxEntries;
|
|
84959
|
-
const entries2 = visible.slice(0, maxEntries);
|
|
84960
|
-
return { dirPath, entries: entries2, scannedAt, truncated, totalCount };
|
|
84961
|
-
}
|
|
84962
|
-
var DEFAULT_MAX_ENTRIES = 500;
|
|
84963
|
-
var init_dir_listing_scanner = __esm(() => {
|
|
84964
|
-
init_workspace_path_security();
|
|
84965
|
-
init_workspace_visibility_policy();
|
|
84966
|
-
});
|
|
84967
|
-
|
|
84968
|
-
// src/infrastructure/services/workspace/dir-listing-sync.ts
|
|
84969
|
-
import { gzipSync } from "node:zlib";
|
|
84970
|
-
function listingCacheKey(workingDir, dirPath) {
|
|
84971
|
-
return `${workingDir}\x00${dirPath}`;
|
|
84972
|
-
}
|
|
84973
|
-
async function scanDirListingForSync(workingDir, dirPath) {
|
|
84974
|
-
const listing = await listDirectory(workingDir, dirPath);
|
|
84975
|
-
const dataHash = computeDirListingContentHash(listing);
|
|
84976
|
-
const cacheKey = listingCacheKey(workingDir, dirPath);
|
|
84977
|
-
if (lastSyncedContentHash.get(cacheKey) === dataHash)
|
|
84978
|
-
return null;
|
|
84979
|
-
const json = JSON.stringify(listing);
|
|
84980
|
-
return {
|
|
84981
|
-
dirPath,
|
|
84982
|
-
data: { compression: "gzip", content: gzipSync(Buffer.from(json)).toString("base64") },
|
|
84983
|
-
dataHash,
|
|
84984
|
-
scannedAt: listing.scannedAt,
|
|
84985
|
-
truncated: listing.truncated,
|
|
84986
|
-
totalCount: listing.totalCount
|
|
84987
|
-
};
|
|
84988
|
-
}
|
|
84989
|
-
async function scanDirListingsWithConcurrency(workingDir, dirPaths) {
|
|
84990
|
-
const items = [];
|
|
84991
|
-
let index = 0;
|
|
84992
|
-
async function worker() {
|
|
84993
|
-
while (index < dirPaths.length) {
|
|
84994
|
-
const currentIndex = index;
|
|
84995
|
-
index += 1;
|
|
84996
|
-
const dirPath = dirPaths[currentIndex];
|
|
84997
|
-
if (dirPath === undefined)
|
|
84998
|
-
continue;
|
|
84999
|
-
const item = await scanDirListingForSync(workingDir, dirPath);
|
|
85000
|
-
if (item)
|
|
85001
|
-
items.push(item);
|
|
85002
|
-
}
|
|
85003
|
-
}
|
|
85004
|
-
const workerCount = Math.min(SCAN_CONCURRENCY, dirPaths.length);
|
|
85005
|
-
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
85006
|
-
return items;
|
|
85007
|
-
}
|
|
85008
|
-
function markItemsSynced(workingDir, items) {
|
|
85009
|
-
for (const item of items) {
|
|
85010
|
-
lastSyncedContentHash.set(listingCacheKey(workingDir, item.dirPath), item.dataHash);
|
|
85011
|
-
}
|
|
85012
|
-
}
|
|
85013
|
-
async function syncDirListingToBackend(session2, workingDir, dirPath) {
|
|
85014
|
-
const item = await scanDirListingForSync(workingDir, dirPath);
|
|
85015
|
-
if (!item)
|
|
85016
|
-
return;
|
|
85017
|
-
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
|
|
85018
|
-
sessionId: session2.sessionId,
|
|
85019
|
-
machineId: session2.machineId,
|
|
85020
|
-
workingDir,
|
|
85021
|
-
dirPath: item.dirPath,
|
|
85022
|
-
data: item.data,
|
|
85023
|
-
dataHash: item.dataHash,
|
|
85024
|
-
scannedAt: item.scannedAt,
|
|
85025
|
-
truncated: item.truncated,
|
|
85026
|
-
totalCount: item.totalCount
|
|
85027
|
-
});
|
|
85028
|
-
markItemsSynced(workingDir, [item]);
|
|
85029
|
-
}
|
|
85030
|
-
async function syncDirListingsToBackend(session2, workingDir, dirPaths) {
|
|
85031
|
-
const unique = [...new Set(dirPaths)];
|
|
85032
|
-
if (unique.length === 0)
|
|
85033
|
-
return;
|
|
85034
|
-
if (unique.length === 1) {
|
|
85035
|
-
const dirPath = unique[0];
|
|
85036
|
-
if (dirPath !== undefined) {
|
|
85037
|
-
await syncDirListingToBackend(session2, workingDir, dirPath);
|
|
85038
|
-
}
|
|
85039
|
-
return;
|
|
85040
|
-
}
|
|
85041
|
-
const items = await scanDirListingsWithConcurrency(workingDir, unique);
|
|
85042
|
-
if (items.length === 0)
|
|
85043
|
-
return;
|
|
85044
|
-
for (let i2 = 0;i2 < items.length; i2 += MAX_BATCH_SIZE) {
|
|
85045
|
-
const chunk2 = items.slice(i2, i2 + MAX_BATCH_SIZE);
|
|
85046
|
-
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2Batch, {
|
|
85047
|
-
sessionId: session2.sessionId,
|
|
85048
|
-
machineId: session2.machineId,
|
|
85049
|
-
workingDir,
|
|
85050
|
-
items: chunk2
|
|
85051
|
-
});
|
|
85052
|
-
markItemsSynced(workingDir, chunk2);
|
|
85053
|
-
}
|
|
85054
|
-
}
|
|
85055
|
-
var MAX_BATCH_SIZE = 25, SCAN_CONCURRENCY = 4, lastSyncedContentHash;
|
|
85056
|
-
var init_dir_listing_sync = __esm(() => {
|
|
85057
|
-
init_dir_listing_content_hash();
|
|
85058
|
-
init_dir_listing_scanner();
|
|
85059
|
-
init_api3();
|
|
85060
|
-
lastSyncedContentHash = new Map;
|
|
85061
|
-
});
|
|
85062
|
-
|
|
85063
|
-
// src/infrastructure/services/workspace/workspace-file-search.ts
|
|
85064
|
-
import { promises as fsPromises2 } from "node:fs";
|
|
85065
|
-
import path4 from "node:path";
|
|
85066
|
-
async function searchWorkspaceFiles(rootDir, query, options) {
|
|
85067
|
-
const maxResults = options?.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
85068
|
-
const scannedAt = Date.now();
|
|
85069
|
-
const normalizedQuery = query.trim().toLowerCase();
|
|
85070
|
-
const matches = [];
|
|
85071
|
-
let visitedDirs = 0;
|
|
85072
|
-
let truncated = false;
|
|
85073
|
-
async function visitDir(relDir) {
|
|
85074
|
-
if (visitedDirs >= MAX_VISIT_DIRS || matches.length >= maxResults) {
|
|
85075
|
-
truncated = true;
|
|
85076
|
-
return;
|
|
85077
|
-
}
|
|
85078
|
-
visitedDirs++;
|
|
85079
|
-
const absDir = relDir ? path4.join(rootDir, relDir) : rootDir;
|
|
85080
|
-
let dirents;
|
|
85081
|
-
try {
|
|
85082
|
-
dirents = await fsPromises2.readdir(absDir, { withFileTypes: true });
|
|
85083
|
-
} catch {
|
|
85084
|
-
return;
|
|
85085
|
-
}
|
|
85086
|
-
const fileCandidates = [];
|
|
85087
|
-
const subdirs = [];
|
|
85088
|
-
for (const ent of dirents) {
|
|
85089
|
-
if (isAlwaysExcludedDirName(ent.name))
|
|
85090
|
-
continue;
|
|
85091
|
-
const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
|
|
85092
|
-
if (!isPathVisible(relativePath))
|
|
85093
|
-
continue;
|
|
85094
|
-
if (ent.isDirectory()) {
|
|
85095
|
-
subdirs.push(relativePath);
|
|
85096
|
-
} else if (ent.isFile()) {
|
|
85097
|
-
fileCandidates.push(relativePath);
|
|
85098
|
-
}
|
|
85099
|
-
}
|
|
85100
|
-
const ignored = await filterGitIgnored(rootDir, fileCandidates);
|
|
85101
|
-
for (const filePath of fileCandidates) {
|
|
85102
|
-
if (ignored.has(filePath))
|
|
85103
|
-
continue;
|
|
85104
|
-
const fileName = path4.basename(filePath).toLowerCase();
|
|
85105
|
-
if (normalizedQuery === "" || fileName.includes(normalizedQuery)) {
|
|
85106
|
-
matches.push({ path: filePath, type: "file" });
|
|
85107
|
-
if (matches.length >= maxResults) {
|
|
85108
|
-
truncated = true;
|
|
85109
|
-
return;
|
|
85110
|
-
}
|
|
85111
|
-
}
|
|
85112
|
-
}
|
|
85113
|
-
for (const sub of subdirs) {
|
|
85114
|
-
if (matches.length >= maxResults || visitedDirs >= MAX_VISIT_DIRS) {
|
|
85115
|
-
truncated = true;
|
|
85116
|
-
return;
|
|
85117
|
-
}
|
|
85118
|
-
await visitDir(sub);
|
|
85119
|
-
}
|
|
85120
|
-
}
|
|
85121
|
-
await visitDir("");
|
|
85122
|
-
return {
|
|
85123
|
-
query,
|
|
85124
|
-
entries: matches,
|
|
85125
|
-
scannedAt,
|
|
85126
|
-
truncated,
|
|
85127
|
-
totalCount: matches.length
|
|
85128
|
-
};
|
|
85129
|
-
}
|
|
85130
|
-
var DEFAULT_MAX_RESULTS = 300, MAX_VISIT_DIRS = 2000;
|
|
85131
|
-
var init_workspace_file_search = __esm(() => {
|
|
85132
|
-
init_workspace_visibility_policy();
|
|
85133
|
-
});
|
|
85134
|
-
|
|
85135
|
-
// src/commands/machine/daemon-start/dir-listing-subscription.ts
|
|
85136
|
-
import { createHash as createHash3 } from "node:crypto";
|
|
85137
|
-
import { gzipSync as gzipSync2 } from "node:zlib";
|
|
85138
|
-
function logSubscriptionWarn(label, err) {
|
|
85139
|
-
console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage2(err)}`);
|
|
85140
|
-
}
|
|
85141
|
-
async function uploadDirListing(session2, workingDir, dirPath) {
|
|
85142
|
-
await syncDirListingToBackend(session2, workingDir, dirPath);
|
|
85143
|
-
await session2.backend.mutation(api.workspaceFiles.fulfillDirListingRequest, {
|
|
85144
|
-
sessionId: session2.sessionId,
|
|
85145
|
-
machineId: session2.machineId,
|
|
85146
|
-
workingDir,
|
|
85147
|
-
dirPath
|
|
85148
|
-
});
|
|
85149
|
-
}
|
|
85150
|
-
async function uploadFileSearch(session2, workingDir, query) {
|
|
85151
|
-
const result = await searchWorkspaceFiles(workingDir, query);
|
|
85152
|
-
const json = JSON.stringify(result);
|
|
85153
|
-
const dataHash = createHash3("md5").update(json).digest("hex");
|
|
85154
|
-
const compressed = gzipSync2(Buffer.from(json)).toString("base64");
|
|
85155
|
-
await session2.backend.mutation(api.workspaceFiles.syncFileSearchV2, {
|
|
85156
|
-
sessionId: session2.sessionId,
|
|
85157
|
-
machineId: session2.machineId,
|
|
85158
|
-
workingDir,
|
|
85159
|
-
query,
|
|
85160
|
-
data: { compression: "gzip", content: compressed },
|
|
85161
|
-
dataHash,
|
|
85162
|
-
scannedAt: result.scannedAt,
|
|
85163
|
-
truncated: result.truncated,
|
|
85164
|
-
totalCount: result.totalCount
|
|
85165
|
-
});
|
|
85166
|
-
await session2.backend.mutation(api.workspaceFiles.fulfillFileSearchRequest, {
|
|
85167
|
-
sessionId: session2.sessionId,
|
|
85168
|
-
machineId: session2.machineId,
|
|
85169
|
-
workingDir,
|
|
85170
|
-
query
|
|
85171
|
-
});
|
|
85172
|
-
}
|
|
85173
|
-
var fulfillDirListingRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
85174
|
-
for (const request2 of requests) {
|
|
85175
|
-
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
85176
|
-
const start3 = Date.now();
|
|
85177
|
-
yield* exports_Effect.tryPromise(() => uploadDirListing(session2, request2.workingDir, request2.dirPath));
|
|
85178
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing fulfilled: ${request2.workingDir}/${request2.dirPath || "(root)"} (${Date.now() - start3}ms)`);
|
|
85179
|
-
}), (err) => {
|
|
85180
|
-
logSubscriptionWarn(`Dir listing failed for ${request2.workingDir}/${request2.dirPath}`, err);
|
|
85181
|
-
return exports_Effect.void;
|
|
85182
|
-
});
|
|
85183
|
-
}
|
|
85184
|
-
}), fulfillFileSearchRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
85185
|
-
for (const request2 of requests) {
|
|
85186
|
-
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
85187
|
-
const start3 = Date.now();
|
|
85188
|
-
yield* exports_Effect.tryPromise(() => uploadFileSearch(session2, request2.workingDir, request2.query));
|
|
85189
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD0D File search fulfilled: ${request2.workingDir} query="${request2.query}" (${Date.now() - start3}ms)`);
|
|
85190
|
-
}), (err) => {
|
|
85191
|
-
logSubscriptionWarn(`File search failed for ${request2.workingDir}`, err);
|
|
85192
|
-
return exports_Effect.void;
|
|
85193
|
-
});
|
|
85194
|
-
}
|
|
85195
|
-
}), startDirListingSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
85196
|
-
const session2 = yield* DaemonSessionService;
|
|
85197
|
-
let processingDir = false;
|
|
85198
|
-
let processingSearch = false;
|
|
85199
|
-
const unsubDir = wsClient2.onUpdate(api.workspaceFiles.getPendingDirListingRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
85200
|
-
if (!requests?.length || processingDir)
|
|
85201
|
-
return;
|
|
85202
|
-
processingDir = true;
|
|
85203
|
-
exports_Effect.runPromise(fulfillDirListingRequestsEffect(session2, requests)).catch((err) => {
|
|
85204
|
-
logSubscriptionWarn("Dir listing subscription processing failed", err);
|
|
85205
|
-
}).finally(() => {
|
|
85206
|
-
processingDir = false;
|
|
85207
|
-
});
|
|
85208
|
-
}, (err) => {
|
|
85209
|
-
logSubscriptionWarn("Dir listing subscription error", err);
|
|
85210
|
-
});
|
|
85211
|
-
const unsubSearch = wsClient2.onUpdate(api.workspaceFiles.getPendingFileSearchRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
85212
|
-
if (!requests?.length || processingSearch)
|
|
85213
|
-
return;
|
|
85214
|
-
processingSearch = true;
|
|
85215
|
-
exports_Effect.runPromise(fulfillFileSearchRequestsEffect(session2, requests)).catch((err) => {
|
|
85216
|
-
logSubscriptionWarn("File search subscription processing failed", err);
|
|
85217
|
-
}).finally(() => {
|
|
85218
|
-
processingSearch = false;
|
|
85219
|
-
});
|
|
85220
|
-
}, (err) => {
|
|
85221
|
-
logSubscriptionWarn("File search subscription error", err);
|
|
85222
|
-
});
|
|
85223
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription started (reactive)`);
|
|
85224
|
-
return {
|
|
85225
|
-
stop: () => {
|
|
85226
|
-
unsubDir();
|
|
85227
|
-
unsubSearch();
|
|
85228
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription stopped`);
|
|
85229
|
-
}
|
|
85230
|
-
};
|
|
85231
|
-
});
|
|
85232
|
-
var init_dir_listing_subscription = __esm(() => {
|
|
85233
|
-
init_esm();
|
|
85234
|
-
init_daemon_services();
|
|
85235
|
-
init_api3();
|
|
85236
|
-
init_dir_listing_sync();
|
|
85237
|
-
init_workspace_file_search();
|
|
85238
|
-
init_convex_error();
|
|
85239
|
-
});
|
|
85240
|
-
|
|
85241
|
-
// src/infrastructure/services/workspace/workspace-fs-watch-paths.ts
|
|
85242
|
-
function parentDirPath(relativePath) {
|
|
85243
|
-
const normalized = relativePath.replace(/\\/g, "/");
|
|
85244
|
-
const idx = normalized.lastIndexOf("/");
|
|
85245
|
-
return idx === -1 ? "" : normalized.slice(0, idx);
|
|
85246
|
-
}
|
|
85247
|
-
function shouldIgnoreWatchRelativePath(relativePath) {
|
|
85248
|
-
const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
85249
|
-
if (!normalized || normalized === ".")
|
|
85250
|
-
return false;
|
|
85251
|
-
return hasExcludedDirSegment(normalized);
|
|
85252
|
-
}
|
|
85253
|
-
function dirsToRefreshForEvent(relativePath, isDirectory = false) {
|
|
85254
|
-
const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
85255
|
-
if (!normalized || normalized === ".")
|
|
85256
|
-
return [""];
|
|
85257
|
-
const dirs = new Set;
|
|
85258
|
-
dirs.add(parentDirPath(normalized));
|
|
85259
|
-
if (isDirectory)
|
|
85260
|
-
dirs.add(normalized);
|
|
85261
|
-
return [...dirs];
|
|
85262
|
-
}
|
|
85263
|
-
function filterDirsByActiveSet(dirs, activeDirPaths) {
|
|
85264
|
-
return dirs.filter((d) => activeDirPaths.has(d));
|
|
85265
|
-
}
|
|
85266
|
-
var init_workspace_fs_watch_paths = __esm(() => {
|
|
85267
|
-
init_workspace_visibility_policy();
|
|
85268
|
-
});
|
|
85269
|
-
|
|
85270
|
-
// src/infrastructure/services/workspace/workspace-fs-watcher.ts
|
|
85271
|
-
import { watch } from "node:fs";
|
|
85272
|
-
import path5 from "node:path";
|
|
85273
|
-
function isRecursiveWatchPlatform() {
|
|
85274
|
-
return process.platform === "darwin" || process.platform === "win32";
|
|
85275
|
-
}
|
|
85276
|
-
function normalizeFilename(filename) {
|
|
85277
|
-
if (filename == null)
|
|
85278
|
-
return null;
|
|
85279
|
-
const value = typeof filename === "string" ? filename : filename.toString();
|
|
85280
|
-
if (!value || value === "." || value === "..")
|
|
85281
|
-
return null;
|
|
85282
|
-
return value.replace(/\\/g, "/");
|
|
85283
|
-
}
|
|
85284
|
-
function createWorkspaceFsWatcher(options) {
|
|
85285
|
-
const absWorkingDir = path5.resolve(options.workingDir);
|
|
85286
|
-
const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
85287
|
-
let activeDirPaths = new Set(options.activeDirPaths);
|
|
85288
|
-
let stopped = false;
|
|
85289
|
-
let debounceTimer = null;
|
|
85290
|
-
const pendingDirs = new Set;
|
|
85291
|
-
let rootWatcher = null;
|
|
85292
|
-
const dirWatchers = new Map;
|
|
85293
|
-
const scheduleFlush = () => {
|
|
85294
|
-
if (debounceTimer)
|
|
85295
|
-
clearTimeout(debounceTimer);
|
|
85296
|
-
debounceTimer = setTimeout(() => {
|
|
85297
|
-
debounceTimer = null;
|
|
85298
|
-
if (pendingDirs.size === 0)
|
|
85299
|
-
return;
|
|
85300
|
-
const dirs = [...pendingDirs];
|
|
85301
|
-
pendingDirs.clear();
|
|
85302
|
-
Promise.resolve(options.onRefreshDirs(dirs));
|
|
85303
|
-
}, debounceMs);
|
|
85304
|
-
debounceTimer.unref?.();
|
|
85305
|
-
};
|
|
85306
|
-
const enqueueDirs = (dirs) => {
|
|
85307
|
-
for (const dir of dirs)
|
|
85308
|
-
pendingDirs.add(dir);
|
|
85309
|
-
scheduleFlush();
|
|
85310
|
-
};
|
|
85311
|
-
const handleRelativePath = (relativePath, isDirectory = false) => {
|
|
85312
|
-
if (stopped)
|
|
85313
|
-
return;
|
|
85314
|
-
if (shouldIgnoreWatchRelativePath(relativePath))
|
|
85315
|
-
return;
|
|
85316
|
-
const toRefresh = filterDirsByActiveSet(dirsToRefreshForEvent(relativePath, isDirectory), activeDirPaths);
|
|
85317
|
-
if (toRefresh.length > 0)
|
|
85318
|
-
enqueueDirs(toRefresh);
|
|
85319
|
-
};
|
|
85320
|
-
const onWatchEvent = (watchedDirPath, filename) => {
|
|
85321
|
-
const normalizedFilename = normalizeFilename(filename);
|
|
85322
|
-
if (!normalizedFilename)
|
|
85323
|
-
return;
|
|
85324
|
-
let relativePath;
|
|
85325
|
-
if (isRecursiveWatchPlatform()) {
|
|
85326
|
-
relativePath = normalizedFilename;
|
|
85327
|
-
} else if (watchedDirPath === "") {
|
|
85328
|
-
relativePath = normalizedFilename;
|
|
85329
|
-
} else {
|
|
85330
|
-
relativePath = `${watchedDirPath}/${normalizedFilename}`;
|
|
85331
|
-
}
|
|
85332
|
-
const isDirectory = relativePath.endsWith("/");
|
|
85333
|
-
handleRelativePath(relativePath.replace(/\/+$/, ""), isDirectory);
|
|
85334
|
-
};
|
|
85335
|
-
const closePerDirWatchers = () => {
|
|
85336
|
-
for (const watcher of dirWatchers.values())
|
|
85337
|
-
watcher.close();
|
|
85338
|
-
dirWatchers.clear();
|
|
85339
|
-
};
|
|
85340
|
-
const startPerDirWatch = (dirPath) => {
|
|
85341
|
-
if (dirPath === "" || dirWatchers.has(dirPath))
|
|
85342
|
-
return;
|
|
85343
|
-
const absDir = path5.join(absWorkingDir, dirPath);
|
|
85344
|
-
const watcher = watch(absDir, (_eventType, filename) => {
|
|
85345
|
-
onWatchEvent(dirPath, filename);
|
|
85346
|
-
});
|
|
85347
|
-
dirWatchers.set(dirPath, watcher);
|
|
85348
|
-
};
|
|
85349
|
-
const rewirePerDirWatches = () => {
|
|
85350
|
-
const wanted = new Set;
|
|
85351
|
-
for (const dirPath of activeDirPaths) {
|
|
85352
|
-
if (dirPath !== "")
|
|
85353
|
-
wanted.add(dirPath);
|
|
85354
|
-
}
|
|
85355
|
-
for (const [dirPath, watcher] of dirWatchers) {
|
|
85356
|
-
if (!wanted.has(dirPath)) {
|
|
85357
|
-
watcher.close();
|
|
85358
|
-
dirWatchers.delete(dirPath);
|
|
85359
|
-
}
|
|
85360
|
-
}
|
|
85361
|
-
for (const dirPath of wanted) {
|
|
85362
|
-
if (!dirWatchers.has(dirPath))
|
|
85363
|
-
startPerDirWatch(dirPath);
|
|
85364
|
-
}
|
|
85365
|
-
};
|
|
85366
|
-
const startWatching = () => {
|
|
85367
|
-
if (isRecursiveWatchPlatform()) {
|
|
85368
|
-
rootWatcher = watch(absWorkingDir, { recursive: true }, (_eventType, filename) => {
|
|
85369
|
-
onWatchEvent("", filename);
|
|
85370
|
-
});
|
|
85371
|
-
return;
|
|
85372
|
-
}
|
|
85373
|
-
rootWatcher = watch(absWorkingDir, (_eventType, filename) => {
|
|
85374
|
-
onWatchEvent("", filename);
|
|
85375
|
-
});
|
|
85376
|
-
rewirePerDirWatches();
|
|
85377
|
-
};
|
|
85378
|
-
startWatching();
|
|
85379
|
-
return {
|
|
85380
|
-
updateActiveDirPaths: (paths) => {
|
|
85381
|
-
activeDirPaths = new Set(paths);
|
|
85382
|
-
if (!isRecursiveWatchPlatform() && !stopped) {
|
|
85383
|
-
rewirePerDirWatches();
|
|
85384
|
-
}
|
|
85385
|
-
},
|
|
85386
|
-
stop: () => {
|
|
85387
|
-
stopped = true;
|
|
85388
|
-
if (debounceTimer) {
|
|
85389
|
-
clearTimeout(debounceTimer);
|
|
85390
|
-
debounceTimer = null;
|
|
85391
|
-
}
|
|
85392
|
-
rootWatcher?.close();
|
|
85393
|
-
rootWatcher = null;
|
|
85394
|
-
closePerDirWatchers();
|
|
85395
|
-
pendingDirs.clear();
|
|
85396
|
-
}
|
|
85397
|
-
};
|
|
85398
|
-
}
|
|
85399
|
-
var DEFAULT_DEBOUNCE_MS = 400;
|
|
85400
|
-
var init_workspace_fs_watcher = __esm(() => {
|
|
85401
|
-
init_workspace_fs_watch_paths();
|
|
85402
|
-
});
|
|
85403
|
-
|
|
85404
|
-
// src/commands/machine/daemon-start/dir-listing-watch-subscription.ts
|
|
85405
|
-
var startDirListingWatchSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
85406
|
-
const session2 = yield* DaemonSessionService;
|
|
85407
|
-
const watchers = new Map;
|
|
85408
|
-
const applyTargets = (targets) => {
|
|
85409
|
-
const nextWorkingDirs = new Set(targets.map((t) => t.workingDir));
|
|
85410
|
-
for (const [workingDir, handle] of watchers) {
|
|
85411
|
-
if (!nextWorkingDirs.has(workingDir)) {
|
|
85412
|
-
handle.stop();
|
|
85413
|
-
watchers.delete(workingDir);
|
|
85414
|
-
}
|
|
85415
|
-
}
|
|
85416
|
-
for (const target of targets) {
|
|
85417
|
-
const activeSet = new Set(target.activeDirPaths);
|
|
85418
|
-
const existing = watchers.get(target.workingDir);
|
|
85419
|
-
if (existing) {
|
|
85420
|
-
existing.updateActiveDirPaths(activeSet);
|
|
85421
|
-
continue;
|
|
85422
|
-
}
|
|
85423
|
-
const handle = createWorkspaceFsWatcher({
|
|
85424
|
-
workingDir: target.workingDir,
|
|
85425
|
-
activeDirPaths: activeSet,
|
|
85426
|
-
onRefreshDirs: async (dirPaths) => {
|
|
85427
|
-
try {
|
|
85428
|
-
await syncDirListingsToBackend(session2, target.workingDir, dirPaths);
|
|
85429
|
-
} catch (err) {
|
|
85430
|
-
console.warn(`[${formatTimestamp()}] ⚠️ FS watch sync failed for ${target.workingDir}: ${getErrorMessage2(err)}`);
|
|
85431
|
-
}
|
|
85432
|
-
}
|
|
85433
|
-
});
|
|
85434
|
-
watchers.set(target.workingDir, handle);
|
|
85435
|
-
}
|
|
85436
|
-
};
|
|
85437
|
-
let stopped = false;
|
|
85438
|
-
const unsub = wsClient2.onUpdate(api.workspaceFiles.listDirListingWatchTargets, { sessionId: session2.sessionId, machineId: session2.machineId }, (targets) => {
|
|
85439
|
-
if (stopped)
|
|
85440
|
-
return;
|
|
85441
|
-
applyTargets(targets ?? []);
|
|
85442
|
-
}, (err) => {
|
|
85443
|
-
console.warn(`[${formatTimestamp()}] ⚠️ Dir listing watch subscription error: ${getErrorMessage2(err)}`);
|
|
85444
|
-
});
|
|
85445
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription started`);
|
|
85446
|
-
return {
|
|
85447
|
-
stop: () => {
|
|
85448
|
-
stopped = true;
|
|
85449
|
-
unsub();
|
|
85450
|
-
for (const handle of watchers.values())
|
|
85451
|
-
handle.stop();
|
|
85452
|
-
watchers.clear();
|
|
85453
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription stopped`);
|
|
85454
|
-
}
|
|
85455
|
-
};
|
|
85456
|
-
});
|
|
85457
|
-
var init_dir_listing_watch_subscription = __esm(() => {
|
|
85458
|
-
init_esm();
|
|
85459
|
-
init_daemon_services();
|
|
85460
|
-
init_api3();
|
|
85461
|
-
init_dir_listing_sync();
|
|
85462
|
-
init_workspace_fs_watcher();
|
|
85463
|
-
init_convex_error();
|
|
85464
|
-
});
|
|
85465
|
-
|
|
85466
84707
|
// src/events/daemon/agent/on-request-start-agent.ts
|
|
85467
84708
|
function notifyAgentStartFailed(backend2, opts) {
|
|
85468
84709
|
backend2.mutation(api.machines.emitAgentStartFailed, opts).catch((err) => {
|
|
@@ -85562,8 +84803,13 @@ var init_on_request_stop_agent = __esm(() => {
|
|
|
85562
84803
|
init_stop_agent();
|
|
85563
84804
|
});
|
|
85564
84805
|
|
|
84806
|
+
// src/commands/machine/daemon-start/utils.ts
|
|
84807
|
+
function formatTimestamp() {
|
|
84808
|
+
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
84809
|
+
}
|
|
84810
|
+
|
|
85565
84811
|
// src/commands/machine/daemon-start/handlers/orphan-tracker.ts
|
|
85566
|
-
import { createHash as
|
|
84812
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
85567
84813
|
import {
|
|
85568
84814
|
appendFileSync,
|
|
85569
84815
|
existsSync as existsSync5,
|
|
@@ -85577,7 +84823,7 @@ import { homedir as homedir5 } from "node:os";
|
|
|
85577
84823
|
import { join as join15 } from "node:path";
|
|
85578
84824
|
function getUrlHash() {
|
|
85579
84825
|
const url2 = getConvexUrl();
|
|
85580
|
-
return
|
|
84826
|
+
return createHash2("sha256").update(url2).digest("hex").substring(0, 8);
|
|
85581
84827
|
}
|
|
85582
84828
|
function getChildPidsFilePath() {
|
|
85583
84829
|
const dir = join15(homedir5(), ".chatroom");
|
|
@@ -85771,19 +85017,19 @@ class ProcessManager {
|
|
|
85771
85017
|
this.pendingStops.clear();
|
|
85772
85018
|
}
|
|
85773
85019
|
waitForExit(runId, ms) {
|
|
85774
|
-
return new Promise((
|
|
85020
|
+
return new Promise((resolve4) => {
|
|
85775
85021
|
const interval = 100;
|
|
85776
85022
|
let elapsed3 = 0;
|
|
85777
85023
|
const timer = setInterval(() => {
|
|
85778
85024
|
if (!this.runningProcesses.has(runId)) {
|
|
85779
85025
|
clearInterval(timer);
|
|
85780
|
-
|
|
85026
|
+
resolve4(true);
|
|
85781
85027
|
return;
|
|
85782
85028
|
}
|
|
85783
85029
|
elapsed3 += interval;
|
|
85784
85030
|
if (elapsed3 >= ms) {
|
|
85785
85031
|
clearInterval(timer);
|
|
85786
|
-
|
|
85032
|
+
resolve4(false);
|
|
85787
85033
|
}
|
|
85788
85034
|
}, interval);
|
|
85789
85035
|
});
|
|
@@ -85818,9 +85064,9 @@ var init_killer = __esm(() => {
|
|
|
85818
85064
|
});
|
|
85819
85065
|
|
|
85820
85066
|
// ../../services/backend/src/output-encoding.ts
|
|
85821
|
-
import { gunzipSync
|
|
85067
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
85822
85068
|
function encodeOutput(plain) {
|
|
85823
|
-
const compressed =
|
|
85069
|
+
const compressed = gzipSync(Buffer.from(plain, "utf-8"));
|
|
85824
85070
|
return {
|
|
85825
85071
|
compression: "gzip",
|
|
85826
85072
|
content: compressed.toString("base64")
|
|
@@ -85998,7 +85244,7 @@ var init_output_store = __esm(() => {
|
|
|
85998
85244
|
});
|
|
85999
85245
|
|
|
86000
85246
|
// src/commands/machine/daemon-start/handlers/process/spawner.ts
|
|
86001
|
-
import { spawn as
|
|
85247
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
86002
85248
|
async function flushTailV2(deps, tracked, force = false) {
|
|
86003
85249
|
if (!force && !isRunLogObserved(tracked.runId))
|
|
86004
85250
|
return;
|
|
@@ -86081,7 +85327,7 @@ async function spawnCommandProcess(deps, event, commandKey) {
|
|
|
86081
85327
|
tempDirReady = true;
|
|
86082
85328
|
}
|
|
86083
85329
|
const store = createOutputStore(runIdStr);
|
|
86084
|
-
const child =
|
|
85330
|
+
const child = spawn4("sh", ["-c", script], {
|
|
86085
85331
|
cwd: workingDir,
|
|
86086
85332
|
env: buildChatroomSpawnEnv(deps.convexUrl),
|
|
86087
85333
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -86343,8 +85589,8 @@ var init_command_runner = __esm(() => {
|
|
|
86343
85589
|
}).catch((err) => {
|
|
86344
85590
|
console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as killed on shutdown: ${getErrorMessage2(err)}`);
|
|
86345
85591
|
})));
|
|
86346
|
-
yield* exports_Effect.promise(() => new Promise((
|
|
86347
|
-
const t = setTimeout(
|
|
85592
|
+
yield* exports_Effect.promise(() => new Promise((resolve4) => {
|
|
85593
|
+
const t = setTimeout(resolve4, 3000);
|
|
86348
85594
|
t.unref?.();
|
|
86349
85595
|
}));
|
|
86350
85596
|
for (const [, tracked] of trackedEntries) {
|
|
@@ -86356,8 +85602,8 @@ var init_command_runner = __esm(() => {
|
|
|
86356
85602
|
clearTrackedPids();
|
|
86357
85603
|
yield* exports_Effect.promise(() => Promise.race([
|
|
86358
85604
|
statusUpdates,
|
|
86359
|
-
new Promise((
|
|
86360
|
-
const t = setTimeout(
|
|
85605
|
+
new Promise((resolve4) => {
|
|
85606
|
+
const t = setTimeout(resolve4, 2000);
|
|
86361
85607
|
t.unref?.();
|
|
86362
85608
|
})
|
|
86363
85609
|
]));
|
|
@@ -86485,7 +85731,7 @@ var init_git = __esm(() => {
|
|
|
86485
85731
|
});
|
|
86486
85732
|
|
|
86487
85733
|
// src/infrastructure/local-actions/execute-local-action.ts
|
|
86488
|
-
import { exec as
|
|
85734
|
+
import { exec as exec2 } from "node:child_process";
|
|
86489
85735
|
import { access as access3 } from "node:fs/promises";
|
|
86490
85736
|
function escapeShellArg(arg) {
|
|
86491
85737
|
return `"${arg.replace(/"/g, "\\\"")}"`;
|
|
@@ -86494,14 +85740,14 @@ function resolveWhichCommand(name) {
|
|
|
86494
85740
|
return process.platform === "win32" ? `where ${name}` : `which ${name}`;
|
|
86495
85741
|
}
|
|
86496
85742
|
function isCliAvailable(cliName) {
|
|
86497
|
-
return new Promise((
|
|
86498
|
-
|
|
86499
|
-
|
|
85743
|
+
return new Promise((resolve4) => {
|
|
85744
|
+
exec2(resolveWhichCommand(cliName), (err) => {
|
|
85745
|
+
resolve4(!err);
|
|
86500
85746
|
});
|
|
86501
85747
|
});
|
|
86502
85748
|
}
|
|
86503
85749
|
function execFireAndForget(command, logTag) {
|
|
86504
|
-
|
|
85750
|
+
exec2(command, (err) => {
|
|
86505
85751
|
if (err) {
|
|
86506
85752
|
console.warn(`[${logTag}] exec failed: ${err.message}`);
|
|
86507
85753
|
}
|
|
@@ -86620,10 +85866,10 @@ var init_local_actions = __esm(() => {
|
|
|
86620
85866
|
import { execFileSync } from "node:child_process";
|
|
86621
85867
|
function runPicker(command, args2) {
|
|
86622
85868
|
try {
|
|
86623
|
-
const
|
|
86624
|
-
if (!
|
|
85869
|
+
const path3 = execFileSync(command, args2, { encoding: "utf8", timeout: 300000 }).trim();
|
|
85870
|
+
if (!path3)
|
|
86625
85871
|
return { success: false, error: "No folder selected" };
|
|
86626
|
-
return { success: true, path:
|
|
85872
|
+
return { success: true, path: path3 };
|
|
86627
85873
|
} catch (error) {
|
|
86628
85874
|
const exitCode = typeof error === "object" && error !== null && "status" in error ? error.status : null;
|
|
86629
85875
|
if (exitCode === 1)
|
|
@@ -86665,13 +85911,13 @@ function pickFolderDialog() {
|
|
|
86665
85911
|
var init_pick_folder = () => {};
|
|
86666
85912
|
|
|
86667
85913
|
// src/commands/machine/pid.ts
|
|
86668
|
-
import { createHash as
|
|
85914
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
86669
85915
|
import { existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
86670
85916
|
import { homedir as homedir6 } from "node:os";
|
|
86671
85917
|
import { join as join17 } from "node:path";
|
|
86672
85918
|
function getUrlHash2() {
|
|
86673
85919
|
const url2 = getConvexUrl();
|
|
86674
|
-
return
|
|
85920
|
+
return createHash3("sha256").update(url2).digest("hex").substring(0, 8);
|
|
86675
85921
|
}
|
|
86676
85922
|
function getPidFileName() {
|
|
86677
85923
|
return `daemon-${getUrlHash2()}.pid`;
|
|
@@ -86764,7 +86010,7 @@ async function waitForLockOrTimeout(deadline, intervalMs, sleep5) {
|
|
|
86764
86010
|
async function acquireLockWithRetry(options) {
|
|
86765
86011
|
const intervalMs = options?.intervalMs ?? LOCK_RETRY_INTERVAL_MS;
|
|
86766
86012
|
const maxWaitMs = options?.maxWaitMs ?? LOCK_RETRY_MAX_WAIT_MS;
|
|
86767
|
-
const sleep5 = options?.sleep ?? ((ms) => new Promise((
|
|
86013
|
+
const sleep5 = options?.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
|
|
86768
86014
|
const deadline = Date.now() + maxWaitMs;
|
|
86769
86015
|
if (await waitForLockOrTimeout(deadline, intervalMs, sleep5)) {
|
|
86770
86016
|
return true;
|
|
@@ -87130,14 +86376,14 @@ var init_sse_event_buffer = __esm(() => {
|
|
|
87130
86376
|
}
|
|
87131
86377
|
_wake() {
|
|
87132
86378
|
if (this._waiter) {
|
|
87133
|
-
const
|
|
86379
|
+
const resolve4 = this._waiter;
|
|
87134
86380
|
this._waiter = null;
|
|
87135
|
-
|
|
86381
|
+
resolve4();
|
|
87136
86382
|
}
|
|
87137
86383
|
}
|
|
87138
86384
|
_waitForData() {
|
|
87139
|
-
return new Promise((
|
|
87140
|
-
this._waiter =
|
|
86385
|
+
return new Promise((resolve4) => {
|
|
86386
|
+
this._waiter = resolve4;
|
|
87141
86387
|
});
|
|
87142
86388
|
}
|
|
87143
86389
|
[Symbol.asyncIterator]() {
|
|
@@ -87192,8 +86438,8 @@ class OpencodeSdkSession {
|
|
|
87192
86438
|
async prompt(input) {
|
|
87193
86439
|
if (this.closed)
|
|
87194
86440
|
throw new Error("Session is closed");
|
|
87195
|
-
const idlePromise = new Promise((
|
|
87196
|
-
this._idleResolve =
|
|
86441
|
+
const idlePromise = new Promise((resolve4) => {
|
|
86442
|
+
this._idleResolve = resolve4;
|
|
87197
86443
|
});
|
|
87198
86444
|
const IDLE_TIMEOUT_MS = 300000;
|
|
87199
86445
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -87277,7 +86523,7 @@ var init_opencode_session = __esm(() => {
|
|
|
87277
86523
|
});
|
|
87278
86524
|
|
|
87279
86525
|
// src/infrastructure/harnesses/opencode-sdk/opencode-harness.ts
|
|
87280
|
-
import { spawn as
|
|
86526
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
87281
86527
|
function harnessEventSessionId(event) {
|
|
87282
86528
|
const p = event.properties;
|
|
87283
86529
|
if (!p)
|
|
@@ -87524,14 +86770,14 @@ class OpencodeSdkHarness {
|
|
|
87524
86770
|
}
|
|
87525
86771
|
this.sessionListeners.clear();
|
|
87526
86772
|
this.childProcess.kill("SIGTERM");
|
|
87527
|
-
await new Promise((
|
|
86773
|
+
await new Promise((resolve4) => {
|
|
87528
86774
|
const timeout3 = setTimeout(() => {
|
|
87529
86775
|
this.childProcess.kill("SIGKILL");
|
|
87530
|
-
|
|
86776
|
+
resolve4();
|
|
87531
86777
|
}, 5000);
|
|
87532
86778
|
this.childProcess.once("exit", () => {
|
|
87533
86779
|
clearTimeout(timeout3);
|
|
87534
|
-
|
|
86780
|
+
resolve4();
|
|
87535
86781
|
});
|
|
87536
86782
|
});
|
|
87537
86783
|
}
|
|
@@ -87551,7 +86797,7 @@ class OpencodeSdkHarness {
|
|
|
87551
86797
|
}
|
|
87552
86798
|
}
|
|
87553
86799
|
var OPENCODE_COMMAND3 = "opencode", SERVE_STARTUP_TIMEOUT_MS2 = 1e4, startOpencodeSdkHarness = async (config3) => {
|
|
87554
|
-
const childProcess =
|
|
86800
|
+
const childProcess = spawn5(OPENCODE_COMMAND3, ["serve", "--print-logs"], {
|
|
87555
86801
|
cwd: config3.workingDir,
|
|
87556
86802
|
stdio: ["pipe", "pipe", "pipe"],
|
|
87557
86803
|
shell: false,
|
|
@@ -88913,10 +88159,10 @@ class BufferedJournalFactory {
|
|
|
88913
88159
|
const waitForInProgress = () => {
|
|
88914
88160
|
if (!flushInProgress)
|
|
88915
88161
|
return Promise.resolve();
|
|
88916
|
-
return new Promise((
|
|
88162
|
+
return new Promise((resolve4) => {
|
|
88917
88163
|
const check3 = () => {
|
|
88918
88164
|
if (!flushInProgress)
|
|
88919
|
-
|
|
88165
|
+
resolve4();
|
|
88920
88166
|
else
|
|
88921
88167
|
setTimeout(check3, 10);
|
|
88922
88168
|
};
|
|
@@ -89078,15 +88324,555 @@ async function assertRegisteredWorkingDir(session2, workingDir) {
|
|
|
89078
88324
|
if (!workspaces.some((w) => normalizeWorkingDirForLookup(w.workingDir) === normalizedWorkingDir)) {
|
|
89079
88325
|
return { ok: false, error: "Workspace not registered for this machine" };
|
|
89080
88326
|
}
|
|
89081
|
-
return { ok: true };
|
|
88327
|
+
return { ok: true };
|
|
88328
|
+
}
|
|
88329
|
+
var init_assert_registered_working_dir = __esm(() => {
|
|
88330
|
+
init_workspace_cache();
|
|
88331
|
+
});
|
|
88332
|
+
|
|
88333
|
+
// src/infrastructure/services/workspace/workspace-path-security.ts
|
|
88334
|
+
import { realpath as realpath2 } from "node:fs/promises";
|
|
88335
|
+
import { basename, dirname as dirname8, isAbsolute, relative, resolve as resolve4, sep } from "node:path";
|
|
88336
|
+
import { gunzipSync as gunzipSync2 } from "node:zlib";
|
|
88337
|
+
function validateRelativePathSegments(filePath) {
|
|
88338
|
+
if (filePath.includes("\x00"))
|
|
88339
|
+
return { ok: false, error: "Invalid file path" };
|
|
88340
|
+
if (filePath.includes(".."))
|
|
88341
|
+
return { ok: false, error: "Invalid file path" };
|
|
88342
|
+
if (filePath.startsWith("/"))
|
|
88343
|
+
return { ok: false, error: "Invalid file path" };
|
|
88344
|
+
return { ok: true };
|
|
88345
|
+
}
|
|
88346
|
+
function isPathInsideRoot(workspaceRoot, targetPath) {
|
|
88347
|
+
const rel = relative(workspaceRoot, targetPath);
|
|
88348
|
+
if (rel === "")
|
|
88349
|
+
return true;
|
|
88350
|
+
if (rel.startsWith("..") || rel.includes(`..${sep}`))
|
|
88351
|
+
return false;
|
|
88352
|
+
if (isAbsolute(rel))
|
|
88353
|
+
return false;
|
|
88354
|
+
return true;
|
|
88355
|
+
}
|
|
88356
|
+
async function resolvePathWithinWorkspace(workingDir, filePath) {
|
|
88357
|
+
const basic = validateRelativePathSegments(filePath);
|
|
88358
|
+
if (!basic.ok)
|
|
88359
|
+
return basic;
|
|
88360
|
+
let workspaceRoot;
|
|
88361
|
+
try {
|
|
88362
|
+
workspaceRoot = await realpath2(resolve4(workingDir));
|
|
88363
|
+
} catch {
|
|
88364
|
+
return { ok: false, error: "Working directory not found" };
|
|
88365
|
+
}
|
|
88366
|
+
const candidate = resolve4(workspaceRoot, filePath);
|
|
88367
|
+
if (!isPathInsideRoot(workspaceRoot, candidate)) {
|
|
88368
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
88369
|
+
}
|
|
88370
|
+
try {
|
|
88371
|
+
const resolved = await realpath2(candidate);
|
|
88372
|
+
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
88373
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
88374
|
+
}
|
|
88375
|
+
return { ok: true, absolutePath: resolved };
|
|
88376
|
+
} catch (err) {
|
|
88377
|
+
const code2 = err?.code;
|
|
88378
|
+
if (code2 !== "ENOENT") {
|
|
88379
|
+
return { ok: false, error: "Invalid file path" };
|
|
88380
|
+
}
|
|
88381
|
+
const parent = dirname8(candidate);
|
|
88382
|
+
if (parent === workspaceRoot || isPathInsideRoot(workspaceRoot, parent)) {
|
|
88383
|
+
try {
|
|
88384
|
+
const parentReal = await realpath2(parent);
|
|
88385
|
+
if (!isPathInsideRoot(workspaceRoot, parentReal)) {
|
|
88386
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
88387
|
+
}
|
|
88388
|
+
const resolved = resolve4(parentReal, basename(candidate));
|
|
88389
|
+
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
88390
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
88391
|
+
}
|
|
88392
|
+
return { ok: true, absolutePath: resolved };
|
|
88393
|
+
} catch {
|
|
88394
|
+
return { ok: true, absolutePath: candidate };
|
|
88395
|
+
}
|
|
88396
|
+
}
|
|
88397
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
88398
|
+
}
|
|
88399
|
+
}
|
|
88400
|
+
function gunzipBase64Payload(base64, maxBytes) {
|
|
88401
|
+
let compressed;
|
|
88402
|
+
try {
|
|
88403
|
+
compressed = Buffer.from(base64, "base64");
|
|
88404
|
+
} catch {
|
|
88405
|
+
return { ok: false, errorMessage: "Missing file data" };
|
|
88406
|
+
}
|
|
88407
|
+
if (compressed.length > maxBytes * 10) {
|
|
88408
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
88409
|
+
}
|
|
88410
|
+
try {
|
|
88411
|
+
const content = gunzipSync2(compressed, { maxOutputLength: maxBytes });
|
|
88412
|
+
if (content.length > maxBytes) {
|
|
88413
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
88414
|
+
}
|
|
88415
|
+
return { ok: true, content };
|
|
88416
|
+
} catch {
|
|
88417
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
88418
|
+
}
|
|
88419
|
+
}
|
|
88420
|
+
var init_workspace_path_security = () => {};
|
|
88421
|
+
|
|
88422
|
+
// ../../node_modules/.pnpm/ignore@7.0.5/node_modules/ignore/index.js
|
|
88423
|
+
var require_ignore = __commonJS((exports, module) => {
|
|
88424
|
+
function makeArray(subject) {
|
|
88425
|
+
return Array.isArray(subject) ? subject : [subject];
|
|
88426
|
+
}
|
|
88427
|
+
var UNDEFINED = undefined;
|
|
88428
|
+
var EMPTY = "";
|
|
88429
|
+
var SPACE = " ";
|
|
88430
|
+
var ESCAPE = "\\";
|
|
88431
|
+
var REGEX_TEST_BLANK_LINE = /^\s+$/;
|
|
88432
|
+
var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
|
|
88433
|
+
var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
|
|
88434
|
+
var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
|
|
88435
|
+
var REGEX_SPLITALL_CRLF = /\r?\n/g;
|
|
88436
|
+
var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
|
|
88437
|
+
var REGEX_TEST_TRAILING_SLASH = /\/$/;
|
|
88438
|
+
var SLASH = "/";
|
|
88439
|
+
var TMP_KEY_IGNORE = "node-ignore";
|
|
88440
|
+
if (typeof Symbol !== "undefined") {
|
|
88441
|
+
TMP_KEY_IGNORE = Symbol.for("node-ignore");
|
|
88442
|
+
}
|
|
88443
|
+
var KEY_IGNORE = TMP_KEY_IGNORE;
|
|
88444
|
+
var define = (object, key, value) => {
|
|
88445
|
+
Object.defineProperty(object, key, { value });
|
|
88446
|
+
return value;
|
|
88447
|
+
};
|
|
88448
|
+
var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
|
|
88449
|
+
var RETURN_FALSE = () => false;
|
|
88450
|
+
var sanitizeRange = (range) => range.replace(REGEX_REGEXP_RANGE, (match17, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match17 : EMPTY);
|
|
88451
|
+
var cleanRangeBackSlash = (slashes) => {
|
|
88452
|
+
const { length: length2 } = slashes;
|
|
88453
|
+
return slashes.slice(0, length2 - length2 % 2);
|
|
88454
|
+
};
|
|
88455
|
+
var REPLACERS = [
|
|
88456
|
+
[
|
|
88457
|
+
/^\uFEFF/,
|
|
88458
|
+
() => EMPTY
|
|
88459
|
+
],
|
|
88460
|
+
[
|
|
88461
|
+
/((?:\\\\)*?)(\\?\s+)$/,
|
|
88462
|
+
(_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
|
|
88463
|
+
],
|
|
88464
|
+
[
|
|
88465
|
+
/(\\+?)\s/g,
|
|
88466
|
+
(_, m1) => {
|
|
88467
|
+
const { length: length2 } = m1;
|
|
88468
|
+
return m1.slice(0, length2 - length2 % 2) + SPACE;
|
|
88469
|
+
}
|
|
88470
|
+
],
|
|
88471
|
+
[
|
|
88472
|
+
/[\\$.|*+(){^]/g,
|
|
88473
|
+
(match17) => `\\${match17}`
|
|
88474
|
+
],
|
|
88475
|
+
[
|
|
88476
|
+
/(?!\\)\?/g,
|
|
88477
|
+
() => "[^/]"
|
|
88478
|
+
],
|
|
88479
|
+
[
|
|
88480
|
+
/^\//,
|
|
88481
|
+
() => "^"
|
|
88482
|
+
],
|
|
88483
|
+
[
|
|
88484
|
+
/\//g,
|
|
88485
|
+
() => "\\/"
|
|
88486
|
+
],
|
|
88487
|
+
[
|
|
88488
|
+
/^\^*\\\*\\\*\\\//,
|
|
88489
|
+
() => "^(?:.*\\/)?"
|
|
88490
|
+
],
|
|
88491
|
+
[
|
|
88492
|
+
/^(?=[^^])/,
|
|
88493
|
+
function startingReplacer() {
|
|
88494
|
+
return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
|
|
88495
|
+
}
|
|
88496
|
+
],
|
|
88497
|
+
[
|
|
88498
|
+
/\\\/\\\*\\\*(?=\\\/|$)/g,
|
|
88499
|
+
(_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
|
|
88500
|
+
],
|
|
88501
|
+
[
|
|
88502
|
+
/(^|[^\\]+)(\\\*)+(?=.+)/g,
|
|
88503
|
+
(_, p1, p2) => {
|
|
88504
|
+
const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
|
|
88505
|
+
return p1 + unescaped;
|
|
88506
|
+
}
|
|
88507
|
+
],
|
|
88508
|
+
[
|
|
88509
|
+
/\\\\\\(?=[$.|*+(){^])/g,
|
|
88510
|
+
() => ESCAPE
|
|
88511
|
+
],
|
|
88512
|
+
[
|
|
88513
|
+
/\\\\/g,
|
|
88514
|
+
() => ESCAPE
|
|
88515
|
+
],
|
|
88516
|
+
[
|
|
88517
|
+
/(\\)?\[([^\]/]*?)(\\*)($|\])/g,
|
|
88518
|
+
(match17, leadEscape, range, endEscape, close2) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close2}` : close2 === "]" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range)}${endEscape}]` : "[]" : "[]"
|
|
88519
|
+
],
|
|
88520
|
+
[
|
|
88521
|
+
/(?:[^*])$/,
|
|
88522
|
+
(match17) => /\/$/.test(match17) ? `${match17}$` : `${match17}(?=$|\\/$)`
|
|
88523
|
+
]
|
|
88524
|
+
];
|
|
88525
|
+
var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
|
|
88526
|
+
var MODE_IGNORE = "regex";
|
|
88527
|
+
var MODE_CHECK_IGNORE = "checkRegex";
|
|
88528
|
+
var UNDERSCORE = "_";
|
|
88529
|
+
var TRAILING_WILD_CARD_REPLACERS = {
|
|
88530
|
+
[MODE_IGNORE](_, p1) {
|
|
88531
|
+
const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
|
|
88532
|
+
return `${prefix}(?=$|\\/$)`;
|
|
88533
|
+
},
|
|
88534
|
+
[MODE_CHECK_IGNORE](_, p1) {
|
|
88535
|
+
const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
|
|
88536
|
+
return `${prefix}(?=$|\\/$)`;
|
|
88537
|
+
}
|
|
88538
|
+
};
|
|
88539
|
+
var makeRegexPrefix = (pattern2) => REPLACERS.reduce((prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern2)), pattern2);
|
|
88540
|
+
var isString3 = (subject) => typeof subject === "string";
|
|
88541
|
+
var checkPattern = (pattern2) => pattern2 && isString3(pattern2) && !REGEX_TEST_BLANK_LINE.test(pattern2) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern2) && pattern2.indexOf("#") !== 0;
|
|
88542
|
+
var splitPattern = (pattern2) => pattern2.split(REGEX_SPLITALL_CRLF).filter(Boolean);
|
|
88543
|
+
|
|
88544
|
+
class IgnoreRule {
|
|
88545
|
+
constructor(pattern2, mark2, body, ignoreCase, negative, prefix) {
|
|
88546
|
+
this.pattern = pattern2;
|
|
88547
|
+
this.mark = mark2;
|
|
88548
|
+
this.negative = negative;
|
|
88549
|
+
define(this, "body", body);
|
|
88550
|
+
define(this, "ignoreCase", ignoreCase);
|
|
88551
|
+
define(this, "regexPrefix", prefix);
|
|
88552
|
+
}
|
|
88553
|
+
get regex() {
|
|
88554
|
+
const key = UNDERSCORE + MODE_IGNORE;
|
|
88555
|
+
if (this[key]) {
|
|
88556
|
+
return this[key];
|
|
88557
|
+
}
|
|
88558
|
+
return this._make(MODE_IGNORE, key);
|
|
88559
|
+
}
|
|
88560
|
+
get checkRegex() {
|
|
88561
|
+
const key = UNDERSCORE + MODE_CHECK_IGNORE;
|
|
88562
|
+
if (this[key]) {
|
|
88563
|
+
return this[key];
|
|
88564
|
+
}
|
|
88565
|
+
return this._make(MODE_CHECK_IGNORE, key);
|
|
88566
|
+
}
|
|
88567
|
+
_make(mode, key) {
|
|
88568
|
+
const str = this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD, TRAILING_WILD_CARD_REPLACERS[mode]);
|
|
88569
|
+
const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
|
|
88570
|
+
return define(this, key, regex);
|
|
88571
|
+
}
|
|
88572
|
+
}
|
|
88573
|
+
var createRule = ({
|
|
88574
|
+
pattern: pattern2,
|
|
88575
|
+
mark: mark2
|
|
88576
|
+
}, ignoreCase) => {
|
|
88577
|
+
let negative = false;
|
|
88578
|
+
let body = pattern2;
|
|
88579
|
+
if (body.indexOf("!") === 0) {
|
|
88580
|
+
negative = true;
|
|
88581
|
+
body = body.substr(1);
|
|
88582
|
+
}
|
|
88583
|
+
body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
|
|
88584
|
+
const regexPrefix = makeRegexPrefix(body);
|
|
88585
|
+
return new IgnoreRule(pattern2, mark2, body, ignoreCase, negative, regexPrefix);
|
|
88586
|
+
};
|
|
88587
|
+
|
|
88588
|
+
class RuleManager {
|
|
88589
|
+
constructor(ignoreCase) {
|
|
88590
|
+
this._ignoreCase = ignoreCase;
|
|
88591
|
+
this._rules = [];
|
|
88592
|
+
}
|
|
88593
|
+
_add(pattern2) {
|
|
88594
|
+
if (pattern2 && pattern2[KEY_IGNORE]) {
|
|
88595
|
+
this._rules = this._rules.concat(pattern2._rules._rules);
|
|
88596
|
+
this._added = true;
|
|
88597
|
+
return;
|
|
88598
|
+
}
|
|
88599
|
+
if (isString3(pattern2)) {
|
|
88600
|
+
pattern2 = {
|
|
88601
|
+
pattern: pattern2
|
|
88602
|
+
};
|
|
88603
|
+
}
|
|
88604
|
+
if (checkPattern(pattern2.pattern)) {
|
|
88605
|
+
const rule = createRule(pattern2, this._ignoreCase);
|
|
88606
|
+
this._added = true;
|
|
88607
|
+
this._rules.push(rule);
|
|
88608
|
+
}
|
|
88609
|
+
}
|
|
88610
|
+
add(pattern2) {
|
|
88611
|
+
this._added = false;
|
|
88612
|
+
makeArray(isString3(pattern2) ? splitPattern(pattern2) : pattern2).forEach(this._add, this);
|
|
88613
|
+
return this._added;
|
|
88614
|
+
}
|
|
88615
|
+
test(path3, checkUnignored, mode) {
|
|
88616
|
+
let ignored = false;
|
|
88617
|
+
let unignored = false;
|
|
88618
|
+
let matchedRule;
|
|
88619
|
+
this._rules.forEach((rule) => {
|
|
88620
|
+
const { negative } = rule;
|
|
88621
|
+
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
88622
|
+
return;
|
|
88623
|
+
}
|
|
88624
|
+
const matched = rule[mode].test(path3);
|
|
88625
|
+
if (!matched) {
|
|
88626
|
+
return;
|
|
88627
|
+
}
|
|
88628
|
+
ignored = !negative;
|
|
88629
|
+
unignored = negative;
|
|
88630
|
+
matchedRule = negative ? UNDEFINED : rule;
|
|
88631
|
+
});
|
|
88632
|
+
const ret = {
|
|
88633
|
+
ignored,
|
|
88634
|
+
unignored
|
|
88635
|
+
};
|
|
88636
|
+
if (matchedRule) {
|
|
88637
|
+
ret.rule = matchedRule;
|
|
88638
|
+
}
|
|
88639
|
+
return ret;
|
|
88640
|
+
}
|
|
88641
|
+
}
|
|
88642
|
+
var throwError = (message, Ctor) => {
|
|
88643
|
+
throw new Ctor(message);
|
|
88644
|
+
};
|
|
88645
|
+
var checkPath = (path3, originalPath, doThrow) => {
|
|
88646
|
+
if (!isString3(path3)) {
|
|
88647
|
+
return doThrow(`path must be a string, but got \`${originalPath}\``, TypeError);
|
|
88648
|
+
}
|
|
88649
|
+
if (!path3) {
|
|
88650
|
+
return doThrow(`path must not be empty`, TypeError);
|
|
88651
|
+
}
|
|
88652
|
+
if (checkPath.isNotRelative(path3)) {
|
|
88653
|
+
const r = "`path.relative()`d";
|
|
88654
|
+
return doThrow(`path should be a ${r} string, but got "${originalPath}"`, RangeError);
|
|
88655
|
+
}
|
|
88656
|
+
return true;
|
|
88657
|
+
};
|
|
88658
|
+
var isNotRelative = (path3) => REGEX_TEST_INVALID_PATH.test(path3);
|
|
88659
|
+
checkPath.isNotRelative = isNotRelative;
|
|
88660
|
+
checkPath.convert = (p) => p;
|
|
88661
|
+
|
|
88662
|
+
class Ignore {
|
|
88663
|
+
constructor({
|
|
88664
|
+
ignorecase = true,
|
|
88665
|
+
ignoreCase = ignorecase,
|
|
88666
|
+
allowRelativePaths = false
|
|
88667
|
+
} = {}) {
|
|
88668
|
+
define(this, KEY_IGNORE, true);
|
|
88669
|
+
this._rules = new RuleManager(ignoreCase);
|
|
88670
|
+
this._strictPathCheck = !allowRelativePaths;
|
|
88671
|
+
this._initCache();
|
|
88672
|
+
}
|
|
88673
|
+
_initCache() {
|
|
88674
|
+
this._ignoreCache = Object.create(null);
|
|
88675
|
+
this._testCache = Object.create(null);
|
|
88676
|
+
}
|
|
88677
|
+
add(pattern2) {
|
|
88678
|
+
if (this._rules.add(pattern2)) {
|
|
88679
|
+
this._initCache();
|
|
88680
|
+
}
|
|
88681
|
+
return this;
|
|
88682
|
+
}
|
|
88683
|
+
addPattern(pattern2) {
|
|
88684
|
+
return this.add(pattern2);
|
|
88685
|
+
}
|
|
88686
|
+
_test(originalPath, cache, checkUnignored, slices) {
|
|
88687
|
+
const path3 = originalPath && checkPath.convert(originalPath);
|
|
88688
|
+
checkPath(path3, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
|
|
88689
|
+
return this._t(path3, cache, checkUnignored, slices);
|
|
88690
|
+
}
|
|
88691
|
+
checkIgnore(path3) {
|
|
88692
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path3)) {
|
|
88693
|
+
return this.test(path3);
|
|
88694
|
+
}
|
|
88695
|
+
const slices = path3.split(SLASH).filter(Boolean);
|
|
88696
|
+
slices.pop();
|
|
88697
|
+
if (slices.length) {
|
|
88698
|
+
const parent = this._t(slices.join(SLASH) + SLASH, this._testCache, true, slices);
|
|
88699
|
+
if (parent.ignored) {
|
|
88700
|
+
return parent;
|
|
88701
|
+
}
|
|
88702
|
+
}
|
|
88703
|
+
return this._rules.test(path3, false, MODE_CHECK_IGNORE);
|
|
88704
|
+
}
|
|
88705
|
+
_t(path3, cache, checkUnignored, slices) {
|
|
88706
|
+
if (path3 in cache) {
|
|
88707
|
+
return cache[path3];
|
|
88708
|
+
}
|
|
88709
|
+
if (!slices) {
|
|
88710
|
+
slices = path3.split(SLASH).filter(Boolean);
|
|
88711
|
+
}
|
|
88712
|
+
slices.pop();
|
|
88713
|
+
if (!slices.length) {
|
|
88714
|
+
return cache[path3] = this._rules.test(path3, checkUnignored, MODE_IGNORE);
|
|
88715
|
+
}
|
|
88716
|
+
const parent = this._t(slices.join(SLASH) + SLASH, cache, checkUnignored, slices);
|
|
88717
|
+
return cache[path3] = parent.ignored ? parent : this._rules.test(path3, checkUnignored, MODE_IGNORE);
|
|
88718
|
+
}
|
|
88719
|
+
ignores(path3) {
|
|
88720
|
+
return this._test(path3, this._ignoreCache, false).ignored;
|
|
88721
|
+
}
|
|
88722
|
+
createFilter() {
|
|
88723
|
+
return (path3) => !this.ignores(path3);
|
|
88724
|
+
}
|
|
88725
|
+
filter(paths) {
|
|
88726
|
+
return makeArray(paths).filter(this.createFilter());
|
|
88727
|
+
}
|
|
88728
|
+
test(path3) {
|
|
88729
|
+
return this._test(path3, this._testCache, true);
|
|
88730
|
+
}
|
|
88731
|
+
}
|
|
88732
|
+
var factory2 = (options) => new Ignore(options);
|
|
88733
|
+
var isPathValid = (path3) => checkPath(path3 && checkPath.convert(path3), path3, RETURN_FALSE);
|
|
88734
|
+
var setupWindows = () => {
|
|
88735
|
+
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
88736
|
+
checkPath.convert = makePosix;
|
|
88737
|
+
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
88738
|
+
checkPath.isNotRelative = (path3) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path3) || isNotRelative(path3);
|
|
88739
|
+
};
|
|
88740
|
+
if (typeof process !== "undefined" && process.platform === "win32") {
|
|
88741
|
+
setupWindows();
|
|
88742
|
+
}
|
|
88743
|
+
module.exports = factory2;
|
|
88744
|
+
factory2.default = factory2;
|
|
88745
|
+
module.exports.isPathValid = isPathValid;
|
|
88746
|
+
define(module.exports, Symbol.for("setupWindows"), setupWindows);
|
|
88747
|
+
});
|
|
88748
|
+
|
|
88749
|
+
// src/infrastructure/services/workspace/workspace-ignore.ts
|
|
88750
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
88751
|
+
import path3 from "node:path";
|
|
88752
|
+
async function loadWorkspaceIgnore(rootDir) {
|
|
88753
|
+
const ig = import_ignore.default();
|
|
88754
|
+
for (const name of IGNORE_FILES) {
|
|
88755
|
+
try {
|
|
88756
|
+
const content = await readFile7(path3.join(rootDir, name), "utf-8");
|
|
88757
|
+
ig.add(content);
|
|
88758
|
+
} catch {}
|
|
88759
|
+
}
|
|
88760
|
+
return ig;
|
|
88761
|
+
}
|
|
88762
|
+
function isPathIgnoredByRules(ig, relativePath) {
|
|
88763
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
88764
|
+
return ig.ignores(normalized);
|
|
88765
|
+
}
|
|
88766
|
+
var import_ignore, IGNORE_FILES;
|
|
88767
|
+
var init_workspace_ignore = __esm(() => {
|
|
88768
|
+
import_ignore = __toESM(require_ignore(), 1);
|
|
88769
|
+
IGNORE_FILES = [".gitignore", ".cursorignore"];
|
|
88770
|
+
});
|
|
88771
|
+
|
|
88772
|
+
// src/infrastructure/services/workspace/workspace-visibility-policy.ts
|
|
88773
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
88774
|
+
function isAlwaysExcludedDirName(name) {
|
|
88775
|
+
return ALWAYS_EXCLUDE_DIR_NAMES.has(name);
|
|
88776
|
+
}
|
|
88777
|
+
function isSecretPath(relativePath) {
|
|
88778
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
88779
|
+
return SECRET_PATH_PATTERNS.some((pattern2) => pattern2.test(normalized));
|
|
88780
|
+
}
|
|
88781
|
+
function hasExcludedDirSegment(relativePath) {
|
|
88782
|
+
const segments = relativePath.split("/");
|
|
88783
|
+
return segments.some((segment) => isAlwaysExcludedDirName(segment));
|
|
88784
|
+
}
|
|
88785
|
+
function isPathVisible(relativePath) {
|
|
88786
|
+
if (!relativePath)
|
|
88787
|
+
return true;
|
|
88788
|
+
return !isSecretPath(relativePath) && !hasExcludedDirSegment(relativePath);
|
|
88789
|
+
}
|
|
88790
|
+
function isPathContentReadable(relativePath) {
|
|
88791
|
+
return isPathVisible(relativePath);
|
|
88792
|
+
}
|
|
88793
|
+
async function filterIgnoredPaths(rootDir, relativePaths) {
|
|
88794
|
+
if (relativePaths.length === 0)
|
|
88795
|
+
return new Set;
|
|
88796
|
+
const inRepo = await isGitRepo(rootDir);
|
|
88797
|
+
if (inRepo)
|
|
88798
|
+
return filterGitIgnored(rootDir, relativePaths);
|
|
88799
|
+
const ig = await loadWorkspaceIgnore(rootDir);
|
|
88800
|
+
const ignored = new Set;
|
|
88801
|
+
for (const p of relativePaths) {
|
|
88802
|
+
if (isPathIgnoredByRules(ig, p))
|
|
88803
|
+
ignored.add(p);
|
|
88804
|
+
}
|
|
88805
|
+
return ignored;
|
|
88806
|
+
}
|
|
88807
|
+
async function filterGitIgnored(rootDir, relativePaths) {
|
|
88808
|
+
if (relativePaths.length === 0)
|
|
88809
|
+
return new Set;
|
|
88810
|
+
const inRepo = await isGitRepo(rootDir);
|
|
88811
|
+
if (!inRepo)
|
|
88812
|
+
return new Set;
|
|
88813
|
+
try {
|
|
88814
|
+
const stdout = await new Promise((resolve5, reject) => {
|
|
88815
|
+
const child = spawn6("git", ["check-ignore", "--stdin", "-z"], {
|
|
88816
|
+
cwd: rootDir,
|
|
88817
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" }
|
|
88818
|
+
});
|
|
88819
|
+
let output = "";
|
|
88820
|
+
child.stdout.on("data", (chunk2) => {
|
|
88821
|
+
output += chunk2.toString();
|
|
88822
|
+
});
|
|
88823
|
+
child.on("error", reject);
|
|
88824
|
+
child.on("close", () => resolve5(output));
|
|
88825
|
+
child.stdin.write(relativePaths.join(`
|
|
88826
|
+
`));
|
|
88827
|
+
child.stdin.end();
|
|
88828
|
+
});
|
|
88829
|
+
const ignored = new Set;
|
|
88830
|
+
if (!stdout)
|
|
88831
|
+
return ignored;
|
|
88832
|
+
for (const entry of stdout.split("\x00")) {
|
|
88833
|
+
const trimmed = entry.trim();
|
|
88834
|
+
if (trimmed)
|
|
88835
|
+
ignored.add(trimmed);
|
|
88836
|
+
}
|
|
88837
|
+
return ignored;
|
|
88838
|
+
} catch {
|
|
88839
|
+
return new Set;
|
|
88840
|
+
}
|
|
89082
88841
|
}
|
|
89083
|
-
var
|
|
89084
|
-
|
|
88842
|
+
var ALWAYS_EXCLUDE_DIR_NAMES, SECRET_PATH_PATTERNS;
|
|
88843
|
+
var init_workspace_visibility_policy = __esm(() => {
|
|
88844
|
+
init_workspace_ignore();
|
|
88845
|
+
init_git_reader();
|
|
88846
|
+
ALWAYS_EXCLUDE_DIR_NAMES = new Set([
|
|
88847
|
+
"node_modules",
|
|
88848
|
+
".git",
|
|
88849
|
+
"dist",
|
|
88850
|
+
"build",
|
|
88851
|
+
".next",
|
|
88852
|
+
"coverage",
|
|
88853
|
+
"__pycache__",
|
|
88854
|
+
".turbo",
|
|
88855
|
+
".cache",
|
|
88856
|
+
".tmp",
|
|
88857
|
+
"tmp",
|
|
88858
|
+
"_generated",
|
|
88859
|
+
".vercel"
|
|
88860
|
+
]);
|
|
88861
|
+
SECRET_PATH_PATTERNS = [
|
|
88862
|
+
/^\.env$/,
|
|
88863
|
+
/^\.env\./,
|
|
88864
|
+
/\.pem$/,
|
|
88865
|
+
/\.key$/,
|
|
88866
|
+
/id_rsa$/,
|
|
88867
|
+
/credentials\.json$/,
|
|
88868
|
+
/^secrets(\/|$)/,
|
|
88869
|
+
/^\.aws(\/|$)/
|
|
88870
|
+
];
|
|
89085
88871
|
});
|
|
89086
88872
|
|
|
89087
88873
|
// src/commands/machine/daemon-start/file-content-fulfillment.ts
|
|
89088
|
-
import { readFile as
|
|
89089
|
-
import { gzipSync as
|
|
88874
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
88875
|
+
import { gzipSync as gzipSync2 } from "node:zlib";
|
|
89090
88876
|
function getErrorCause(error) {
|
|
89091
88877
|
if (typeof error === "object" && error !== null && "cause" in error && error.cause !== undefined) {
|
|
89092
88878
|
return error.cause;
|
|
@@ -89097,14 +88883,14 @@ function isENOENT(error) {
|
|
|
89097
88883
|
const cause3 = getErrorCause(error);
|
|
89098
88884
|
return typeof cause3 === "object" && cause3 !== null && "code" in cause3 && cause3.code === "ENOENT";
|
|
89099
88885
|
}
|
|
89100
|
-
function isBinaryFile(
|
|
89101
|
-
const lastDot =
|
|
88886
|
+
function isBinaryFile(path4) {
|
|
88887
|
+
const lastDot = path4.lastIndexOf(".");
|
|
89102
88888
|
if (lastDot === -1)
|
|
89103
88889
|
return false;
|
|
89104
|
-
return BINARY_EXTENSIONS.has(
|
|
88890
|
+
return BINARY_EXTENSIONS.has(path4.slice(lastDot).toLowerCase());
|
|
89105
88891
|
}
|
|
89106
88892
|
function gzipPlainText(text) {
|
|
89107
|
-
return
|
|
88893
|
+
return gzipSync2(Buffer.from(text)).toString("base64");
|
|
89108
88894
|
}
|
|
89109
88895
|
function fulfillGzippedContentEffect(session2, workingDir, filePath, plainText, truncated) {
|
|
89110
88896
|
return exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
@@ -89203,7 +88989,7 @@ var init_file_content_fulfillment = __esm(() => {
|
|
|
89203
88989
|
console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File content blocked: ${filePath} [secret] (${elapsed4}ms)`);
|
|
89204
88990
|
continue;
|
|
89205
88991
|
}
|
|
89206
|
-
const readOutcome = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() =>
|
|
88992
|
+
const readOutcome = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => readFile8(absolutePath)).pipe(exports_Effect.map((buffer) => {
|
|
89207
88993
|
if (buffer.length > MAX_CONTENT_BYTES) {
|
|
89208
88994
|
return {
|
|
89209
88995
|
kind: "ok",
|
|
@@ -89226,7 +89012,7 @@ var init_file_content_fulfillment = __esm(() => {
|
|
|
89226
89012
|
continue;
|
|
89227
89013
|
}
|
|
89228
89014
|
const { content, truncated } = readOutcome.kind === "ok" ? readOutcome : { content: readOutcome.content, truncated: readOutcome.truncated };
|
|
89229
|
-
const compressed =
|
|
89015
|
+
const compressed = gzipSync2(Buffer.from(content));
|
|
89230
89016
|
const contentCompressed = compressed.toString("base64");
|
|
89231
89017
|
yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
89232
89018
|
sessionId: session2.sessionId,
|
|
@@ -89280,15 +89066,476 @@ var init_file_content_subscription = __esm(() => {
|
|
|
89280
89066
|
init_convex_error();
|
|
89281
89067
|
});
|
|
89282
89068
|
|
|
89069
|
+
// src/infrastructure/services/workspace/file-tree-data-hash.ts
|
|
89070
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
89071
|
+
function computeFileTreeDataHash(tree) {
|
|
89072
|
+
return createHash4("md5").update(JSON.stringify(tree)).digest("hex");
|
|
89073
|
+
}
|
|
89074
|
+
var init_file_tree_data_hash = () => {};
|
|
89075
|
+
|
|
89076
|
+
// src/infrastructure/services/workspace/file-tree-partition.ts
|
|
89077
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
89078
|
+
import { gzipSync as gzipSync3 } from "node:zlib";
|
|
89079
|
+
function computeShardDataHash(payload) {
|
|
89080
|
+
return createHash5("md5").update(JSON.stringify(payload)).digest("hex");
|
|
89081
|
+
}
|
|
89082
|
+
function shardIdForPath(path4) {
|
|
89083
|
+
const slash = path4.indexOf("/");
|
|
89084
|
+
return slash === -1 ? "__root__" : path4.slice(0, slash);
|
|
89085
|
+
}
|
|
89086
|
+
function shouldUseV3Upload(tree) {
|
|
89087
|
+
return Buffer.byteLength(JSON.stringify(tree), "utf8") > MAX_TREE_JSON_BYTES;
|
|
89088
|
+
}
|
|
89089
|
+
function childShardId(path4, parentShardId) {
|
|
89090
|
+
if (parentShardId === "__root__") {
|
|
89091
|
+
return shardIdForPath(path4);
|
|
89092
|
+
}
|
|
89093
|
+
if (path4 === parentShardId) {
|
|
89094
|
+
return parentShardId;
|
|
89095
|
+
}
|
|
89096
|
+
const prefix = `${parentShardId}/`;
|
|
89097
|
+
if (!path4.startsWith(prefix)) {
|
|
89098
|
+
return parentShardId;
|
|
89099
|
+
}
|
|
89100
|
+
const remainder = path4.slice(prefix.length);
|
|
89101
|
+
const slash = remainder.indexOf("/");
|
|
89102
|
+
return slash === -1 ? parentShardId : `${parentShardId}/${remainder.slice(0, slash)}`;
|
|
89103
|
+
}
|
|
89104
|
+
function groupEntriesByShardId(entries2, parentShardId) {
|
|
89105
|
+
const groups = new Map;
|
|
89106
|
+
for (const entry of entries2) {
|
|
89107
|
+
const shardId = parentShardId === "__root__" ? shardIdForPath(entry.path) : childShardId(entry.path, parentShardId);
|
|
89108
|
+
const group = groups.get(shardId) ?? [];
|
|
89109
|
+
group.push(entry);
|
|
89110
|
+
groups.set(shardId, group);
|
|
89111
|
+
}
|
|
89112
|
+
return groups;
|
|
89113
|
+
}
|
|
89114
|
+
function buildPreparedShard(shardId, payload) {
|
|
89115
|
+
const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
|
|
89116
|
+
return {
|
|
89117
|
+
shardId,
|
|
89118
|
+
payload,
|
|
89119
|
+
dataHash: computeShardDataHash(payload),
|
|
89120
|
+
entryCount: payload.entries.length,
|
|
89121
|
+
data: { compression: "gzip", content: compressed }
|
|
89122
|
+
};
|
|
89123
|
+
}
|
|
89124
|
+
function prepareShardGroup(entries2, shardId, tree) {
|
|
89125
|
+
const payload = {
|
|
89126
|
+
entries: entries2,
|
|
89127
|
+
scannedAt: tree.scannedAt,
|
|
89128
|
+
rootDir: tree.rootDir
|
|
89129
|
+
};
|
|
89130
|
+
const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
|
|
89131
|
+
if (Buffer.byteLength(compressed, "utf8") <= MAX_SHARD_JSON_BYTES) {
|
|
89132
|
+
return [buildPreparedShard(shardId, payload)];
|
|
89133
|
+
}
|
|
89134
|
+
const subgroups = groupEntriesByShardId(entries2, shardId);
|
|
89135
|
+
if (subgroups.size <= 1) {
|
|
89136
|
+
return [buildPreparedShard(shardId, payload)];
|
|
89137
|
+
}
|
|
89138
|
+
const shards = [];
|
|
89139
|
+
for (const [subId, subEntries] of subgroups) {
|
|
89140
|
+
shards.push(...prepareShardGroup(subEntries, subId, tree));
|
|
89141
|
+
}
|
|
89142
|
+
return shards;
|
|
89143
|
+
}
|
|
89144
|
+
function partitionFileTree(tree) {
|
|
89145
|
+
const topGroups = groupEntriesByShardId(tree.entries, "__root__");
|
|
89146
|
+
const shards = [];
|
|
89147
|
+
for (const [shardId, entries2] of topGroups) {
|
|
89148
|
+
shards.push(...prepareShardGroup(entries2, shardId, tree));
|
|
89149
|
+
}
|
|
89150
|
+
return shards;
|
|
89151
|
+
}
|
|
89152
|
+
var MAX_TREE_JSON_BYTES, MAX_SHARD_JSON_BYTES, MAX_SHARD_BATCH_SIZE = 8;
|
|
89153
|
+
var init_file_tree_partition = __esm(() => {
|
|
89154
|
+
MAX_TREE_JSON_BYTES = 900 * 1024;
|
|
89155
|
+
MAX_SHARD_JSON_BYTES = 800 * 1024;
|
|
89156
|
+
});
|
|
89157
|
+
|
|
89158
|
+
// src/infrastructure/services/workspace/workspace-file-walk.ts
|
|
89159
|
+
import { promises as fsPromises } from "node:fs";
|
|
89160
|
+
import path4 from "node:path";
|
|
89161
|
+
async function walkWorkspaceFiles(rootDir, options) {
|
|
89162
|
+
const maxFilePaths = options?.maxFilePaths ?? 1e4;
|
|
89163
|
+
const filePaths = [];
|
|
89164
|
+
let truncated = false;
|
|
89165
|
+
const inRepo = await isGitRepo(rootDir);
|
|
89166
|
+
const parsedIgnore = inRepo ? null : await loadWorkspaceIgnore(rootDir);
|
|
89167
|
+
async function isIgnored(relativePath) {
|
|
89168
|
+
if (inRepo) {
|
|
89169
|
+
const ignored = await filterIgnoredPaths(rootDir, [relativePath]);
|
|
89170
|
+
return ignored.has(relativePath);
|
|
89171
|
+
}
|
|
89172
|
+
return parsedIgnore !== null && isPathIgnoredByRules(parsedIgnore, relativePath);
|
|
89173
|
+
}
|
|
89174
|
+
async function visitDir(relDir) {
|
|
89175
|
+
if (truncated || filePaths.length >= maxFilePaths) {
|
|
89176
|
+
truncated = true;
|
|
89177
|
+
return;
|
|
89178
|
+
}
|
|
89179
|
+
const absDir = relDir ? path4.join(rootDir, relDir) : rootDir;
|
|
89180
|
+
let dirents;
|
|
89181
|
+
try {
|
|
89182
|
+
dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
|
|
89183
|
+
} catch {
|
|
89184
|
+
return;
|
|
89185
|
+
}
|
|
89186
|
+
for (const ent of dirents) {
|
|
89187
|
+
if (truncated || filePaths.length >= maxFilePaths) {
|
|
89188
|
+
truncated = true;
|
|
89189
|
+
return;
|
|
89190
|
+
}
|
|
89191
|
+
if (isAlwaysExcludedDirName(ent.name))
|
|
89192
|
+
continue;
|
|
89193
|
+
const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
|
|
89194
|
+
if (!isPathVisible(relativePath))
|
|
89195
|
+
continue;
|
|
89196
|
+
if (ent.isDirectory()) {
|
|
89197
|
+
if (await isIgnored(relativePath))
|
|
89198
|
+
continue;
|
|
89199
|
+
await visitDir(relativePath);
|
|
89200
|
+
} else if (ent.isFile()) {
|
|
89201
|
+
if (await isIgnored(relativePath))
|
|
89202
|
+
continue;
|
|
89203
|
+
filePaths.push(relativePath);
|
|
89204
|
+
if (filePaths.length >= maxFilePaths)
|
|
89205
|
+
truncated = true;
|
|
89206
|
+
}
|
|
89207
|
+
}
|
|
89208
|
+
}
|
|
89209
|
+
await visitDir("");
|
|
89210
|
+
return { filePaths, truncated };
|
|
89211
|
+
}
|
|
89212
|
+
var init_workspace_file_walk = __esm(() => {
|
|
89213
|
+
init_workspace_ignore();
|
|
89214
|
+
init_workspace_visibility_policy();
|
|
89215
|
+
init_git_reader();
|
|
89216
|
+
});
|
|
89217
|
+
|
|
89218
|
+
// src/infrastructure/services/workspace/file-tree-scanner.ts
|
|
89219
|
+
async function scanFileTree(rootDir, options) {
|
|
89220
|
+
const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
89221
|
+
const scannedAt = Date.now();
|
|
89222
|
+
const walk = await walkWorkspaceFiles(rootDir, { maxFilePaths: maxEntries });
|
|
89223
|
+
const filteredPaths = walk.filePaths.filter((p) => !isExcluded(p));
|
|
89224
|
+
const entries2 = buildEntries(filteredPaths, maxEntries);
|
|
89225
|
+
return {
|
|
89226
|
+
entries: entries2,
|
|
89227
|
+
scannedAt,
|
|
89228
|
+
rootDir
|
|
89229
|
+
};
|
|
89230
|
+
}
|
|
89231
|
+
function isExcluded(filePath) {
|
|
89232
|
+
return hasExcludedDirSegment(filePath);
|
|
89233
|
+
}
|
|
89234
|
+
function buildEntries(filePaths, maxEntries) {
|
|
89235
|
+
const directories = new Set;
|
|
89236
|
+
for (const filePath of filePaths) {
|
|
89237
|
+
const parts2 = filePath.split("/");
|
|
89238
|
+
for (let i2 = 1;i2 < parts2.length; i2++) {
|
|
89239
|
+
directories.add(parts2.slice(0, i2).join("/"));
|
|
89240
|
+
}
|
|
89241
|
+
}
|
|
89242
|
+
const entries2 = [];
|
|
89243
|
+
const sortedDirs = Array.from(directories).sort();
|
|
89244
|
+
for (const dir of sortedDirs) {
|
|
89245
|
+
if (entries2.length >= maxEntries)
|
|
89246
|
+
break;
|
|
89247
|
+
entries2.push({ path: dir, type: "directory" });
|
|
89248
|
+
}
|
|
89249
|
+
const sortedFiles = filePaths.slice().sort();
|
|
89250
|
+
for (const file of sortedFiles) {
|
|
89251
|
+
if (entries2.length >= maxEntries)
|
|
89252
|
+
break;
|
|
89253
|
+
entries2.push({ path: file, type: "file" });
|
|
89254
|
+
}
|
|
89255
|
+
return entries2;
|
|
89256
|
+
}
|
|
89257
|
+
var DEFAULT_MAX_ENTRIES = 1e4;
|
|
89258
|
+
var init_file_tree_scanner = __esm(() => {
|
|
89259
|
+
init_workspace_file_walk();
|
|
89260
|
+
init_workspace_visibility_policy();
|
|
89261
|
+
});
|
|
89262
|
+
|
|
89263
|
+
// src/infrastructure/services/workspace/file-tree-v3-upload.ts
|
|
89264
|
+
async function uploadFileTreeV3(session2, workingDir, tree, syncGeneration) {
|
|
89265
|
+
const shards = partitionFileTree(tree);
|
|
89266
|
+
const shardIds = [];
|
|
89267
|
+
for (let i2 = 0;i2 < shards.length; i2 += MAX_SHARD_BATCH_SIZE) {
|
|
89268
|
+
const batch = shards.slice(i2, i2 + MAX_SHARD_BATCH_SIZE);
|
|
89269
|
+
await session2.backend.mutation(api.workspaceFiles.syncFileTreeShardV3Batch, {
|
|
89270
|
+
sessionId: session2.sessionId,
|
|
89271
|
+
machineId: session2.machineId,
|
|
89272
|
+
workingDir,
|
|
89273
|
+
syncGeneration,
|
|
89274
|
+
items: batch.map((s) => ({
|
|
89275
|
+
shardId: s.shardId,
|
|
89276
|
+
data: s.data,
|
|
89277
|
+
dataHash: s.dataHash,
|
|
89278
|
+
scannedAt: tree.scannedAt,
|
|
89279
|
+
entryCount: s.entryCount
|
|
89280
|
+
}))
|
|
89281
|
+
});
|
|
89282
|
+
for (const s of batch)
|
|
89283
|
+
shardIds.push(s.shardId);
|
|
89284
|
+
}
|
|
89285
|
+
await session2.backend.mutation(api.workspaceFiles.syncFileTreeManifestV3, {
|
|
89286
|
+
sessionId: session2.sessionId,
|
|
89287
|
+
machineId: session2.machineId,
|
|
89288
|
+
workingDir,
|
|
89289
|
+
syncGeneration,
|
|
89290
|
+
shardIds,
|
|
89291
|
+
totalEntryCount: tree.entries.length,
|
|
89292
|
+
complete: true,
|
|
89293
|
+
scannedAt: tree.scannedAt
|
|
89294
|
+
});
|
|
89295
|
+
return { shardIds, totalEntryCount: tree.entries.length };
|
|
89296
|
+
}
|
|
89297
|
+
var init_file_tree_v3_upload = __esm(() => {
|
|
89298
|
+
init_file_tree_partition();
|
|
89299
|
+
init_api3();
|
|
89300
|
+
});
|
|
89301
|
+
|
|
89302
|
+
// src/infrastructure/services/workspace/workspace-sync-diff.ts
|
|
89303
|
+
function diffPathIndexes(previous, next4) {
|
|
89304
|
+
const added = [];
|
|
89305
|
+
const removed = [];
|
|
89306
|
+
const typeChanged = [];
|
|
89307
|
+
const prev = previous ?? {};
|
|
89308
|
+
for (const [path5, type] of Object.entries(next4)) {
|
|
89309
|
+
if (!(path5 in prev)) {
|
|
89310
|
+
added.push(path5);
|
|
89311
|
+
} else if (prev[path5] !== type) {
|
|
89312
|
+
typeChanged.push(path5);
|
|
89313
|
+
}
|
|
89314
|
+
}
|
|
89315
|
+
for (const path5 of Object.keys(prev)) {
|
|
89316
|
+
if (!(path5 in next4)) {
|
|
89317
|
+
removed.push(path5);
|
|
89318
|
+
}
|
|
89319
|
+
}
|
|
89320
|
+
added.sort();
|
|
89321
|
+
removed.sort();
|
|
89322
|
+
typeChanged.sort();
|
|
89323
|
+
return { added, removed, typeChanged };
|
|
89324
|
+
}
|
|
89325
|
+
function formatPathDiffSummary(diff8) {
|
|
89326
|
+
return `+${diff8.added.length} added, -${diff8.removed.length} removed${diff8.typeChanged.length > 0 ? `, ~${diff8.typeChanged.length} type-changed` : ""}`;
|
|
89327
|
+
}
|
|
89328
|
+
|
|
89329
|
+
// src/infrastructure/services/workspace/workspace-sync-queue.ts
|
|
89330
|
+
function queueKey(machineId, workingDir) {
|
|
89331
|
+
return `${machineId}\x00${workingDir}`;
|
|
89332
|
+
}
|
|
89333
|
+
function getOrCreateState(key) {
|
|
89334
|
+
let state = queues.get(key);
|
|
89335
|
+
if (!state) {
|
|
89336
|
+
state = { running: false, trailing: false, drainPromise: null };
|
|
89337
|
+
queues.set(key, state);
|
|
89338
|
+
}
|
|
89339
|
+
return state;
|
|
89340
|
+
}
|
|
89341
|
+
async function enqueueFileTreeSync(machineId, workingDir, task) {
|
|
89342
|
+
const key = queueKey(machineId, workingDir);
|
|
89343
|
+
const state = getOrCreateState(key);
|
|
89344
|
+
if (state.running) {
|
|
89345
|
+
state.trailing = true;
|
|
89346
|
+
return state.drainPromise ?? Promise.resolve();
|
|
89347
|
+
}
|
|
89348
|
+
const run3 = async () => {
|
|
89349
|
+
state.running = true;
|
|
89350
|
+
try {
|
|
89351
|
+
do {
|
|
89352
|
+
state.trailing = false;
|
|
89353
|
+
await task();
|
|
89354
|
+
} while (state.trailing);
|
|
89355
|
+
} finally {
|
|
89356
|
+
state.running = false;
|
|
89357
|
+
state.trailing = false;
|
|
89358
|
+
if (!state.trailing) {
|
|
89359
|
+
queues.delete(key);
|
|
89360
|
+
}
|
|
89361
|
+
}
|
|
89362
|
+
};
|
|
89363
|
+
state.drainPromise = run3();
|
|
89364
|
+
return state.drainPromise;
|
|
89365
|
+
}
|
|
89366
|
+
var queues;
|
|
89367
|
+
var init_workspace_sync_queue = __esm(() => {
|
|
89368
|
+
queues = new Map;
|
|
89369
|
+
});
|
|
89370
|
+
|
|
89371
|
+
// src/infrastructure/services/workspace/workspace-sync-state.ts
|
|
89372
|
+
import { createHash as createHash6, randomUUID as randomUUID6 } from "node:crypto";
|
|
89373
|
+
import * as fs11 from "node:fs/promises";
|
|
89374
|
+
import { homedir as homedir7 } from "node:os";
|
|
89375
|
+
import { join as join18 } from "node:path";
|
|
89376
|
+
function workspaceKeyFor(workingDir) {
|
|
89377
|
+
const normalized = normalizeWorkingDirForLookup(workingDir);
|
|
89378
|
+
return createHash6("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
89379
|
+
}
|
|
89380
|
+
function buildPathIndex(entries2) {
|
|
89381
|
+
const paths = {};
|
|
89382
|
+
for (const entry of entries2) {
|
|
89383
|
+
paths[entry.path] = entry.type;
|
|
89384
|
+
}
|
|
89385
|
+
return paths;
|
|
89386
|
+
}
|
|
89387
|
+
function manifestPath(machineId, workingDir) {
|
|
89388
|
+
const key = workspaceKeyFor(workingDir);
|
|
89389
|
+
return join18(SYNC_STATE_DIR, machineId, key, "manifest.json");
|
|
89390
|
+
}
|
|
89391
|
+
async function ensureDir(filePath) {
|
|
89392
|
+
await fs11.mkdir(join18(filePath, ".."), { recursive: true, mode: 448 });
|
|
89393
|
+
}
|
|
89394
|
+
async function loadWorkspaceSyncManifest(machineId, workingDir) {
|
|
89395
|
+
try {
|
|
89396
|
+
const content = await fs11.readFile(manifestPath(machineId, workingDir), "utf-8");
|
|
89397
|
+
return JSON.parse(content);
|
|
89398
|
+
} catch (error) {
|
|
89399
|
+
if (error.code === "ENOENT")
|
|
89400
|
+
return null;
|
|
89401
|
+
return null;
|
|
89402
|
+
}
|
|
89403
|
+
}
|
|
89404
|
+
async function saveWorkspaceSyncManifest(manifest) {
|
|
89405
|
+
const filePath = manifestPath(manifest.machineId, manifest.workingDir);
|
|
89406
|
+
const tempPath = `${filePath}.tmp`;
|
|
89407
|
+
await ensureDir(filePath);
|
|
89408
|
+
const content = JSON.stringify(manifest, null, 2);
|
|
89409
|
+
await fs11.writeFile(tempPath, content, { mode: 384 });
|
|
89410
|
+
await fs11.rename(tempPath, filePath);
|
|
89411
|
+
}
|
|
89412
|
+
function createManifestFromTree(args2) {
|
|
89413
|
+
return {
|
|
89414
|
+
version: SYNC_STATE_VERSION,
|
|
89415
|
+
machineId: args2.machineId,
|
|
89416
|
+
workingDir: normalizeWorkingDirForLookup(args2.workingDir),
|
|
89417
|
+
syncGeneration: randomUUID6(),
|
|
89418
|
+
completedAt: Date.now(),
|
|
89419
|
+
scanner: args2.scanner,
|
|
89420
|
+
dataHash: args2.dataHash,
|
|
89421
|
+
totalEntryCount: args2.tree.entries.length,
|
|
89422
|
+
paths: buildPathIndex(args2.tree.entries)
|
|
89423
|
+
};
|
|
89424
|
+
}
|
|
89425
|
+
var SYNC_STATE_VERSION = "1", SYNC_STATE_DIR;
|
|
89426
|
+
var init_workspace_sync_state = __esm(() => {
|
|
89427
|
+
SYNC_STATE_DIR = join18(homedir7(), ".chatroom", "sync-state");
|
|
89428
|
+
});
|
|
89429
|
+
|
|
89430
|
+
// src/commands/machine/daemon-start/file-tree-subscription.ts
|
|
89431
|
+
import { gzipSync as gzipSync4 } from "node:zlib";
|
|
89432
|
+
function logSubscriptionWarn(label, err) {
|
|
89433
|
+
console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage2(err)}`);
|
|
89434
|
+
}
|
|
89435
|
+
async function syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration) {
|
|
89436
|
+
if (shouldUseV3Upload(tree)) {
|
|
89437
|
+
await uploadFileTreeV3(session2, normalizedWorkingDir, tree, syncGeneration);
|
|
89438
|
+
return;
|
|
89439
|
+
}
|
|
89440
|
+
const treeJson = JSON.stringify(tree);
|
|
89441
|
+
const compressed = gzipSync4(Buffer.from(treeJson)).toString("base64");
|
|
89442
|
+
await session2.backend.mutation(api.workspaceFiles.syncFileTreeV2, {
|
|
89443
|
+
sessionId: session2.sessionId,
|
|
89444
|
+
machineId: session2.machineId,
|
|
89445
|
+
workingDir: normalizedWorkingDir,
|
|
89446
|
+
data: { compression: "gzip", content: compressed },
|
|
89447
|
+
dataHash,
|
|
89448
|
+
scannedAt: tree.scannedAt
|
|
89449
|
+
});
|
|
89450
|
+
}
|
|
89451
|
+
async function uploadFileTree(session2, workingDir) {
|
|
89452
|
+
const normalizedWorkingDir = normalizeWorkingDirForLookup(workingDir);
|
|
89453
|
+
const previousManifest = await loadWorkspaceSyncManifest(session2.machineId, normalizedWorkingDir);
|
|
89454
|
+
const tree = await scanFileTree(normalizedWorkingDir);
|
|
89455
|
+
const dataHash = computeFileTreeDataHash(tree);
|
|
89456
|
+
if (previousManifest?.dataHash === dataHash) {
|
|
89457
|
+
await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
|
|
89458
|
+
sessionId: session2.sessionId,
|
|
89459
|
+
machineId: session2.machineId,
|
|
89460
|
+
workingDir: normalizedWorkingDir
|
|
89461
|
+
});
|
|
89462
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree unchanged, skipped upload: ${normalizedWorkingDir}`);
|
|
89463
|
+
return;
|
|
89464
|
+
}
|
|
89465
|
+
const pathDiff = diffPathIndexes(previousManifest?.paths, buildPathIndex(tree.entries));
|
|
89466
|
+
if (previousManifest) {
|
|
89467
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree diff: ${formatPathDiffSummary(pathDiff)} (${normalizedWorkingDir})`);
|
|
89468
|
+
}
|
|
89469
|
+
const scanner = await isGitRepo(normalizedWorkingDir) ? "git" : "filesystem";
|
|
89470
|
+
const manifest = createManifestFromTree({
|
|
89471
|
+
machineId: session2.machineId,
|
|
89472
|
+
workingDir: normalizedWorkingDir,
|
|
89473
|
+
scanner,
|
|
89474
|
+
dataHash,
|
|
89475
|
+
tree
|
|
89476
|
+
});
|
|
89477
|
+
await syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, manifest.syncGeneration);
|
|
89478
|
+
await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
|
|
89479
|
+
sessionId: session2.sessionId,
|
|
89480
|
+
machineId: session2.machineId,
|
|
89481
|
+
workingDir: normalizedWorkingDir
|
|
89482
|
+
});
|
|
89483
|
+
await saveWorkspaceSyncManifest(manifest);
|
|
89484
|
+
}
|
|
89485
|
+
var startFileTreeSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
89486
|
+
const session2 = yield* DaemonSessionService;
|
|
89487
|
+
const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.getPendingFileTreeRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
89488
|
+
if (!requests?.length)
|
|
89489
|
+
return;
|
|
89490
|
+
const uniqueDirs = [
|
|
89491
|
+
...new Set(requests.map((r) => normalizeWorkingDirForLookup(r.workingDir)))
|
|
89492
|
+
];
|
|
89493
|
+
for (const workingDir of uniqueDirs) {
|
|
89494
|
+
const normalized = normalizeWorkingDirForLookup(workingDir);
|
|
89495
|
+
enqueueFileTreeSync(session2.machineId, normalized, () => {
|
|
89496
|
+
const start3 = Date.now();
|
|
89497
|
+
return uploadFileTree(session2, normalized).then(() => {
|
|
89498
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree fulfilled: ${normalized} (${Date.now() - start3}ms)`);
|
|
89499
|
+
}).catch((err) => {
|
|
89500
|
+
logSubscriptionWarn(`File tree failed for ${normalized}`, err);
|
|
89501
|
+
});
|
|
89502
|
+
}).catch((err) => {
|
|
89503
|
+
logSubscriptionWarn("File tree queue drain failed", err);
|
|
89504
|
+
});
|
|
89505
|
+
}
|
|
89506
|
+
}, (err) => {
|
|
89507
|
+
logSubscriptionWarn("File tree subscription error", err);
|
|
89508
|
+
});
|
|
89509
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree subscription started (reactive)`);
|
|
89510
|
+
return {
|
|
89511
|
+
stop: () => {
|
|
89512
|
+
unsubscribe();
|
|
89513
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree subscription stopped`);
|
|
89514
|
+
}
|
|
89515
|
+
};
|
|
89516
|
+
});
|
|
89517
|
+
var init_file_tree_subscription = __esm(() => {
|
|
89518
|
+
init_esm();
|
|
89519
|
+
init_daemon_services();
|
|
89520
|
+
init_api3();
|
|
89521
|
+
init_git_reader();
|
|
89522
|
+
init_file_tree_data_hash();
|
|
89523
|
+
init_file_tree_partition();
|
|
89524
|
+
init_file_tree_scanner();
|
|
89525
|
+
init_file_tree_v3_upload();
|
|
89526
|
+
init_workspace_sync_queue();
|
|
89527
|
+
init_workspace_sync_state();
|
|
89528
|
+
init_convex_error();
|
|
89529
|
+
});
|
|
89530
|
+
|
|
89283
89531
|
// src/commands/machine/daemon-start/file-write-errors.ts
|
|
89284
89532
|
function unsupportedFileWriteOperationMessage(operation) {
|
|
89285
89533
|
return `Unsupported file write operation "${operation}". ` + "Please upgrade chatroom-cli to the latest version and restart the machine daemon " + "(e.g. npm install -g chatroom-cli@latest).";
|
|
89286
89534
|
}
|
|
89287
89535
|
|
|
89288
89536
|
// src/commands/machine/daemon-start/file-write-fulfillment.ts
|
|
89289
|
-
import { access as access4, mkdir as
|
|
89537
|
+
import { access as access4, mkdir as mkdir9, rename as rename5, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
|
|
89290
89538
|
import { dirname as dirname9 } from "node:path";
|
|
89291
|
-
import { gzipSync as gzipSync5 } from "node:zlib";
|
|
89292
89539
|
function isTerminalFileWriteError(errorMessage) {
|
|
89293
89540
|
const terminalMessages = new Set([
|
|
89294
89541
|
"Invalid file path",
|
|
@@ -89308,28 +89555,6 @@ function isTerminalFileWriteError(errorMessage) {
|
|
|
89308
89555
|
return true;
|
|
89309
89556
|
return terminalMessages.has(errorMessage);
|
|
89310
89557
|
}
|
|
89311
|
-
function parentDirPath2(filePath) {
|
|
89312
|
-
const idx = filePath.lastIndexOf("/");
|
|
89313
|
-
return idx === -1 ? "" : filePath.slice(0, idx);
|
|
89314
|
-
}
|
|
89315
|
-
async function syncParentDirListingAfterWrite(session2, workingDir, filePath) {
|
|
89316
|
-
const dirPath = parentDirPath2(filePath);
|
|
89317
|
-
const listing = await listDirectory(workingDir, dirPath);
|
|
89318
|
-
const json = JSON.stringify(listing);
|
|
89319
|
-
const dataHash = computeDirListingContentHash(listing);
|
|
89320
|
-
const compressed = gzipSync5(Buffer.from(json)).toString("base64");
|
|
89321
|
-
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
|
|
89322
|
-
sessionId: session2.sessionId,
|
|
89323
|
-
machineId: session2.machineId,
|
|
89324
|
-
workingDir,
|
|
89325
|
-
dirPath,
|
|
89326
|
-
data: { compression: "gzip", content: compressed },
|
|
89327
|
-
dataHash,
|
|
89328
|
-
scannedAt: listing.scannedAt,
|
|
89329
|
-
truncated: listing.truncated,
|
|
89330
|
-
totalCount: listing.totalCount
|
|
89331
|
-
});
|
|
89332
|
-
}
|
|
89333
89558
|
async function completeWriteRequest(session2, requestId, result) {
|
|
89334
89559
|
await session2.backend.mutation(api.workspaceFiles.completeFileWriteRequest, {
|
|
89335
89560
|
sessionId: session2.sessionId,
|
|
@@ -89362,9 +89587,9 @@ async function validateWriteOperation(operation, absolutePath) {
|
|
|
89362
89587
|
}
|
|
89363
89588
|
async function writePayloadToDisk(absolutePath, operation, content) {
|
|
89364
89589
|
if (operation === "create") {
|
|
89365
|
-
await
|
|
89590
|
+
await mkdir9(dirname9(absolutePath), { recursive: true });
|
|
89366
89591
|
}
|
|
89367
|
-
await
|
|
89592
|
+
await writeFile8(absolutePath, content);
|
|
89368
89593
|
}
|
|
89369
89594
|
async function fulfillOneFileWriteRequest(session2, request2) {
|
|
89370
89595
|
const startTime = Date.now();
|
|
@@ -89425,12 +89650,8 @@ async function fulfillOneFileWriteRequest(session2, request2) {
|
|
|
89425
89650
|
});
|
|
89426
89651
|
return;
|
|
89427
89652
|
}
|
|
89428
|
-
await
|
|
89429
|
-
await
|
|
89430
|
-
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
89431
|
-
if (parentDirPath2(filePath) !== parentDirPath2(request2.targetFilePath)) {
|
|
89432
|
-
await syncParentDirListingAfterWrite(session2, workingDir, request2.targetFilePath);
|
|
89433
|
-
}
|
|
89653
|
+
await mkdir9(dirname9(targetResolved.absolutePath), { recursive: true });
|
|
89654
|
+
await rename5(resolved.absolutePath, targetResolved.absolutePath);
|
|
89434
89655
|
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
89435
89656
|
const elapsed4 = Date.now() - startTime;
|
|
89436
89657
|
console.log(`[${formatTimestamp()}] ✏️ File rename fulfilled: ${filePath} → ${request2.targetFilePath} (${elapsed4}ms)`);
|
|
@@ -89445,8 +89666,7 @@ async function fulfillOneFileWriteRequest(session2, request2) {
|
|
|
89445
89666
|
});
|
|
89446
89667
|
return;
|
|
89447
89668
|
}
|
|
89448
|
-
await
|
|
89449
|
-
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
89669
|
+
await mkdir9(resolved.absolutePath, { recursive: true });
|
|
89450
89670
|
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
89451
89671
|
const elapsed4 = Date.now() - startTime;
|
|
89452
89672
|
console.log(`[${formatTimestamp()}] ✏️ Directory mkdir fulfilled: ${filePath} (${elapsed4}ms)`);
|
|
@@ -89468,8 +89688,7 @@ async function fulfillOneFileWriteRequest(session2, request2) {
|
|
|
89468
89688
|
});
|
|
89469
89689
|
return;
|
|
89470
89690
|
}
|
|
89471
|
-
await
|
|
89472
|
-
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
89691
|
+
await rm3(resolved.absolutePath, { recursive: true, force: false });
|
|
89473
89692
|
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
89474
89693
|
const elapsed4 = Date.now() - startTime;
|
|
89475
89694
|
console.log(`[${formatTimestamp()}] ✏️ File delete fulfilled: ${filePath} (${elapsed4}ms)`);
|
|
@@ -89499,7 +89718,6 @@ async function fulfillOneFileWriteRequest(session2, request2) {
|
|
|
89499
89718
|
return;
|
|
89500
89719
|
}
|
|
89501
89720
|
await writePayloadToDisk(resolved.absolutePath, operation, payload.content);
|
|
89502
|
-
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
89503
89721
|
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
89504
89722
|
const elapsed3 = Date.now() - startTime;
|
|
89505
89723
|
console.log(`[${formatTimestamp()}] ✏️ File write fulfilled: ${filePath} (${operation}, ${(payload.content.length / 1024).toFixed(1)}KB, ${elapsed3}ms)`);
|
|
@@ -89522,8 +89740,6 @@ var init_file_write_fulfillment = __esm(() => {
|
|
|
89522
89740
|
init_daemon_services();
|
|
89523
89741
|
init_api3();
|
|
89524
89742
|
init_assert_registered_working_dir();
|
|
89525
|
-
init_dir_listing_content_hash();
|
|
89526
|
-
init_dir_listing_scanner();
|
|
89527
89743
|
init_workspace_path_security();
|
|
89528
89744
|
MAX_CONTENT_BYTES2 = 512 * 1024;
|
|
89529
89745
|
fulfillFileWriteRequestsEffect = exports_Effect.gen(function* () {
|
|
@@ -89579,7 +89795,7 @@ var init_file_write_subscription = __esm(() => {
|
|
|
89579
89795
|
});
|
|
89580
89796
|
|
|
89581
89797
|
// src/infrastructure/git/git-state-pipeline.ts
|
|
89582
|
-
import { createHash as
|
|
89798
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
89583
89799
|
|
|
89584
89800
|
class GitStatePipeline {
|
|
89585
89801
|
fields;
|
|
@@ -89611,7 +89827,7 @@ class GitStatePipeline {
|
|
|
89611
89827
|
const raw = values3.get(field.key) ?? field.defaultValue;
|
|
89612
89828
|
hashInput[field.key] = field.toHashable(raw);
|
|
89613
89829
|
}
|
|
89614
|
-
return
|
|
89830
|
+
return createHash7("md5").update(JSON.stringify(hashInput)).digest("hex");
|
|
89615
89831
|
}
|
|
89616
89832
|
toMutationArgs(values3, slim) {
|
|
89617
89833
|
const args2 = {};
|
|
@@ -89941,7 +90157,7 @@ var init_git_heartbeat = __esm(() => {
|
|
|
89941
90157
|
});
|
|
89942
90158
|
|
|
89943
90159
|
// src/commands/machine/daemon-start/git-subscription.ts
|
|
89944
|
-
import { gzipSync as
|
|
90160
|
+
import { gzipSync as gzipSync5 } from "node:zlib";
|
|
89945
90161
|
function extractDiffStatFromShowOutput(content) {
|
|
89946
90162
|
for (const line of content.split(`
|
|
89947
90163
|
`)) {
|
|
@@ -89956,7 +90172,7 @@ async function processFullDiff(deps, req) {
|
|
|
89956
90172
|
if (result.status === "available" || result.status === "truncated") {
|
|
89957
90173
|
const diffStatResult = await getDiffStat(req.workingDir);
|
|
89958
90174
|
const diffStat = diffStatResult.status === "available" ? diffStatResult.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 };
|
|
89959
|
-
const compressed =
|
|
90175
|
+
const compressed = gzipSync5(Buffer.from(result.content));
|
|
89960
90176
|
const diffContentCompressed = compressed.toString("base64");
|
|
89961
90177
|
await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
|
|
89962
90178
|
sessionId: deps.sessionId,
|
|
@@ -89968,7 +90184,7 @@ async function processFullDiff(deps, req) {
|
|
|
89968
90184
|
});
|
|
89969
90185
|
console.log(`[${formatTimestamp()}] \uD83D\uDCC4 Full diff pushed: ${req.workingDir} (${diffStat.filesChanged} files, ${(Buffer.byteLength(result.content) / 1024).toFixed(1)}KB → ${(compressed.length / 1024).toFixed(1)}KB gzip, ${result.truncated ? "truncated" : "complete"})`);
|
|
89970
90186
|
} else {
|
|
89971
|
-
const emptyCompressed =
|
|
90187
|
+
const emptyCompressed = gzipSync5(Buffer.from("")).toString("base64");
|
|
89972
90188
|
await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
|
|
89973
90189
|
sessionId: deps.sessionId,
|
|
89974
90190
|
machineId: deps.machineId,
|
|
@@ -90069,7 +90285,7 @@ async function processCommitDetail(deps, req) {
|
|
|
90069
90285
|
]);
|
|
90070
90286
|
await upsertCommitDetailResult(deps, req, result, metadata);
|
|
90071
90287
|
if (result.status === "available" || result.status === "truncated") {
|
|
90072
|
-
const compressed =
|
|
90288
|
+
const compressed = gzipSync5(Buffer.from(result.content));
|
|
90073
90289
|
console.log(`[${formatTimestamp()}] \uD83D\uDD0D Commit detail pushed: ${req.sha.slice(0, 7)} in ${req.workingDir} (${(Buffer.byteLength(result.content) / 1024).toFixed(1)}KB → ${(compressed.length / 1024).toFixed(1)}KB gzip)`);
|
|
90074
90290
|
}
|
|
90075
90291
|
}
|
|
@@ -90100,7 +90316,7 @@ async function upsertCommitDetailResult(deps, req, result, metadata) {
|
|
|
90100
90316
|
return;
|
|
90101
90317
|
}
|
|
90102
90318
|
const diffStat = extractDiffStatFromShowOutput(result.content);
|
|
90103
|
-
const compressed =
|
|
90319
|
+
const compressed = gzipSync5(Buffer.from(result.content));
|
|
90104
90320
|
const diffContentCompressed = compressed.toString("base64");
|
|
90105
90321
|
await deps.backend.mutation(api.workspaces.upsertCommitDetailV2, {
|
|
90106
90322
|
...baseArgs,
|
|
@@ -91224,6 +91440,7 @@ var init_classify_resume_storm_reason = __esm(() => {
|
|
|
91224
91440
|
/unauthorized/i,
|
|
91225
91441
|
/unauthenticated/i,
|
|
91226
91442
|
/authentication failed/i,
|
|
91443
|
+
/authentication error/i,
|
|
91227
91444
|
/invalid.{0,24}api.{0,12}key/i,
|
|
91228
91445
|
/api key.{0,20}(invalid|missing|expired)/i
|
|
91229
91446
|
]
|
|
@@ -91244,10 +91461,7 @@ var init_classify_resume_storm_reason = __esm(() => {
|
|
|
91244
91461
|
]
|
|
91245
91462
|
}
|
|
91246
91463
|
];
|
|
91247
|
-
PERMANENT_FAILURE_REASONS = new Set([
|
|
91248
|
-
"auth_error",
|
|
91249
|
-
"config_error"
|
|
91250
|
-
]);
|
|
91464
|
+
PERMANENT_FAILURE_REASONS = new Set(["config_error"]);
|
|
91251
91465
|
});
|
|
91252
91466
|
|
|
91253
91467
|
// src/domain/agent-lifecycle/policies/abort-resume-storm.ts
|
|
@@ -94441,17 +94655,17 @@ var init_jsonc = __esm(() => {
|
|
|
94441
94655
|
});
|
|
94442
94656
|
|
|
94443
94657
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
94444
|
-
import { readFile as
|
|
94445
|
-
import { join as
|
|
94658
|
+
import { readFile as readFile10, readdir, stat as stat3 } from "node:fs/promises";
|
|
94659
|
+
import { join as join19, basename as basename2, resolve as resolve5 } from "node:path";
|
|
94446
94660
|
async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
94447
|
-
const parentDir =
|
|
94661
|
+
const parentDir = join19(rootDir, cleaned.slice(0, -2));
|
|
94448
94662
|
try {
|
|
94449
94663
|
const entries2 = await readdir(parentDir, { withFileTypes: true });
|
|
94450
94664
|
const dirs = [];
|
|
94451
94665
|
for (const entry of entries2) {
|
|
94452
94666
|
if (!entry.isDirectory())
|
|
94453
94667
|
continue;
|
|
94454
|
-
const dirPath =
|
|
94668
|
+
const dirPath = join19(parentDir, entry.name);
|
|
94455
94669
|
if (resolve5(dirPath).startsWith(resolve5(rootDir))) {
|
|
94456
94670
|
dirs.push(dirPath);
|
|
94457
94671
|
}
|
|
@@ -94462,7 +94676,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
94462
94676
|
}
|
|
94463
94677
|
}
|
|
94464
94678
|
async function resolveLiteralPath(rootDir, cleaned) {
|
|
94465
|
-
const dir =
|
|
94679
|
+
const dir = join19(rootDir, cleaned);
|
|
94466
94680
|
try {
|
|
94467
94681
|
if (!resolve5(dir).startsWith(resolve5(rootDir)))
|
|
94468
94682
|
return [];
|
|
@@ -94482,7 +94696,7 @@ async function resolveGlobPattern(rootDir, pattern2) {
|
|
|
94482
94696
|
}
|
|
94483
94697
|
async function readPackageJson(dir) {
|
|
94484
94698
|
try {
|
|
94485
|
-
const content = await
|
|
94699
|
+
const content = await readFile10(join19(dir, "package.json"), "utf-8");
|
|
94486
94700
|
const pkg = JSON.parse(content);
|
|
94487
94701
|
return {
|
|
94488
94702
|
name: pkg.name || basename2(dir),
|
|
@@ -94494,7 +94708,7 @@ async function readPackageJson(dir) {
|
|
|
94494
94708
|
}
|
|
94495
94709
|
async function readPnpmWorkspacePatterns(rootDir) {
|
|
94496
94710
|
try {
|
|
94497
|
-
const content = await
|
|
94711
|
+
const content = await readFile10(join19(rootDir, "pnpm-workspace.yaml"), "utf-8");
|
|
94498
94712
|
const patterns = [];
|
|
94499
94713
|
let inPackages = false;
|
|
94500
94714
|
for (const line of content.split(`
|
|
@@ -94521,7 +94735,7 @@ async function readPnpmWorkspacePatterns(rootDir) {
|
|
|
94521
94735
|
}
|
|
94522
94736
|
async function readPackageJsonWorkspacePatterns(rootDir) {
|
|
94523
94737
|
try {
|
|
94524
|
-
const content = await
|
|
94738
|
+
const content = await readFile10(join19(rootDir, "package.json"), "utf-8");
|
|
94525
94739
|
const pkg = JSON.parse(content);
|
|
94526
94740
|
if (!pkg.workspaces)
|
|
94527
94741
|
return [];
|
|
@@ -94569,12 +94783,12 @@ async function resolveSubWorkspaces(rootDir, pm) {
|
|
|
94569
94783
|
var init_workspace_resolver = () => {};
|
|
94570
94784
|
|
|
94571
94785
|
// src/infrastructure/services/workspace/command-discovery.ts
|
|
94572
|
-
import { access as access5, readFile as
|
|
94573
|
-
import { join as
|
|
94786
|
+
import { access as access5, readFile as readFile11 } from "node:fs/promises";
|
|
94787
|
+
import { join as join20, relative as relative2, basename as basename3 } from "node:path";
|
|
94574
94788
|
async function detectPackageManager(workingDir) {
|
|
94575
94789
|
for (const { file, manager } of LOCKFILE_MAP) {
|
|
94576
94790
|
try {
|
|
94577
|
-
await access5(
|
|
94791
|
+
await access5(join20(workingDir, file));
|
|
94578
94792
|
return manager;
|
|
94579
94793
|
} catch {}
|
|
94580
94794
|
}
|
|
@@ -94618,7 +94832,7 @@ function isValidScriptEntry(name, script) {
|
|
|
94618
94832
|
}
|
|
94619
94833
|
async function readJsonFile(filePath, label) {
|
|
94620
94834
|
try {
|
|
94621
|
-
const content = await
|
|
94835
|
+
const content = await readFile11(filePath, "utf-8");
|
|
94622
94836
|
return parseJsonc2(content);
|
|
94623
94837
|
} catch (error) {
|
|
94624
94838
|
if (error.code !== "ENOENT") {
|
|
@@ -94643,7 +94857,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
|
|
|
94643
94857
|
}
|
|
94644
94858
|
async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
94645
94859
|
let rootPackageName = basename3(workingDir);
|
|
94646
|
-
const pkg = await readJsonFile(
|
|
94860
|
+
const pkg = await readJsonFile(join20(workingDir, "package.json"), "root package.json");
|
|
94647
94861
|
if (!pkg)
|
|
94648
94862
|
return { commands: [], rootPackageName };
|
|
94649
94863
|
if (pkg.name)
|
|
@@ -94659,7 +94873,7 @@ async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
|
94659
94873
|
}
|
|
94660
94874
|
async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
|
|
94661
94875
|
const turboTaskNames = [];
|
|
94662
|
-
const turbo = await readJsonFile(
|
|
94876
|
+
const turbo = await readJsonFile(join20(workingDir, "turbo.json"), "turbo.json");
|
|
94663
94877
|
if (!turbo?.tasks || typeof turbo.tasks !== "object")
|
|
94664
94878
|
return turboTaskNames;
|
|
94665
94879
|
for (const taskName of Object.keys(turbo.tasks)) {
|
|
@@ -94728,14 +94942,14 @@ var init_command_discovery = __esm(() => {
|
|
|
94728
94942
|
});
|
|
94729
94943
|
|
|
94730
94944
|
// src/commands/machine/daemon-start/command-sync-heartbeat.ts
|
|
94731
|
-
import { createHash as
|
|
94945
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
94732
94946
|
var pushCommandsEffect, pushSingleWorkspaceCommandsEffect = (workingDir) => exports_Effect.gen(function* () {
|
|
94733
94947
|
const session2 = yield* DaemonSessionService;
|
|
94734
94948
|
const mutable2 = yield* DaemonMutableStateService;
|
|
94735
94949
|
const lastPushedGitState = yield* exports_Ref.get(mutable2.lastPushedGitState);
|
|
94736
94950
|
const commands = yield* exports_Effect.promise(() => discoverCommands(workingDir));
|
|
94737
94951
|
const stateKey = `commands:${session2.machineId}::${workingDir}`;
|
|
94738
|
-
const commandsHash =
|
|
94952
|
+
const commandsHash = createHash8("md5").update(JSON.stringify(commands)).digest("hex");
|
|
94739
94953
|
if (lastPushedGitState.get(stateKey) === commandsHash) {
|
|
94740
94954
|
return;
|
|
94741
94955
|
}
|
|
@@ -95166,10 +95380,10 @@ function assignProp(target, prop, value) {
|
|
|
95166
95380
|
configurable: true
|
|
95167
95381
|
});
|
|
95168
95382
|
}
|
|
95169
|
-
function getElementAtPath(obj,
|
|
95170
|
-
if (!
|
|
95383
|
+
function getElementAtPath(obj, path5) {
|
|
95384
|
+
if (!path5)
|
|
95171
95385
|
return obj;
|
|
95172
|
-
return
|
|
95386
|
+
return path5.reduce((acc, key) => acc?.[key], obj);
|
|
95173
95387
|
}
|
|
95174
95388
|
function promiseAllObject(promisesObj) {
|
|
95175
95389
|
const keys5 = Object.keys(promisesObj);
|
|
@@ -95415,11 +95629,11 @@ function aborted(x, startIndex = 0) {
|
|
|
95415
95629
|
}
|
|
95416
95630
|
return false;
|
|
95417
95631
|
}
|
|
95418
|
-
function prefixIssues(
|
|
95632
|
+
function prefixIssues(path5, issues) {
|
|
95419
95633
|
return issues.map((iss) => {
|
|
95420
95634
|
var _a2;
|
|
95421
95635
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
95422
|
-
iss.path.unshift(
|
|
95636
|
+
iss.path.unshift(path5);
|
|
95423
95637
|
return iss;
|
|
95424
95638
|
});
|
|
95425
95639
|
}
|
|
@@ -95604,7 +95818,7 @@ function treeifyError(error, _mapper) {
|
|
|
95604
95818
|
return issue2.message;
|
|
95605
95819
|
};
|
|
95606
95820
|
const result = { errors: [] };
|
|
95607
|
-
const processError = (error2,
|
|
95821
|
+
const processError = (error2, path5 = []) => {
|
|
95608
95822
|
var _a2, _b2;
|
|
95609
95823
|
for (const issue2 of error2.issues) {
|
|
95610
95824
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -95614,7 +95828,7 @@ function treeifyError(error, _mapper) {
|
|
|
95614
95828
|
} else if (issue2.code === "invalid_element") {
|
|
95615
95829
|
processError({ issues: issue2.issues }, issue2.path);
|
|
95616
95830
|
} else {
|
|
95617
|
-
const fullpath = [...
|
|
95831
|
+
const fullpath = [...path5, ...issue2.path];
|
|
95618
95832
|
if (fullpath.length === 0) {
|
|
95619
95833
|
result.errors.push(mapper(issue2));
|
|
95620
95834
|
continue;
|
|
@@ -95644,9 +95858,9 @@ function treeifyError(error, _mapper) {
|
|
|
95644
95858
|
processError(error);
|
|
95645
95859
|
return result;
|
|
95646
95860
|
}
|
|
95647
|
-
function toDotPath(
|
|
95861
|
+
function toDotPath(path5) {
|
|
95648
95862
|
const segs = [];
|
|
95649
|
-
for (const seg of
|
|
95863
|
+
for (const seg of path5) {
|
|
95650
95864
|
if (typeof seg === "number")
|
|
95651
95865
|
segs.push(`[${seg}]`);
|
|
95652
95866
|
else if (typeof seg === "symbol")
|
|
@@ -107547,8 +107761,6 @@ var init_command_loop = __esm(() => {
|
|
|
107547
107761
|
init_featureFlags();
|
|
107548
107762
|
init_reliability();
|
|
107549
107763
|
init_esm();
|
|
107550
|
-
init_dir_listing_subscription();
|
|
107551
|
-
init_dir_listing_watch_subscription();
|
|
107552
107764
|
init_api3();
|
|
107553
107765
|
init_on_request_start_agent();
|
|
107554
107766
|
init_on_request_stop_agent();
|
|
@@ -107561,6 +107773,7 @@ var init_command_loop = __esm(() => {
|
|
|
107561
107773
|
init_daemon_services();
|
|
107562
107774
|
init_start_subscriptions();
|
|
107563
107775
|
init_file_content_subscription();
|
|
107776
|
+
init_file_tree_subscription();
|
|
107564
107777
|
init_file_write_subscription();
|
|
107565
107778
|
init_git_heartbeat();
|
|
107566
107779
|
init_git_subscription();
|
|
@@ -107604,8 +107817,7 @@ var init_command_loop = __esm(() => {
|
|
|
107604
107817
|
let gitSubscriptionHandle = null;
|
|
107605
107818
|
let fileContentSubscriptionHandle = null;
|
|
107606
107819
|
let fileWriteSubscriptionHandle = null;
|
|
107607
|
-
let
|
|
107608
|
-
let dirListingWatchSubscriptionHandle = null;
|
|
107820
|
+
let fileTreeSubscriptionHandle = null;
|
|
107609
107821
|
let workspaceListSubscriptionHandle = null;
|
|
107610
107822
|
let observedSyncSubscriptionHandle = null;
|
|
107611
107823
|
let logObserverSubscriptionHandle = null;
|
|
@@ -107670,8 +107882,7 @@ var init_command_loop = __esm(() => {
|
|
|
107670
107882
|
gitSubscriptionHandle?.stop();
|
|
107671
107883
|
fileContentSubscriptionHandle?.stop();
|
|
107672
107884
|
fileWriteSubscriptionHandle?.stop();
|
|
107673
|
-
|
|
107674
|
-
dirListingWatchSubscriptionHandle?.stop();
|
|
107885
|
+
fileTreeSubscriptionHandle?.stop();
|
|
107675
107886
|
workspaceListSubscriptionHandle?.stop();
|
|
107676
107887
|
observedSyncSubscriptionHandle?.stop();
|
|
107677
107888
|
taskMonitorHandle?.stop();
|
|
@@ -107716,8 +107927,7 @@ var init_command_loop = __esm(() => {
|
|
|
107716
107927
|
gitSubscriptionHandle = yield* startGitRequestSubscriptionEffect(wsClient2);
|
|
107717
107928
|
fileContentSubscriptionHandle = yield* startFileContentSubscriptionEffect(wsClient2);
|
|
107718
107929
|
fileWriteSubscriptionHandle = yield* startFileWriteSubscriptionEffect(wsClient2);
|
|
107719
|
-
|
|
107720
|
-
dirListingWatchSubscriptionHandle = yield* startDirListingWatchSubscriptionEffect(wsClient2);
|
|
107930
|
+
fileTreeSubscriptionHandle = yield* startFileTreeSubscriptionEffect(wsClient2);
|
|
107721
107931
|
workspaceListSubscriptionHandle = yield* startWorkspaceListSubscriptionEffect(wsClient2);
|
|
107722
107932
|
observedSyncSubscriptionHandle = yield* startObservedSyncSubscriptionEffect(wsClient2);
|
|
107723
107933
|
const taskMonitorHandle = yield* startTaskMonitorEffect(wsClient2);
|
|
@@ -107918,7 +108128,7 @@ __export(exports_opencode_install, {
|
|
|
107918
108128
|
installTool: () => installTool
|
|
107919
108129
|
});
|
|
107920
108130
|
import * as os2 from "os";
|
|
107921
|
-
import * as
|
|
108131
|
+
import * as path5 from "path";
|
|
107922
108132
|
async function isChatroomInstalledDefault() {
|
|
107923
108133
|
try {
|
|
107924
108134
|
const { execSync: execSync3 } = await import("child_process");
|
|
@@ -107930,7 +108140,7 @@ async function isChatroomInstalledDefault() {
|
|
|
107930
108140
|
}
|
|
107931
108141
|
async function createDefaultDeps18() {
|
|
107932
108142
|
const client4 = await getConvexClient();
|
|
107933
|
-
const
|
|
108143
|
+
const fs12 = await import("fs/promises");
|
|
107934
108144
|
return {
|
|
107935
108145
|
backend: {
|
|
107936
108146
|
mutation: (endpoint, args2) => client4.mutation(endpoint, args2),
|
|
@@ -107943,13 +108153,13 @@ async function createDefaultDeps18() {
|
|
|
107943
108153
|
},
|
|
107944
108154
|
fs: {
|
|
107945
108155
|
access: async (p) => {
|
|
107946
|
-
await
|
|
108156
|
+
await fs12.access(p);
|
|
107947
108157
|
},
|
|
107948
108158
|
mkdir: async (p, options) => {
|
|
107949
|
-
await
|
|
108159
|
+
await fs12.mkdir(p, options);
|
|
107950
108160
|
},
|
|
107951
108161
|
writeFile: async (p, content, encoding) => {
|
|
107952
|
-
await
|
|
108162
|
+
await fs12.writeFile(p, content, encoding);
|
|
107953
108163
|
}
|
|
107954
108164
|
},
|
|
107955
108165
|
isChatroomInstalled: isChatroomInstalledDefault
|
|
@@ -108288,9 +108498,9 @@ After logging in, try this command again.\`;
|
|
|
108288
108498
|
const fsService = yield* OpenCodeInstallFsService;
|
|
108289
108499
|
const { checkExisting = true } = options;
|
|
108290
108500
|
const homeDir = os2.homedir();
|
|
108291
|
-
const toolDir =
|
|
108292
|
-
const toolPath =
|
|
108293
|
-
const handoffToolPath =
|
|
108501
|
+
const toolDir = path5.join(homeDir, ".config", "opencode", "tool");
|
|
108502
|
+
const toolPath = path5.join(toolDir, "chatroom.ts");
|
|
108503
|
+
const handoffToolPath = path5.join(toolDir, "chatroom-handoff.ts");
|
|
108294
108504
|
if (checkExisting) {
|
|
108295
108505
|
const existingFiles = [];
|
|
108296
108506
|
const toolExists = yield* fsService.access(toolPath);
|
|
@@ -108845,4 +109055,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
108845
109055
|
});
|
|
108846
109056
|
program2.parse();
|
|
108847
109057
|
|
|
108848
|
-
//# debugId=
|
|
109058
|
+
//# debugId=0F49F7F33D425EFB64756E2164756E21
|