chatroom-cli 1.59.1 → 1.60.0
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 +1341 -408
- package/dist/index.js.map +24 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -79917,6 +79917,765 @@ var init_daemon_services = __esm(() => {
|
|
|
79917
79917
|
};
|
|
79918
79918
|
});
|
|
79919
79919
|
|
|
79920
|
+
// src/commands/machine/daemon-start/utils.ts
|
|
79921
|
+
function formatTimestamp() {
|
|
79922
|
+
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
79923
|
+
}
|
|
79924
|
+
|
|
79925
|
+
// src/infrastructure/services/workspace/dir-listing-content-hash.ts
|
|
79926
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
79927
|
+
function computeDirListingContentHash(listing) {
|
|
79928
|
+
const payload = {
|
|
79929
|
+
entries: listing.entries,
|
|
79930
|
+
truncated: listing.truncated,
|
|
79931
|
+
totalCount: listing.totalCount
|
|
79932
|
+
};
|
|
79933
|
+
return createHash2("md5").update(JSON.stringify(payload)).digest("hex");
|
|
79934
|
+
}
|
|
79935
|
+
var init_dir_listing_content_hash = () => {};
|
|
79936
|
+
|
|
79937
|
+
// src/infrastructure/services/workspace/workspace-path-security.ts
|
|
79938
|
+
import { realpath } from "node:fs/promises";
|
|
79939
|
+
import { basename, dirname as dirname8, isAbsolute, relative, resolve as resolve3, sep } from "node:path";
|
|
79940
|
+
import { gunzipSync } from "node:zlib";
|
|
79941
|
+
function validateRelativePathSegments(filePath) {
|
|
79942
|
+
if (filePath.includes("\x00"))
|
|
79943
|
+
return { ok: false, error: "Invalid file path" };
|
|
79944
|
+
if (filePath.includes(".."))
|
|
79945
|
+
return { ok: false, error: "Invalid file path" };
|
|
79946
|
+
if (filePath.startsWith("/"))
|
|
79947
|
+
return { ok: false, error: "Invalid file path" };
|
|
79948
|
+
return { ok: true };
|
|
79949
|
+
}
|
|
79950
|
+
function isPathInsideRoot(workspaceRoot, targetPath) {
|
|
79951
|
+
const rel = relative(workspaceRoot, targetPath);
|
|
79952
|
+
if (rel === "")
|
|
79953
|
+
return true;
|
|
79954
|
+
if (rel.startsWith("..") || rel.includes(`..${sep}`))
|
|
79955
|
+
return false;
|
|
79956
|
+
if (isAbsolute(rel))
|
|
79957
|
+
return false;
|
|
79958
|
+
return true;
|
|
79959
|
+
}
|
|
79960
|
+
async function resolvePathWithinWorkspace(workingDir, filePath) {
|
|
79961
|
+
const basic = validateRelativePathSegments(filePath);
|
|
79962
|
+
if (!basic.ok)
|
|
79963
|
+
return basic;
|
|
79964
|
+
let workspaceRoot;
|
|
79965
|
+
try {
|
|
79966
|
+
workspaceRoot = await realpath(resolve3(workingDir));
|
|
79967
|
+
} catch {
|
|
79968
|
+
return { ok: false, error: "Working directory not found" };
|
|
79969
|
+
}
|
|
79970
|
+
const candidate = resolve3(workspaceRoot, filePath);
|
|
79971
|
+
if (!isPathInsideRoot(workspaceRoot, candidate)) {
|
|
79972
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
79973
|
+
}
|
|
79974
|
+
try {
|
|
79975
|
+
const resolved = await realpath(candidate);
|
|
79976
|
+
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
79977
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
79978
|
+
}
|
|
79979
|
+
return { ok: true, absolutePath: resolved };
|
|
79980
|
+
} catch (err) {
|
|
79981
|
+
const code2 = err?.code;
|
|
79982
|
+
if (code2 !== "ENOENT") {
|
|
79983
|
+
return { ok: false, error: "Invalid file path" };
|
|
79984
|
+
}
|
|
79985
|
+
const parent = dirname8(candidate);
|
|
79986
|
+
if (parent === workspaceRoot || isPathInsideRoot(workspaceRoot, parent)) {
|
|
79987
|
+
try {
|
|
79988
|
+
const parentReal = await realpath(parent);
|
|
79989
|
+
if (!isPathInsideRoot(workspaceRoot, parentReal)) {
|
|
79990
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
79991
|
+
}
|
|
79992
|
+
const resolved = resolve3(parentReal, basename(candidate));
|
|
79993
|
+
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
79994
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
79995
|
+
}
|
|
79996
|
+
return { ok: true, absolutePath: resolved };
|
|
79997
|
+
} catch {
|
|
79998
|
+
return { ok: true, absolutePath: candidate };
|
|
79999
|
+
}
|
|
80000
|
+
}
|
|
80001
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
80002
|
+
}
|
|
80003
|
+
}
|
|
80004
|
+
function gunzipBase64Payload(base64, maxBytes) {
|
|
80005
|
+
let compressed;
|
|
80006
|
+
try {
|
|
80007
|
+
compressed = Buffer.from(base64, "base64");
|
|
80008
|
+
} catch {
|
|
80009
|
+
return { ok: false, errorMessage: "Missing file data" };
|
|
80010
|
+
}
|
|
80011
|
+
if (compressed.length > maxBytes * 10) {
|
|
80012
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
80013
|
+
}
|
|
80014
|
+
try {
|
|
80015
|
+
const content = gunzipSync(compressed, { maxOutputLength: maxBytes });
|
|
80016
|
+
if (content.length > maxBytes) {
|
|
80017
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
80018
|
+
}
|
|
80019
|
+
return { ok: true, content };
|
|
80020
|
+
} catch {
|
|
80021
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
80022
|
+
}
|
|
80023
|
+
}
|
|
80024
|
+
var init_workspace_path_security = () => {};
|
|
80025
|
+
|
|
80026
|
+
// src/infrastructure/services/workspace/workspace-visibility-policy.ts
|
|
80027
|
+
import { exec as exec2, spawn as spawn3 } from "node:child_process";
|
|
80028
|
+
import { promisify as promisify2 } from "node:util";
|
|
80029
|
+
function isAlwaysExcludedDirName(name) {
|
|
80030
|
+
return ALWAYS_EXCLUDE_DIR_NAMES.has(name);
|
|
80031
|
+
}
|
|
80032
|
+
function isSecretPath(relativePath) {
|
|
80033
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
80034
|
+
return SECRET_PATH_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
80035
|
+
}
|
|
80036
|
+
function hasExcludedDirSegment(relativePath) {
|
|
80037
|
+
const segments = relativePath.split("/");
|
|
80038
|
+
return segments.some((segment) => isAlwaysExcludedDirName(segment));
|
|
80039
|
+
}
|
|
80040
|
+
function isPathVisible(relativePath) {
|
|
80041
|
+
if (!relativePath)
|
|
80042
|
+
return true;
|
|
80043
|
+
return !isSecretPath(relativePath) && !hasExcludedDirSegment(relativePath);
|
|
80044
|
+
}
|
|
80045
|
+
function isPathContentReadable(relativePath) {
|
|
80046
|
+
return isPathVisible(relativePath);
|
|
80047
|
+
}
|
|
80048
|
+
async function isGitRepo(rootDir) {
|
|
80049
|
+
try {
|
|
80050
|
+
const { stdout } = await execAsync2("git rev-parse --is-inside-work-tree", {
|
|
80051
|
+
cwd: rootDir,
|
|
80052
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" },
|
|
80053
|
+
maxBuffer: 1024 * 1024
|
|
80054
|
+
});
|
|
80055
|
+
return stdout.trim() === "true";
|
|
80056
|
+
} catch {
|
|
80057
|
+
return false;
|
|
80058
|
+
}
|
|
80059
|
+
}
|
|
80060
|
+
async function filterGitIgnored(rootDir, relativePaths) {
|
|
80061
|
+
if (relativePaths.length === 0)
|
|
80062
|
+
return new Set;
|
|
80063
|
+
const inRepo = await isGitRepo(rootDir);
|
|
80064
|
+
if (!inRepo)
|
|
80065
|
+
return new Set;
|
|
80066
|
+
try {
|
|
80067
|
+
const stdout = await new Promise((resolve4, reject) => {
|
|
80068
|
+
const child = spawn3("git", ["check-ignore", "--stdin", "-z"], {
|
|
80069
|
+
cwd: rootDir,
|
|
80070
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" }
|
|
80071
|
+
});
|
|
80072
|
+
let output = "";
|
|
80073
|
+
child.stdout.on("data", (chunk2) => {
|
|
80074
|
+
output += chunk2.toString();
|
|
80075
|
+
});
|
|
80076
|
+
child.on("error", reject);
|
|
80077
|
+
child.on("close", () => resolve4(output));
|
|
80078
|
+
child.stdin.write(relativePaths.join(`
|
|
80079
|
+
`));
|
|
80080
|
+
child.stdin.end();
|
|
80081
|
+
});
|
|
80082
|
+
const ignored = new Set;
|
|
80083
|
+
if (!stdout)
|
|
80084
|
+
return ignored;
|
|
80085
|
+
for (const entry of stdout.split("\x00")) {
|
|
80086
|
+
const trimmed = entry.trim();
|
|
80087
|
+
if (trimmed)
|
|
80088
|
+
ignored.add(trimmed);
|
|
80089
|
+
}
|
|
80090
|
+
return ignored;
|
|
80091
|
+
} catch {
|
|
80092
|
+
return new Set;
|
|
80093
|
+
}
|
|
80094
|
+
}
|
|
80095
|
+
var execAsync2, ALWAYS_EXCLUDE_DIR_NAMES, SECRET_PATH_PATTERNS;
|
|
80096
|
+
var init_workspace_visibility_policy = __esm(() => {
|
|
80097
|
+
execAsync2 = promisify2(exec2);
|
|
80098
|
+
ALWAYS_EXCLUDE_DIR_NAMES = new Set([
|
|
80099
|
+
"node_modules",
|
|
80100
|
+
".git",
|
|
80101
|
+
"dist",
|
|
80102
|
+
"build",
|
|
80103
|
+
".next",
|
|
80104
|
+
"coverage",
|
|
80105
|
+
"__pycache__",
|
|
80106
|
+
".turbo",
|
|
80107
|
+
".cache",
|
|
80108
|
+
".tmp",
|
|
80109
|
+
"tmp",
|
|
80110
|
+
"_generated",
|
|
80111
|
+
".vercel"
|
|
80112
|
+
]);
|
|
80113
|
+
SECRET_PATH_PATTERNS = [
|
|
80114
|
+
/^\.env$/,
|
|
80115
|
+
/^\.env\./,
|
|
80116
|
+
/\.pem$/,
|
|
80117
|
+
/\.key$/,
|
|
80118
|
+
/id_rsa$/,
|
|
80119
|
+
/credentials\.json$/,
|
|
80120
|
+
/^secrets(\/|$)/,
|
|
80121
|
+
/^\.aws(\/|$)/
|
|
80122
|
+
];
|
|
80123
|
+
});
|
|
80124
|
+
|
|
80125
|
+
// src/infrastructure/services/workspace/dir-listing-scanner.ts
|
|
80126
|
+
import { promises as fsPromises } from "node:fs";
|
|
80127
|
+
import path3 from "node:path";
|
|
80128
|
+
async function listDirectory(rootDir, dirPath, options) {
|
|
80129
|
+
const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
80130
|
+
const scannedAt = Date.now();
|
|
80131
|
+
const absDir = dirPath ? path3.join(rootDir, dirPath) : rootDir;
|
|
80132
|
+
const resolvedRoot = path3.resolve(rootDir);
|
|
80133
|
+
const resolvedDir = path3.resolve(absDir);
|
|
80134
|
+
if (!isPathInsideRoot(resolvedRoot, resolvedDir)) {
|
|
80135
|
+
return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
|
|
80136
|
+
}
|
|
80137
|
+
let dirents;
|
|
80138
|
+
try {
|
|
80139
|
+
dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
|
|
80140
|
+
} catch {
|
|
80141
|
+
return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
|
|
80142
|
+
}
|
|
80143
|
+
const candidates = [];
|
|
80144
|
+
for (const ent of dirents) {
|
|
80145
|
+
if (isAlwaysExcludedDirName(ent.name))
|
|
80146
|
+
continue;
|
|
80147
|
+
const relativePath = dirPath ? `${dirPath}/${ent.name}` : ent.name;
|
|
80148
|
+
if (!isPathVisible(relativePath))
|
|
80149
|
+
continue;
|
|
80150
|
+
if (ent.isDirectory()) {
|
|
80151
|
+
candidates.push({ name: ent.name, path: relativePath, type: "directory" });
|
|
80152
|
+
} else if (ent.isFile()) {
|
|
80153
|
+
let size9;
|
|
80154
|
+
try {
|
|
80155
|
+
const st = await fsPromises.stat(path3.join(absDir, ent.name));
|
|
80156
|
+
size9 = st.size;
|
|
80157
|
+
} catch {}
|
|
80158
|
+
candidates.push({ name: ent.name, path: relativePath, type: "file", size: size9 });
|
|
80159
|
+
}
|
|
80160
|
+
}
|
|
80161
|
+
const ignored = await filterGitIgnored(rootDir, candidates.map((c) => c.path));
|
|
80162
|
+
const visible = candidates.filter((c) => !ignored.has(c.path));
|
|
80163
|
+
visible.sort((a, b) => {
|
|
80164
|
+
if (a.type === "directory" && b.type === "file")
|
|
80165
|
+
return -1;
|
|
80166
|
+
if (a.type === "file" && b.type === "directory")
|
|
80167
|
+
return 1;
|
|
80168
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
80169
|
+
});
|
|
80170
|
+
const totalCount = visible.length;
|
|
80171
|
+
const truncated = totalCount > maxEntries;
|
|
80172
|
+
const entries2 = visible.slice(0, maxEntries);
|
|
80173
|
+
return { dirPath, entries: entries2, scannedAt, truncated, totalCount };
|
|
80174
|
+
}
|
|
80175
|
+
var DEFAULT_MAX_ENTRIES = 500;
|
|
80176
|
+
var init_dir_listing_scanner = __esm(() => {
|
|
80177
|
+
init_workspace_path_security();
|
|
80178
|
+
init_workspace_visibility_policy();
|
|
80179
|
+
});
|
|
80180
|
+
|
|
80181
|
+
// src/infrastructure/services/workspace/dir-listing-sync.ts
|
|
80182
|
+
import { gzipSync } from "node:zlib";
|
|
80183
|
+
function listingCacheKey(workingDir, dirPath) {
|
|
80184
|
+
return `${workingDir}\x00${dirPath}`;
|
|
80185
|
+
}
|
|
80186
|
+
async function scanDirListingForSync(workingDir, dirPath) {
|
|
80187
|
+
const listing = await listDirectory(workingDir, dirPath);
|
|
80188
|
+
const dataHash = computeDirListingContentHash(listing);
|
|
80189
|
+
const cacheKey = listingCacheKey(workingDir, dirPath);
|
|
80190
|
+
if (lastSyncedContentHash.get(cacheKey) === dataHash)
|
|
80191
|
+
return null;
|
|
80192
|
+
const json = JSON.stringify(listing);
|
|
80193
|
+
return {
|
|
80194
|
+
dirPath,
|
|
80195
|
+
data: { compression: "gzip", content: gzipSync(Buffer.from(json)).toString("base64") },
|
|
80196
|
+
dataHash,
|
|
80197
|
+
scannedAt: listing.scannedAt,
|
|
80198
|
+
truncated: listing.truncated,
|
|
80199
|
+
totalCount: listing.totalCount
|
|
80200
|
+
};
|
|
80201
|
+
}
|
|
80202
|
+
async function scanDirListingsWithConcurrency(workingDir, dirPaths) {
|
|
80203
|
+
const items = [];
|
|
80204
|
+
let index = 0;
|
|
80205
|
+
async function worker() {
|
|
80206
|
+
while (index < dirPaths.length) {
|
|
80207
|
+
const currentIndex = index;
|
|
80208
|
+
index += 1;
|
|
80209
|
+
const dirPath = dirPaths[currentIndex];
|
|
80210
|
+
if (dirPath === undefined)
|
|
80211
|
+
continue;
|
|
80212
|
+
const item = await scanDirListingForSync(workingDir, dirPath);
|
|
80213
|
+
if (item)
|
|
80214
|
+
items.push(item);
|
|
80215
|
+
}
|
|
80216
|
+
}
|
|
80217
|
+
const workerCount = Math.min(SCAN_CONCURRENCY, dirPaths.length);
|
|
80218
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
80219
|
+
return items;
|
|
80220
|
+
}
|
|
80221
|
+
function markItemsSynced(workingDir, items) {
|
|
80222
|
+
for (const item of items) {
|
|
80223
|
+
lastSyncedContentHash.set(listingCacheKey(workingDir, item.dirPath), item.dataHash);
|
|
80224
|
+
}
|
|
80225
|
+
}
|
|
80226
|
+
async function syncDirListingToBackend(session2, workingDir, dirPath) {
|
|
80227
|
+
const item = await scanDirListingForSync(workingDir, dirPath);
|
|
80228
|
+
if (!item)
|
|
80229
|
+
return;
|
|
80230
|
+
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
|
|
80231
|
+
sessionId: session2.sessionId,
|
|
80232
|
+
machineId: session2.machineId,
|
|
80233
|
+
workingDir,
|
|
80234
|
+
dirPath: item.dirPath,
|
|
80235
|
+
data: item.data,
|
|
80236
|
+
dataHash: item.dataHash,
|
|
80237
|
+
scannedAt: item.scannedAt,
|
|
80238
|
+
truncated: item.truncated,
|
|
80239
|
+
totalCount: item.totalCount
|
|
80240
|
+
});
|
|
80241
|
+
markItemsSynced(workingDir, [item]);
|
|
80242
|
+
}
|
|
80243
|
+
async function syncDirListingsToBackend(session2, workingDir, dirPaths) {
|
|
80244
|
+
const unique = [...new Set(dirPaths)];
|
|
80245
|
+
if (unique.length === 0)
|
|
80246
|
+
return;
|
|
80247
|
+
if (unique.length === 1) {
|
|
80248
|
+
const dirPath = unique[0];
|
|
80249
|
+
if (dirPath !== undefined) {
|
|
80250
|
+
await syncDirListingToBackend(session2, workingDir, dirPath);
|
|
80251
|
+
}
|
|
80252
|
+
return;
|
|
80253
|
+
}
|
|
80254
|
+
const items = await scanDirListingsWithConcurrency(workingDir, unique);
|
|
80255
|
+
if (items.length === 0)
|
|
80256
|
+
return;
|
|
80257
|
+
for (let i2 = 0;i2 < items.length; i2 += MAX_BATCH_SIZE) {
|
|
80258
|
+
const chunk2 = items.slice(i2, i2 + MAX_BATCH_SIZE);
|
|
80259
|
+
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2Batch, {
|
|
80260
|
+
sessionId: session2.sessionId,
|
|
80261
|
+
machineId: session2.machineId,
|
|
80262
|
+
workingDir,
|
|
80263
|
+
items: chunk2
|
|
80264
|
+
});
|
|
80265
|
+
markItemsSynced(workingDir, chunk2);
|
|
80266
|
+
}
|
|
80267
|
+
}
|
|
80268
|
+
var MAX_BATCH_SIZE = 25, SCAN_CONCURRENCY = 4, lastSyncedContentHash;
|
|
80269
|
+
var init_dir_listing_sync = __esm(() => {
|
|
80270
|
+
init_dir_listing_content_hash();
|
|
80271
|
+
init_dir_listing_scanner();
|
|
80272
|
+
init_api3();
|
|
80273
|
+
lastSyncedContentHash = new Map;
|
|
80274
|
+
});
|
|
80275
|
+
|
|
80276
|
+
// src/infrastructure/services/workspace/workspace-file-search.ts
|
|
80277
|
+
import { promises as fsPromises2 } from "node:fs";
|
|
80278
|
+
import path4 from "node:path";
|
|
80279
|
+
async function searchWorkspaceFiles(rootDir, query, options) {
|
|
80280
|
+
const maxResults = options?.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
80281
|
+
const scannedAt = Date.now();
|
|
80282
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
80283
|
+
const matches = [];
|
|
80284
|
+
let visitedDirs = 0;
|
|
80285
|
+
let truncated = false;
|
|
80286
|
+
async function visitDir(relDir) {
|
|
80287
|
+
if (visitedDirs >= MAX_VISIT_DIRS || matches.length >= maxResults) {
|
|
80288
|
+
truncated = true;
|
|
80289
|
+
return;
|
|
80290
|
+
}
|
|
80291
|
+
visitedDirs++;
|
|
80292
|
+
const absDir = relDir ? path4.join(rootDir, relDir) : rootDir;
|
|
80293
|
+
let dirents;
|
|
80294
|
+
try {
|
|
80295
|
+
dirents = await fsPromises2.readdir(absDir, { withFileTypes: true });
|
|
80296
|
+
} catch {
|
|
80297
|
+
return;
|
|
80298
|
+
}
|
|
80299
|
+
const fileCandidates = [];
|
|
80300
|
+
const subdirs = [];
|
|
80301
|
+
for (const ent of dirents) {
|
|
80302
|
+
if (isAlwaysExcludedDirName(ent.name))
|
|
80303
|
+
continue;
|
|
80304
|
+
const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
|
|
80305
|
+
if (!isPathVisible(relativePath))
|
|
80306
|
+
continue;
|
|
80307
|
+
if (ent.isDirectory()) {
|
|
80308
|
+
subdirs.push(relativePath);
|
|
80309
|
+
} else if (ent.isFile()) {
|
|
80310
|
+
fileCandidates.push(relativePath);
|
|
80311
|
+
}
|
|
80312
|
+
}
|
|
80313
|
+
const ignored = await filterGitIgnored(rootDir, fileCandidates);
|
|
80314
|
+
for (const filePath of fileCandidates) {
|
|
80315
|
+
if (ignored.has(filePath))
|
|
80316
|
+
continue;
|
|
80317
|
+
const fileName = path4.basename(filePath).toLowerCase();
|
|
80318
|
+
if (normalizedQuery === "" || fileName.includes(normalizedQuery)) {
|
|
80319
|
+
matches.push({ path: filePath, type: "file" });
|
|
80320
|
+
if (matches.length >= maxResults) {
|
|
80321
|
+
truncated = true;
|
|
80322
|
+
return;
|
|
80323
|
+
}
|
|
80324
|
+
}
|
|
80325
|
+
}
|
|
80326
|
+
for (const sub of subdirs) {
|
|
80327
|
+
if (matches.length >= maxResults || visitedDirs >= MAX_VISIT_DIRS) {
|
|
80328
|
+
truncated = true;
|
|
80329
|
+
return;
|
|
80330
|
+
}
|
|
80331
|
+
await visitDir(sub);
|
|
80332
|
+
}
|
|
80333
|
+
}
|
|
80334
|
+
await visitDir("");
|
|
80335
|
+
return {
|
|
80336
|
+
query,
|
|
80337
|
+
entries: matches,
|
|
80338
|
+
scannedAt,
|
|
80339
|
+
truncated,
|
|
80340
|
+
totalCount: matches.length
|
|
80341
|
+
};
|
|
80342
|
+
}
|
|
80343
|
+
var DEFAULT_MAX_RESULTS = 300, MAX_VISIT_DIRS = 2000;
|
|
80344
|
+
var init_workspace_file_search = __esm(() => {
|
|
80345
|
+
init_workspace_visibility_policy();
|
|
80346
|
+
});
|
|
80347
|
+
|
|
80348
|
+
// src/commands/machine/daemon-start/dir-listing-subscription.ts
|
|
80349
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
80350
|
+
import { gzipSync as gzipSync2 } from "node:zlib";
|
|
80351
|
+
function logSubscriptionWarn(label, err) {
|
|
80352
|
+
console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage(err)}`);
|
|
80353
|
+
}
|
|
80354
|
+
async function uploadDirListing(session2, workingDir, dirPath) {
|
|
80355
|
+
await syncDirListingToBackend(session2, workingDir, dirPath);
|
|
80356
|
+
await session2.backend.mutation(api.workspaceFiles.fulfillDirListingRequest, {
|
|
80357
|
+
sessionId: session2.sessionId,
|
|
80358
|
+
machineId: session2.machineId,
|
|
80359
|
+
workingDir,
|
|
80360
|
+
dirPath
|
|
80361
|
+
});
|
|
80362
|
+
}
|
|
80363
|
+
async function uploadFileSearch(session2, workingDir, query) {
|
|
80364
|
+
const result = await searchWorkspaceFiles(workingDir, query);
|
|
80365
|
+
const json = JSON.stringify(result);
|
|
80366
|
+
const dataHash = createHash3("md5").update(json).digest("hex");
|
|
80367
|
+
const compressed = gzipSync2(Buffer.from(json)).toString("base64");
|
|
80368
|
+
await session2.backend.mutation(api.workspaceFiles.syncFileSearchV2, {
|
|
80369
|
+
sessionId: session2.sessionId,
|
|
80370
|
+
machineId: session2.machineId,
|
|
80371
|
+
workingDir,
|
|
80372
|
+
query,
|
|
80373
|
+
data: { compression: "gzip", content: compressed },
|
|
80374
|
+
dataHash,
|
|
80375
|
+
scannedAt: result.scannedAt,
|
|
80376
|
+
truncated: result.truncated,
|
|
80377
|
+
totalCount: result.totalCount
|
|
80378
|
+
});
|
|
80379
|
+
await session2.backend.mutation(api.workspaceFiles.fulfillFileSearchRequest, {
|
|
80380
|
+
sessionId: session2.sessionId,
|
|
80381
|
+
machineId: session2.machineId,
|
|
80382
|
+
workingDir,
|
|
80383
|
+
query
|
|
80384
|
+
});
|
|
80385
|
+
}
|
|
80386
|
+
var fulfillDirListingRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
80387
|
+
for (const request2 of requests) {
|
|
80388
|
+
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
80389
|
+
const start3 = Date.now();
|
|
80390
|
+
yield* exports_Effect.tryPromise(() => uploadDirListing(session2, request2.workingDir, request2.dirPath));
|
|
80391
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing fulfilled: ${request2.workingDir}/${request2.dirPath || "(root)"} (${Date.now() - start3}ms)`);
|
|
80392
|
+
}), (err) => {
|
|
80393
|
+
logSubscriptionWarn(`Dir listing failed for ${request2.workingDir}/${request2.dirPath}`, err);
|
|
80394
|
+
return exports_Effect.void;
|
|
80395
|
+
});
|
|
80396
|
+
}
|
|
80397
|
+
}), fulfillFileSearchRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
80398
|
+
for (const request2 of requests) {
|
|
80399
|
+
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
80400
|
+
const start3 = Date.now();
|
|
80401
|
+
yield* exports_Effect.tryPromise(() => uploadFileSearch(session2, request2.workingDir, request2.query));
|
|
80402
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD0D File search fulfilled: ${request2.workingDir} query="${request2.query}" (${Date.now() - start3}ms)`);
|
|
80403
|
+
}), (err) => {
|
|
80404
|
+
logSubscriptionWarn(`File search failed for ${request2.workingDir}`, err);
|
|
80405
|
+
return exports_Effect.void;
|
|
80406
|
+
});
|
|
80407
|
+
}
|
|
80408
|
+
}), startDirListingSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
80409
|
+
const session2 = yield* DaemonSessionService;
|
|
80410
|
+
let processingDir = false;
|
|
80411
|
+
let processingSearch = false;
|
|
80412
|
+
const unsubDir = wsClient2.onUpdate(api.workspaceFiles.getPendingDirListingRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
80413
|
+
if (!requests?.length || processingDir)
|
|
80414
|
+
return;
|
|
80415
|
+
processingDir = true;
|
|
80416
|
+
exports_Effect.runPromise(fulfillDirListingRequestsEffect(session2, requests)).catch((err) => {
|
|
80417
|
+
logSubscriptionWarn("Dir listing subscription processing failed", err);
|
|
80418
|
+
}).finally(() => {
|
|
80419
|
+
processingDir = false;
|
|
80420
|
+
});
|
|
80421
|
+
}, (err) => {
|
|
80422
|
+
logSubscriptionWarn("Dir listing subscription error", err);
|
|
80423
|
+
});
|
|
80424
|
+
const unsubSearch = wsClient2.onUpdate(api.workspaceFiles.getPendingFileSearchRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
80425
|
+
if (!requests?.length || processingSearch)
|
|
80426
|
+
return;
|
|
80427
|
+
processingSearch = true;
|
|
80428
|
+
exports_Effect.runPromise(fulfillFileSearchRequestsEffect(session2, requests)).catch((err) => {
|
|
80429
|
+
logSubscriptionWarn("File search subscription processing failed", err);
|
|
80430
|
+
}).finally(() => {
|
|
80431
|
+
processingSearch = false;
|
|
80432
|
+
});
|
|
80433
|
+
}, (err) => {
|
|
80434
|
+
logSubscriptionWarn("File search subscription error", err);
|
|
80435
|
+
});
|
|
80436
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription started (reactive)`);
|
|
80437
|
+
return {
|
|
80438
|
+
stop: () => {
|
|
80439
|
+
unsubDir();
|
|
80440
|
+
unsubSearch();
|
|
80441
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription stopped`);
|
|
80442
|
+
}
|
|
80443
|
+
};
|
|
80444
|
+
});
|
|
80445
|
+
var init_dir_listing_subscription = __esm(() => {
|
|
80446
|
+
init_esm();
|
|
80447
|
+
init_daemon_services();
|
|
80448
|
+
init_api3();
|
|
80449
|
+
init_dir_listing_sync();
|
|
80450
|
+
init_workspace_file_search();
|
|
80451
|
+
init_convex_error();
|
|
80452
|
+
});
|
|
80453
|
+
|
|
80454
|
+
// src/infrastructure/services/workspace/workspace-fs-watch-paths.ts
|
|
80455
|
+
function parentDirPath(relativePath) {
|
|
80456
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
80457
|
+
const idx = normalized.lastIndexOf("/");
|
|
80458
|
+
return idx === -1 ? "" : normalized.slice(0, idx);
|
|
80459
|
+
}
|
|
80460
|
+
function shouldIgnoreWatchRelativePath(relativePath) {
|
|
80461
|
+
const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
80462
|
+
if (!normalized || normalized === ".")
|
|
80463
|
+
return false;
|
|
80464
|
+
return hasExcludedDirSegment(normalized);
|
|
80465
|
+
}
|
|
80466
|
+
function dirsToRefreshForEvent(relativePath, isDirectory = false) {
|
|
80467
|
+
const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
80468
|
+
if (!normalized || normalized === ".")
|
|
80469
|
+
return [""];
|
|
80470
|
+
const dirs = new Set;
|
|
80471
|
+
dirs.add(parentDirPath(normalized));
|
|
80472
|
+
if (isDirectory)
|
|
80473
|
+
dirs.add(normalized);
|
|
80474
|
+
return [...dirs];
|
|
80475
|
+
}
|
|
80476
|
+
function filterDirsByActiveSet(dirs, activeDirPaths) {
|
|
80477
|
+
return dirs.filter((d) => activeDirPaths.has(d));
|
|
80478
|
+
}
|
|
80479
|
+
var init_workspace_fs_watch_paths = __esm(() => {
|
|
80480
|
+
init_workspace_visibility_policy();
|
|
80481
|
+
});
|
|
80482
|
+
|
|
80483
|
+
// src/infrastructure/services/workspace/workspace-fs-watcher.ts
|
|
80484
|
+
import { watch } from "node:fs";
|
|
80485
|
+
import path5 from "node:path";
|
|
80486
|
+
function isRecursiveWatchPlatform() {
|
|
80487
|
+
return process.platform === "darwin" || process.platform === "win32";
|
|
80488
|
+
}
|
|
80489
|
+
function normalizeFilename(filename) {
|
|
80490
|
+
if (filename == null)
|
|
80491
|
+
return null;
|
|
80492
|
+
const value = typeof filename === "string" ? filename : filename.toString();
|
|
80493
|
+
if (!value || value === "." || value === "..")
|
|
80494
|
+
return null;
|
|
80495
|
+
return value.replace(/\\/g, "/");
|
|
80496
|
+
}
|
|
80497
|
+
function createWorkspaceFsWatcher(options) {
|
|
80498
|
+
const absWorkingDir = path5.resolve(options.workingDir);
|
|
80499
|
+
const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
80500
|
+
let activeDirPaths = new Set(options.activeDirPaths);
|
|
80501
|
+
let stopped = false;
|
|
80502
|
+
let debounceTimer = null;
|
|
80503
|
+
const pendingDirs = new Set;
|
|
80504
|
+
let rootWatcher = null;
|
|
80505
|
+
const dirWatchers = new Map;
|
|
80506
|
+
const scheduleFlush = () => {
|
|
80507
|
+
if (debounceTimer)
|
|
80508
|
+
clearTimeout(debounceTimer);
|
|
80509
|
+
debounceTimer = setTimeout(() => {
|
|
80510
|
+
debounceTimer = null;
|
|
80511
|
+
if (pendingDirs.size === 0)
|
|
80512
|
+
return;
|
|
80513
|
+
const dirs = [...pendingDirs];
|
|
80514
|
+
pendingDirs.clear();
|
|
80515
|
+
Promise.resolve(options.onRefreshDirs(dirs));
|
|
80516
|
+
}, debounceMs);
|
|
80517
|
+
debounceTimer.unref?.();
|
|
80518
|
+
};
|
|
80519
|
+
const enqueueDirs = (dirs) => {
|
|
80520
|
+
for (const dir of dirs)
|
|
80521
|
+
pendingDirs.add(dir);
|
|
80522
|
+
scheduleFlush();
|
|
80523
|
+
};
|
|
80524
|
+
const handleRelativePath = (relativePath, isDirectory = false) => {
|
|
80525
|
+
if (stopped)
|
|
80526
|
+
return;
|
|
80527
|
+
if (shouldIgnoreWatchRelativePath(relativePath))
|
|
80528
|
+
return;
|
|
80529
|
+
const toRefresh = filterDirsByActiveSet(dirsToRefreshForEvent(relativePath, isDirectory), activeDirPaths);
|
|
80530
|
+
if (toRefresh.length > 0)
|
|
80531
|
+
enqueueDirs(toRefresh);
|
|
80532
|
+
};
|
|
80533
|
+
const onWatchEvent = (watchedDirPath, filename) => {
|
|
80534
|
+
const normalizedFilename = normalizeFilename(filename);
|
|
80535
|
+
if (!normalizedFilename)
|
|
80536
|
+
return;
|
|
80537
|
+
let relativePath;
|
|
80538
|
+
if (isRecursiveWatchPlatform()) {
|
|
80539
|
+
relativePath = normalizedFilename;
|
|
80540
|
+
} else if (watchedDirPath === "") {
|
|
80541
|
+
relativePath = normalizedFilename;
|
|
80542
|
+
} else {
|
|
80543
|
+
relativePath = `${watchedDirPath}/${normalizedFilename}`;
|
|
80544
|
+
}
|
|
80545
|
+
const isDirectory = relativePath.endsWith("/");
|
|
80546
|
+
handleRelativePath(relativePath.replace(/\/+$/, ""), isDirectory);
|
|
80547
|
+
};
|
|
80548
|
+
const closePerDirWatchers = () => {
|
|
80549
|
+
for (const watcher of dirWatchers.values())
|
|
80550
|
+
watcher.close();
|
|
80551
|
+
dirWatchers.clear();
|
|
80552
|
+
};
|
|
80553
|
+
const startPerDirWatch = (dirPath) => {
|
|
80554
|
+
if (dirPath === "" || dirWatchers.has(dirPath))
|
|
80555
|
+
return;
|
|
80556
|
+
const absDir = path5.join(absWorkingDir, dirPath);
|
|
80557
|
+
const watcher = watch(absDir, (_eventType, filename) => {
|
|
80558
|
+
onWatchEvent(dirPath, filename);
|
|
80559
|
+
});
|
|
80560
|
+
dirWatchers.set(dirPath, watcher);
|
|
80561
|
+
};
|
|
80562
|
+
const rewirePerDirWatches = () => {
|
|
80563
|
+
const wanted = new Set;
|
|
80564
|
+
for (const dirPath of activeDirPaths) {
|
|
80565
|
+
if (dirPath !== "")
|
|
80566
|
+
wanted.add(dirPath);
|
|
80567
|
+
}
|
|
80568
|
+
for (const [dirPath, watcher] of dirWatchers) {
|
|
80569
|
+
if (!wanted.has(dirPath)) {
|
|
80570
|
+
watcher.close();
|
|
80571
|
+
dirWatchers.delete(dirPath);
|
|
80572
|
+
}
|
|
80573
|
+
}
|
|
80574
|
+
for (const dirPath of wanted) {
|
|
80575
|
+
if (!dirWatchers.has(dirPath))
|
|
80576
|
+
startPerDirWatch(dirPath);
|
|
80577
|
+
}
|
|
80578
|
+
};
|
|
80579
|
+
const startWatching = () => {
|
|
80580
|
+
if (isRecursiveWatchPlatform()) {
|
|
80581
|
+
rootWatcher = watch(absWorkingDir, { recursive: true }, (_eventType, filename) => {
|
|
80582
|
+
onWatchEvent("", filename);
|
|
80583
|
+
});
|
|
80584
|
+
return;
|
|
80585
|
+
}
|
|
80586
|
+
rootWatcher = watch(absWorkingDir, (_eventType, filename) => {
|
|
80587
|
+
onWatchEvent("", filename);
|
|
80588
|
+
});
|
|
80589
|
+
rewirePerDirWatches();
|
|
80590
|
+
};
|
|
80591
|
+
startWatching();
|
|
80592
|
+
return {
|
|
80593
|
+
updateActiveDirPaths: (paths) => {
|
|
80594
|
+
activeDirPaths = new Set(paths);
|
|
80595
|
+
if (!isRecursiveWatchPlatform() && !stopped) {
|
|
80596
|
+
rewirePerDirWatches();
|
|
80597
|
+
}
|
|
80598
|
+
},
|
|
80599
|
+
stop: () => {
|
|
80600
|
+
stopped = true;
|
|
80601
|
+
if (debounceTimer) {
|
|
80602
|
+
clearTimeout(debounceTimer);
|
|
80603
|
+
debounceTimer = null;
|
|
80604
|
+
}
|
|
80605
|
+
rootWatcher?.close();
|
|
80606
|
+
rootWatcher = null;
|
|
80607
|
+
closePerDirWatchers();
|
|
80608
|
+
pendingDirs.clear();
|
|
80609
|
+
}
|
|
80610
|
+
};
|
|
80611
|
+
}
|
|
80612
|
+
var DEFAULT_DEBOUNCE_MS = 400;
|
|
80613
|
+
var init_workspace_fs_watcher = __esm(() => {
|
|
80614
|
+
init_workspace_fs_watch_paths();
|
|
80615
|
+
});
|
|
80616
|
+
|
|
80617
|
+
// src/commands/machine/daemon-start/dir-listing-watch-subscription.ts
|
|
80618
|
+
var startDirListingWatchSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
80619
|
+
const session2 = yield* DaemonSessionService;
|
|
80620
|
+
const watchers = new Map;
|
|
80621
|
+
const applyTargets = (targets) => {
|
|
80622
|
+
const nextWorkingDirs = new Set(targets.map((t) => t.workingDir));
|
|
80623
|
+
for (const [workingDir, handle] of watchers) {
|
|
80624
|
+
if (!nextWorkingDirs.has(workingDir)) {
|
|
80625
|
+
handle.stop();
|
|
80626
|
+
watchers.delete(workingDir);
|
|
80627
|
+
}
|
|
80628
|
+
}
|
|
80629
|
+
for (const target of targets) {
|
|
80630
|
+
const activeSet = new Set(target.activeDirPaths);
|
|
80631
|
+
const existing = watchers.get(target.workingDir);
|
|
80632
|
+
if (existing) {
|
|
80633
|
+
existing.updateActiveDirPaths(activeSet);
|
|
80634
|
+
continue;
|
|
80635
|
+
}
|
|
80636
|
+
const handle = createWorkspaceFsWatcher({
|
|
80637
|
+
workingDir: target.workingDir,
|
|
80638
|
+
activeDirPaths: activeSet,
|
|
80639
|
+
onRefreshDirs: async (dirPaths) => {
|
|
80640
|
+
try {
|
|
80641
|
+
await syncDirListingsToBackend(session2, target.workingDir, dirPaths);
|
|
80642
|
+
} catch (err) {
|
|
80643
|
+
console.warn(`[${formatTimestamp()}] ⚠️ FS watch sync failed for ${target.workingDir}: ${getErrorMessage(err)}`);
|
|
80644
|
+
}
|
|
80645
|
+
}
|
|
80646
|
+
});
|
|
80647
|
+
watchers.set(target.workingDir, handle);
|
|
80648
|
+
}
|
|
80649
|
+
};
|
|
80650
|
+
let stopped = false;
|
|
80651
|
+
const unsub = wsClient2.onUpdate(api.workspaceFiles.listDirListingWatchTargets, { sessionId: session2.sessionId, machineId: session2.machineId }, (targets) => {
|
|
80652
|
+
if (stopped)
|
|
80653
|
+
return;
|
|
80654
|
+
applyTargets(targets ?? []);
|
|
80655
|
+
}, (err) => {
|
|
80656
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Dir listing watch subscription error: ${getErrorMessage(err)}`);
|
|
80657
|
+
});
|
|
80658
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription started`);
|
|
80659
|
+
return {
|
|
80660
|
+
stop: () => {
|
|
80661
|
+
stopped = true;
|
|
80662
|
+
unsub();
|
|
80663
|
+
for (const handle of watchers.values())
|
|
80664
|
+
handle.stop();
|
|
80665
|
+
watchers.clear();
|
|
80666
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription stopped`);
|
|
80667
|
+
}
|
|
80668
|
+
};
|
|
80669
|
+
});
|
|
80670
|
+
var init_dir_listing_watch_subscription = __esm(() => {
|
|
80671
|
+
init_esm();
|
|
80672
|
+
init_daemon_services();
|
|
80673
|
+
init_api3();
|
|
80674
|
+
init_dir_listing_sync();
|
|
80675
|
+
init_workspace_fs_watcher();
|
|
80676
|
+
init_convex_error();
|
|
80677
|
+
});
|
|
80678
|
+
|
|
79920
80679
|
// src/events/daemon/agent/on-request-start-agent.ts
|
|
79921
80680
|
function notifyAgentStartFailed(backend2, opts) {
|
|
79922
80681
|
backend2.mutation(api.machines.emitAgentStartFailed, opts).catch((err) => {
|
|
@@ -80016,13 +80775,8 @@ var init_on_request_stop_agent = __esm(() => {
|
|
|
80016
80775
|
init_stop_agent();
|
|
80017
80776
|
});
|
|
80018
80777
|
|
|
80019
|
-
// src/commands/machine/daemon-start/utils.ts
|
|
80020
|
-
function formatTimestamp() {
|
|
80021
|
-
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
80022
|
-
}
|
|
80023
|
-
|
|
80024
80778
|
// src/commands/machine/daemon-start/handlers/orphan-tracker.ts
|
|
80025
|
-
import { createHash as
|
|
80779
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
80026
80780
|
import {
|
|
80027
80781
|
appendFileSync,
|
|
80028
80782
|
existsSync as existsSync5,
|
|
@@ -80036,7 +80790,7 @@ import { homedir as homedir5 } from "node:os";
|
|
|
80036
80790
|
import { join as join15 } from "node:path";
|
|
80037
80791
|
function getUrlHash() {
|
|
80038
80792
|
const url2 = getConvexUrl();
|
|
80039
|
-
return
|
|
80793
|
+
return createHash4("sha256").update(url2).digest("hex").substring(0, 8);
|
|
80040
80794
|
}
|
|
80041
80795
|
function getChildPidsFilePath() {
|
|
80042
80796
|
const dir = join15(homedir5(), ".chatroom");
|
|
@@ -80230,19 +80984,19 @@ class ProcessManager {
|
|
|
80230
80984
|
this.pendingStops.clear();
|
|
80231
80985
|
}
|
|
80232
80986
|
waitForExit(runId, ms) {
|
|
80233
|
-
return new Promise((
|
|
80987
|
+
return new Promise((resolve4) => {
|
|
80234
80988
|
const interval = 100;
|
|
80235
80989
|
let elapsed3 = 0;
|
|
80236
80990
|
const timer = setInterval(() => {
|
|
80237
80991
|
if (!this.runningProcesses.has(runId)) {
|
|
80238
80992
|
clearInterval(timer);
|
|
80239
|
-
|
|
80993
|
+
resolve4(true);
|
|
80240
80994
|
return;
|
|
80241
80995
|
}
|
|
80242
80996
|
elapsed3 += interval;
|
|
80243
80997
|
if (elapsed3 >= ms) {
|
|
80244
80998
|
clearInterval(timer);
|
|
80245
|
-
|
|
80999
|
+
resolve4(false);
|
|
80246
81000
|
}
|
|
80247
81001
|
}, interval);
|
|
80248
81002
|
});
|
|
@@ -80277,9 +81031,9 @@ var init_killer = __esm(() => {
|
|
|
80277
81031
|
});
|
|
80278
81032
|
|
|
80279
81033
|
// ../../services/backend/src/output-encoding.ts
|
|
80280
|
-
import { gunzipSync, gzipSync } from "node:zlib";
|
|
81034
|
+
import { gunzipSync as gunzipSync2, gzipSync as gzipSync3 } from "node:zlib";
|
|
80281
81035
|
function encodeOutput(plain) {
|
|
80282
|
-
const compressed =
|
|
81036
|
+
const compressed = gzipSync3(Buffer.from(plain, "utf-8"));
|
|
80283
81037
|
return {
|
|
80284
81038
|
compression: "gzip",
|
|
80285
81039
|
content: compressed.toString("base64")
|
|
@@ -80457,7 +81211,7 @@ var init_output_store = __esm(() => {
|
|
|
80457
81211
|
});
|
|
80458
81212
|
|
|
80459
81213
|
// src/commands/machine/daemon-start/handlers/process/spawner.ts
|
|
80460
|
-
import { spawn as
|
|
81214
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
80461
81215
|
async function flushTailV2(deps, tracked, force = false) {
|
|
80462
81216
|
if (!force && !isRunLogObserved(tracked.runId))
|
|
80463
81217
|
return;
|
|
@@ -80540,7 +81294,7 @@ async function spawnCommandProcess(deps, event, commandKey) {
|
|
|
80540
81294
|
tempDirReady = true;
|
|
80541
81295
|
}
|
|
80542
81296
|
const store = createOutputStore(runIdStr);
|
|
80543
|
-
const child =
|
|
81297
|
+
const child = spawn4("sh", ["-c", script], {
|
|
80544
81298
|
cwd: workingDir,
|
|
80545
81299
|
env: buildChatroomSpawnEnv(deps.convexUrl),
|
|
80546
81300
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -80802,8 +81556,8 @@ var init_command_runner = __esm(() => {
|
|
|
80802
81556
|
}).catch((err) => {
|
|
80803
81557
|
console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as killed on shutdown: ${getErrorMessage(err)}`);
|
|
80804
81558
|
})));
|
|
80805
|
-
yield* exports_Effect.promise(() => new Promise((
|
|
80806
|
-
const t = setTimeout(
|
|
81559
|
+
yield* exports_Effect.promise(() => new Promise((resolve4) => {
|
|
81560
|
+
const t = setTimeout(resolve4, 3000);
|
|
80807
81561
|
t.unref?.();
|
|
80808
81562
|
}));
|
|
80809
81563
|
for (const [, tracked] of trackedEntries) {
|
|
@@ -80815,8 +81569,8 @@ var init_command_runner = __esm(() => {
|
|
|
80815
81569
|
clearTrackedPids();
|
|
80816
81570
|
yield* exports_Effect.promise(() => Promise.race([
|
|
80817
81571
|
statusUpdates,
|
|
80818
|
-
new Promise((
|
|
80819
|
-
const t = setTimeout(
|
|
81572
|
+
new Promise((resolve4) => {
|
|
81573
|
+
const t = setTimeout(resolve4, 2000);
|
|
80820
81574
|
t.unref?.();
|
|
80821
81575
|
})
|
|
80822
81576
|
]));
|
|
@@ -80851,28 +81605,81 @@ var init_on_daemon_shutdown = __esm(() => {
|
|
|
80851
81605
|
connected: false
|
|
80852
81606
|
}).catch(() => {}));
|
|
80853
81607
|
});
|
|
80854
|
-
});
|
|
80855
|
-
|
|
80856
|
-
// src/infrastructure/git/types.ts
|
|
80857
|
-
function makeGitStateKey(machineId, workingDir) {
|
|
80858
|
-
return `${machineId}::${workingDir}`;
|
|
81608
|
+
});
|
|
81609
|
+
|
|
81610
|
+
// src/infrastructure/git/types.ts
|
|
81611
|
+
function makeGitStateKey(machineId, workingDir) {
|
|
81612
|
+
return `${machineId}::${workingDir}`;
|
|
81613
|
+
}
|
|
81614
|
+
var FULL_DIFF_MAX_BYTES = 500000, COMMITS_PER_PAGE = 20;
|
|
81615
|
+
|
|
81616
|
+
// src/infrastructure/git/run-command.ts
|
|
81617
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
81618
|
+
function runCommandSpawn(command, args2, cwd, options) {
|
|
81619
|
+
return new Promise((resolve4) => {
|
|
81620
|
+
const child = spawn5(command, args2, {
|
|
81621
|
+
cwd,
|
|
81622
|
+
env: options?.env ?? DEFAULT_GIT_ENV,
|
|
81623
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
81624
|
+
});
|
|
81625
|
+
let stdout = "";
|
|
81626
|
+
let stderr = "";
|
|
81627
|
+
const maxBuffer = options?.maxBuffer ?? 10 * 1024 * 1024;
|
|
81628
|
+
const onData = (chunk2, target) => {
|
|
81629
|
+
const str = chunk2.toString();
|
|
81630
|
+
if (target === "stdout")
|
|
81631
|
+
stdout += str;
|
|
81632
|
+
else
|
|
81633
|
+
stderr += str;
|
|
81634
|
+
if (stdout.length + stderr.length > maxBuffer) {
|
|
81635
|
+
child.kill("SIGTERM");
|
|
81636
|
+
}
|
|
81637
|
+
};
|
|
81638
|
+
child.stdout?.on("data", (c) => onData(c, "stdout"));
|
|
81639
|
+
child.stderr?.on("data", (c) => onData(c, "stderr"));
|
|
81640
|
+
const timer = options?.timeout ? setTimeout(() => child.kill("SIGTERM"), options.timeout) : undefined;
|
|
81641
|
+
child.on("close", (code2) => {
|
|
81642
|
+
if (timer)
|
|
81643
|
+
clearTimeout(timer);
|
|
81644
|
+
if (code2 === 0)
|
|
81645
|
+
resolve4({ stdout, stderr });
|
|
81646
|
+
else {
|
|
81647
|
+
resolve4({
|
|
81648
|
+
error: Object.assign(new Error(stderr || stdout || `exit ${code2}`), {
|
|
81649
|
+
code: code2 ?? undefined
|
|
81650
|
+
})
|
|
81651
|
+
});
|
|
81652
|
+
}
|
|
81653
|
+
});
|
|
81654
|
+
child.on("error", (err) => {
|
|
81655
|
+
if (timer)
|
|
81656
|
+
clearTimeout(timer);
|
|
81657
|
+
resolve4({ error: err });
|
|
81658
|
+
});
|
|
81659
|
+
});
|
|
80859
81660
|
}
|
|
80860
|
-
|
|
81661
|
+
function runGit(args2, cwd, options) {
|
|
81662
|
+
return runCommandSpawn("git", args2, cwd, options);
|
|
81663
|
+
}
|
|
81664
|
+
function runGh(args2, cwd, options) {
|
|
81665
|
+
return runCommandSpawn("gh", args2, cwd, {
|
|
81666
|
+
timeout: options?.timeout,
|
|
81667
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
81668
|
+
});
|
|
81669
|
+
}
|
|
81670
|
+
var DEFAULT_GIT_ENV;
|
|
81671
|
+
var init_run_command = __esm(() => {
|
|
81672
|
+
DEFAULT_GIT_ENV = {
|
|
81673
|
+
...process.env,
|
|
81674
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
81675
|
+
GIT_PAGER: "cat",
|
|
81676
|
+
NO_COLOR: "1"
|
|
81677
|
+
};
|
|
81678
|
+
});
|
|
80861
81679
|
|
|
80862
81680
|
// src/infrastructure/git/git-reader.ts
|
|
80863
|
-
|
|
80864
|
-
|
|
80865
|
-
async function runGit(args2, cwd) {
|
|
80866
|
-
try {
|
|
80867
|
-
const result = await execAsync2(`git ${args2}`, {
|
|
80868
|
-
cwd,
|
|
80869
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" },
|
|
80870
|
-
maxBuffer: FULL_DIFF_MAX_BYTES + 64 * 1024
|
|
80871
|
-
});
|
|
80872
|
-
return result;
|
|
80873
|
-
} catch (err) {
|
|
80874
|
-
return { error: err };
|
|
80875
|
-
}
|
|
81681
|
+
function repoArgs(repoSlug) {
|
|
81682
|
+
return repoSlug ? ["--repo", repoSlug] : [];
|
|
80876
81683
|
}
|
|
80877
81684
|
function isGitNotInstalled(message) {
|
|
80878
81685
|
return message.includes("command not found") || message.includes("ENOENT") || message.includes("not found") || message.includes("'git' is not recognized");
|
|
@@ -80898,14 +81705,14 @@ function classifyError(errMessage) {
|
|
|
80898
81705
|
}
|
|
80899
81706
|
return { status: "error", message: errMessage.trim() };
|
|
80900
81707
|
}
|
|
80901
|
-
async function
|
|
80902
|
-
const result = await runGit("rev-parse --git-dir", workingDir);
|
|
81708
|
+
async function isGitRepo2(workingDir) {
|
|
81709
|
+
const result = await runGit(["rev-parse", "--git-dir"], workingDir);
|
|
80903
81710
|
if ("error" in result)
|
|
80904
81711
|
return false;
|
|
80905
81712
|
return result.stdout.trim().length > 0;
|
|
80906
81713
|
}
|
|
80907
81714
|
async function getBranch(workingDir) {
|
|
80908
|
-
const result = await runGit("rev-parse --abbrev-ref HEAD", workingDir);
|
|
81715
|
+
const result = await runGit(["rev-parse", "--abbrev-ref", "HEAD"], workingDir);
|
|
80909
81716
|
if ("error" in result) {
|
|
80910
81717
|
const errMsg = result.error.message;
|
|
80911
81718
|
if (errMsg.includes("unknown revision") || errMsg.includes("No such file or directory") || errMsg.includes("does not have any commits")) {
|
|
@@ -80920,7 +81727,7 @@ async function getBranch(workingDir) {
|
|
|
80920
81727
|
return { status: "available", branch };
|
|
80921
81728
|
}
|
|
80922
81729
|
async function isDirty(workingDir) {
|
|
80923
|
-
const result = await runGit("status --porcelain", workingDir);
|
|
81730
|
+
const result = await runGit(["status", "--porcelain"], workingDir);
|
|
80924
81731
|
if ("error" in result)
|
|
80925
81732
|
return false;
|
|
80926
81733
|
return result.stdout.trim().length > 0;
|
|
@@ -80936,7 +81743,7 @@ function parseDiffStatLine(statLine) {
|
|
|
80936
81743
|
};
|
|
80937
81744
|
}
|
|
80938
81745
|
async function getDiffStat(workingDir) {
|
|
80939
|
-
const result = await runGit("diff HEAD --stat", workingDir);
|
|
81746
|
+
const result = await runGit(["diff", "HEAD", "--stat"], workingDir);
|
|
80940
81747
|
if ("error" in result) {
|
|
80941
81748
|
const errMsg = result.error.message;
|
|
80942
81749
|
if (isEmptyRepo(result.error.message)) {
|
|
@@ -80965,7 +81772,9 @@ async function getDiffStat(workingDir) {
|
|
|
80965
81772
|
return { status: "available", diffStat };
|
|
80966
81773
|
}
|
|
80967
81774
|
async function getFullDiff(workingDir) {
|
|
80968
|
-
const result = await runGit("diff HEAD", workingDir
|
|
81775
|
+
const result = await runGit(["diff", "HEAD"], workingDir, {
|
|
81776
|
+
maxBuffer: FULL_DIFF_MAX_BYTES + 64 * 1024
|
|
81777
|
+
});
|
|
80969
81778
|
if ("error" in result) {
|
|
80970
81779
|
const errMsg = result.error.message;
|
|
80971
81780
|
if (isEmptyRepo(errMsg)) {
|
|
@@ -80990,8 +81799,7 @@ async function getFullDiff(workingDir) {
|
|
|
80990
81799
|
}
|
|
80991
81800
|
async function getPRDiffByNumber(cwd, prNumber) {
|
|
80992
81801
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
80993
|
-
const
|
|
80994
|
-
const result = await runCommand(`gh pr diff ${prNumber}${repoFlag}`, cwd);
|
|
81802
|
+
const result = await runGh(["pr", "diff", String(prNumber), ...repoArgs(repoSlug)], cwd);
|
|
80995
81803
|
if ("error" in result) {
|
|
80996
81804
|
return { status: "error", message: result.error.message };
|
|
80997
81805
|
}
|
|
@@ -81008,8 +81816,11 @@ async function getPRDiffByNumber(cwd, prNumber) {
|
|
|
81008
81816
|
}
|
|
81009
81817
|
async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
|
|
81010
81818
|
const format4 = "%H%x1f%h%x1f%s%x1f%b%x1f%an%x1f%aI%x1e";
|
|
81011
|
-
const
|
|
81012
|
-
|
|
81819
|
+
const logArgs = ["log", `-${count3}`];
|
|
81820
|
+
if (skip > 0)
|
|
81821
|
+
logArgs.push(`--skip=${skip}`);
|
|
81822
|
+
logArgs.push(`--format=${format4}`);
|
|
81823
|
+
const result = await runGit(logArgs, workingDir);
|
|
81013
81824
|
if ("error" in result) {
|
|
81014
81825
|
return [];
|
|
81015
81826
|
}
|
|
@@ -81031,7 +81842,7 @@ async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
|
|
|
81031
81842
|
return commits;
|
|
81032
81843
|
}
|
|
81033
81844
|
async function getCommitDetail(workingDir, sha) {
|
|
81034
|
-
const result = await runGit(
|
|
81845
|
+
const result = await runGit(["show", sha, "--format=", "--stat", "-p"], workingDir);
|
|
81035
81846
|
if ("error" in result) {
|
|
81036
81847
|
const errMsg = result.error.message;
|
|
81037
81848
|
const classified = classifyError(errMsg);
|
|
@@ -81052,7 +81863,7 @@ async function getCommitDetail(workingDir, sha) {
|
|
|
81052
81863
|
}
|
|
81053
81864
|
async function getCommitMetadata(workingDir, sha) {
|
|
81054
81865
|
const format4 = "%s%x1f%b%x1f%an%x1f%aI";
|
|
81055
|
-
const result = await runGit(
|
|
81866
|
+
const result = await runGit(["log", "-1", `--format=${format4}`, sha], workingDir);
|
|
81056
81867
|
if ("error" in result)
|
|
81057
81868
|
return null;
|
|
81058
81869
|
const output = result.stdout.trim();
|
|
@@ -81065,18 +81876,6 @@ async function getCommitMetadata(workingDir, sha) {
|
|
|
81065
81876
|
const body = rawBody.trim();
|
|
81066
81877
|
return { message, ...body ? { body } : {}, author, date };
|
|
81067
81878
|
}
|
|
81068
|
-
async function runCommand(command, cwd) {
|
|
81069
|
-
try {
|
|
81070
|
-
const result = await execAsync2(command, {
|
|
81071
|
-
cwd,
|
|
81072
|
-
env: { ...process.env, NO_COLOR: "1" },
|
|
81073
|
-
timeout: 15000
|
|
81074
|
-
});
|
|
81075
|
-
return result;
|
|
81076
|
-
} catch (err) {
|
|
81077
|
-
return { error: err };
|
|
81078
|
-
}
|
|
81079
|
-
}
|
|
81080
81879
|
function parseRepoSlug(remoteUrl) {
|
|
81081
81880
|
const trimmed = remoteUrl.trim();
|
|
81082
81881
|
const httpsMatch = trimmed.match(/https?:\/\/[^/]+\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -81090,7 +81889,7 @@ function parseRepoSlug(remoteUrl) {
|
|
|
81090
81889
|
return null;
|
|
81091
81890
|
}
|
|
81092
81891
|
async function getOriginRepoSlug(cwd) {
|
|
81093
|
-
const result = await runGit("remote get-url origin", cwd);
|
|
81892
|
+
const result = await runGit(["remote", "get-url", "origin"], cwd);
|
|
81094
81893
|
if ("error" in result)
|
|
81095
81894
|
return null;
|
|
81096
81895
|
const url2 = result.stdout.trim();
|
|
@@ -81100,9 +81899,22 @@ async function getOriginRepoSlug(cwd) {
|
|
|
81100
81899
|
}
|
|
81101
81900
|
async function getOpenPRsForBranch(cwd, branch) {
|
|
81102
81901
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
81103
|
-
const repoFlag = repoSlug ? ` --repo ${JSON.stringify(repoSlug)}` : "";
|
|
81104
81902
|
const repoOwner = repoSlug?.split("/")[0] ?? null;
|
|
81105
|
-
const result = await
|
|
81903
|
+
const result = await runGh([
|
|
81904
|
+
"pr",
|
|
81905
|
+
"list",
|
|
81906
|
+
"--head",
|
|
81907
|
+
branch,
|
|
81908
|
+
"--state",
|
|
81909
|
+
"open",
|
|
81910
|
+
"--author",
|
|
81911
|
+
"@me",
|
|
81912
|
+
"--json",
|
|
81913
|
+
"number,title,url,headRefName,state,headRepositoryOwner",
|
|
81914
|
+
"--limit",
|
|
81915
|
+
"5",
|
|
81916
|
+
...repoArgs(repoSlug)
|
|
81917
|
+
], cwd);
|
|
81106
81918
|
if ("error" in result) {
|
|
81107
81919
|
return [];
|
|
81108
81920
|
}
|
|
@@ -81133,8 +81945,17 @@ function isGHPRItem(item) {
|
|
|
81133
81945
|
}
|
|
81134
81946
|
async function getAllPRs(cwd) {
|
|
81135
81947
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
81136
|
-
const
|
|
81137
|
-
|
|
81948
|
+
const result = await runGh([
|
|
81949
|
+
"pr",
|
|
81950
|
+
"list",
|
|
81951
|
+
"--limit",
|
|
81952
|
+
"20",
|
|
81953
|
+
"--state",
|
|
81954
|
+
"all",
|
|
81955
|
+
"--json",
|
|
81956
|
+
"number,title,state,headRefName,baseRefName,url,author,createdAt,updatedAt,mergedAt,closedAt,isDraft",
|
|
81957
|
+
...repoArgs(repoSlug)
|
|
81958
|
+
], cwd);
|
|
81138
81959
|
if ("error" in result) {
|
|
81139
81960
|
return [];
|
|
81140
81961
|
}
|
|
@@ -81168,8 +81989,7 @@ async function getAllPRs(cwd) {
|
|
|
81168
81989
|
}
|
|
81169
81990
|
async function getPRCommits(cwd, prNumber) {
|
|
81170
81991
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
81171
|
-
const
|
|
81172
|
-
const result = await runCommand(`gh pr view ${prNumber} --json commits${repoFlag}`, cwd);
|
|
81992
|
+
const result = await runGh(["pr", "view", String(prNumber), "--json", "commits", ...repoArgs(repoSlug)], cwd);
|
|
81173
81993
|
if ("error" in result) {
|
|
81174
81994
|
return [];
|
|
81175
81995
|
}
|
|
@@ -81206,7 +82026,7 @@ async function getPRCommits(cwd, prNumber) {
|
|
|
81206
82026
|
}
|
|
81207
82027
|
}
|
|
81208
82028
|
async function getRemotes(cwd) {
|
|
81209
|
-
const result = await runGit("remote -v", cwd);
|
|
82029
|
+
const result = await runGit(["remote", "-v"], cwd);
|
|
81210
82030
|
if ("error" in result)
|
|
81211
82031
|
return [];
|
|
81212
82032
|
if (!result.stdout.trim())
|
|
@@ -81230,14 +82050,14 @@ async function getRemotes(cwd) {
|
|
|
81230
82050
|
return remotes;
|
|
81231
82051
|
}
|
|
81232
82052
|
async function getCommitsAhead(workingDir) {
|
|
81233
|
-
const result = await runGit("rev-list --count @{upstream}..HEAD", workingDir);
|
|
82053
|
+
const result = await runGit(["rev-list", "--count", "@{upstream}..HEAD"], workingDir);
|
|
81234
82054
|
if ("error" in result)
|
|
81235
82055
|
return 0;
|
|
81236
82056
|
const count3 = parseInt(result.stdout.trim(), 10);
|
|
81237
82057
|
return Number.isNaN(count3) ? 0 : count3;
|
|
81238
82058
|
}
|
|
81239
82059
|
async function getCommitsBehind(workingDir) {
|
|
81240
|
-
const result = await runGit("rev-list --count HEAD..@{upstream}", workingDir);
|
|
82060
|
+
const result = await runGit(["rev-list", "--count", "HEAD..@{upstream}"], workingDir);
|
|
81241
82061
|
if ("error" in result)
|
|
81242
82062
|
return 0;
|
|
81243
82063
|
const count3 = parseInt(result.stdout.trim(), 10);
|
|
@@ -81249,8 +82069,18 @@ async function getCommitStatusChecks(cwd, ref) {
|
|
|
81249
82069
|
return null;
|
|
81250
82070
|
try {
|
|
81251
82071
|
const [checkRunsResult, legacyStatusesResult] = await Promise.all([
|
|
81252
|
-
|
|
81253
|
-
|
|
82072
|
+
runGh([
|
|
82073
|
+
"api",
|
|
82074
|
+
`repos/${repoSlug}/commits/${encodeURIComponent(ref)}/check-runs`,
|
|
82075
|
+
"--jq",
|
|
82076
|
+
"{check_runs: [.check_runs[] | {name: .name, status: .status, conclusion: .conclusion}], total_count: .total_count}"
|
|
82077
|
+
], cwd),
|
|
82078
|
+
runGh([
|
|
82079
|
+
"api",
|
|
82080
|
+
`repos/${repoSlug}/commits/${encodeURIComponent(ref)}/statuses`,
|
|
82081
|
+
"--jq",
|
|
82082
|
+
"[group_by(.context)[] | max_by(.created_at) | {context: .context, state: .state, target_url: .target_url}]"
|
|
82083
|
+
], cwd)
|
|
81254
82084
|
]);
|
|
81255
82085
|
if ("error" in checkRunsResult || "error" in legacyStatusesResult)
|
|
81256
82086
|
return null;
|
|
@@ -81303,49 +82133,34 @@ async function getCommitStatusChecks(cwd, ref) {
|
|
|
81303
82133
|
return null;
|
|
81304
82134
|
}
|
|
81305
82135
|
}
|
|
81306
|
-
var execAsync2;
|
|
81307
82136
|
var init_git_reader = __esm(() => {
|
|
81308
|
-
|
|
82137
|
+
init_run_command();
|
|
81309
82138
|
});
|
|
81310
82139
|
|
|
81311
82140
|
// src/infrastructure/git/git-writer.ts
|
|
81312
|
-
import { exec as exec3 } from "node:child_process";
|
|
81313
|
-
import { promisify as promisify3 } from "node:util";
|
|
81314
|
-
async function runGit2(args2, cwd) {
|
|
81315
|
-
try {
|
|
81316
|
-
const result = await execAsync3(`git ${args2}`, {
|
|
81317
|
-
cwd,
|
|
81318
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" },
|
|
81319
|
-
timeout: 30000
|
|
81320
|
-
});
|
|
81321
|
-
return result;
|
|
81322
|
-
} catch (err) {
|
|
81323
|
-
return { error: err };
|
|
81324
|
-
}
|
|
81325
|
-
}
|
|
81326
82141
|
function classifyError2(errMessage) {
|
|
81327
82142
|
return { status: "error", message: errMessage.trim() };
|
|
81328
82143
|
}
|
|
81329
82144
|
async function discardFile(workingDir, filePath) {
|
|
81330
|
-
const result = await
|
|
82145
|
+
const result = await runGit(["checkout", "--", filePath], workingDir);
|
|
81331
82146
|
if ("error" in result) {
|
|
81332
82147
|
return classifyError2(result.error.message);
|
|
81333
82148
|
}
|
|
81334
82149
|
return { status: "available" };
|
|
81335
82150
|
}
|
|
81336
82151
|
async function discardAllChanges(workingDir) {
|
|
81337
|
-
const checkoutResult = await
|
|
82152
|
+
const checkoutResult = await runGit(["checkout", "--", "."], workingDir);
|
|
81338
82153
|
if ("error" in checkoutResult) {
|
|
81339
82154
|
return classifyError2(checkoutResult.error.message);
|
|
81340
82155
|
}
|
|
81341
|
-
const cleanResult = await
|
|
82156
|
+
const cleanResult = await runGit(["clean", "-fd"], workingDir);
|
|
81342
82157
|
if ("error" in cleanResult) {
|
|
81343
82158
|
return classifyError2(cleanResult.error.message);
|
|
81344
82159
|
}
|
|
81345
82160
|
return { status: "available" };
|
|
81346
82161
|
}
|
|
81347
82162
|
async function gitPull(workingDir) {
|
|
81348
|
-
const result = await
|
|
82163
|
+
const result = await runGit(["pull"], workingDir);
|
|
81349
82164
|
if ("error" in result) {
|
|
81350
82165
|
const message = result.error.message;
|
|
81351
82166
|
if (message.includes("no tracking branch")) {
|
|
@@ -81372,7 +82187,7 @@ async function gitPull(workingDir) {
|
|
|
81372
82187
|
return { status: "available" };
|
|
81373
82188
|
}
|
|
81374
82189
|
async function gitPush(workingDir) {
|
|
81375
|
-
const result = await
|
|
82190
|
+
const result = await runGit(["push"], workingDir);
|
|
81376
82191
|
if ("error" in result) {
|
|
81377
82192
|
const message = result.error.message;
|
|
81378
82193
|
if (message.includes("no upstream branch")) {
|
|
@@ -81402,9 +82217,8 @@ async function gitSync(workingDir) {
|
|
|
81402
82217
|
}
|
|
81403
82218
|
return gitPush(workingDir);
|
|
81404
82219
|
}
|
|
81405
|
-
var execAsync3;
|
|
81406
82220
|
var init_git_writer = __esm(() => {
|
|
81407
|
-
|
|
82221
|
+
init_run_command();
|
|
81408
82222
|
});
|
|
81409
82223
|
|
|
81410
82224
|
// src/infrastructure/git/index.ts
|
|
@@ -81414,7 +82228,7 @@ var init_git = __esm(() => {
|
|
|
81414
82228
|
});
|
|
81415
82229
|
|
|
81416
82230
|
// src/infrastructure/local-actions/execute-local-action.ts
|
|
81417
|
-
import { exec as
|
|
82231
|
+
import { exec as exec3 } from "node:child_process";
|
|
81418
82232
|
import { access as access3 } from "node:fs/promises";
|
|
81419
82233
|
function escapeShellArg(arg) {
|
|
81420
82234
|
return `"${arg.replace(/"/g, "\\\"")}"`;
|
|
@@ -81423,14 +82237,14 @@ function resolveWhichCommand(name) {
|
|
|
81423
82237
|
return process.platform === "win32" ? `where ${name}` : `which ${name}`;
|
|
81424
82238
|
}
|
|
81425
82239
|
function isCliAvailable(cliName) {
|
|
81426
|
-
return new Promise((
|
|
81427
|
-
|
|
81428
|
-
|
|
82240
|
+
return new Promise((resolve4) => {
|
|
82241
|
+
exec3(resolveWhichCommand(cliName), (err) => {
|
|
82242
|
+
resolve4(!err);
|
|
81429
82243
|
});
|
|
81430
82244
|
});
|
|
81431
82245
|
}
|
|
81432
82246
|
function execFireAndForget(command, logTag) {
|
|
81433
|
-
|
|
82247
|
+
exec3(command, (err) => {
|
|
81434
82248
|
if (err) {
|
|
81435
82249
|
console.warn(`[${logTag}] exec failed: ${err.message}`);
|
|
81436
82250
|
}
|
|
@@ -81546,13 +82360,13 @@ var init_local_actions = __esm(() => {
|
|
|
81546
82360
|
});
|
|
81547
82361
|
|
|
81548
82362
|
// src/commands/machine/pid.ts
|
|
81549
|
-
import { createHash as
|
|
82363
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
81550
82364
|
import { existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
81551
82365
|
import { homedir as homedir6 } from "node:os";
|
|
81552
82366
|
import { join as join17 } from "node:path";
|
|
81553
82367
|
function getUrlHash2() {
|
|
81554
82368
|
const url2 = getConvexUrl();
|
|
81555
|
-
return
|
|
82369
|
+
return createHash5("sha256").update(url2).digest("hex").substring(0, 8);
|
|
81556
82370
|
}
|
|
81557
82371
|
function getPidFileName() {
|
|
81558
82372
|
return `daemon-${getUrlHash2()}.pid`;
|
|
@@ -81645,7 +82459,7 @@ async function waitForLockOrTimeout(deadline, intervalMs, sleep5) {
|
|
|
81645
82459
|
async function acquireLockWithRetry(options) {
|
|
81646
82460
|
const intervalMs = options?.intervalMs ?? LOCK_RETRY_INTERVAL_MS;
|
|
81647
82461
|
const maxWaitMs = options?.maxWaitMs ?? LOCK_RETRY_MAX_WAIT_MS;
|
|
81648
|
-
const sleep5 = options?.sleep ?? ((ms) => new Promise((
|
|
82462
|
+
const sleep5 = options?.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
|
|
81649
82463
|
const deadline = Date.now() + maxWaitMs;
|
|
81650
82464
|
if (await waitForLockOrTimeout(deadline, intervalMs, sleep5)) {
|
|
81651
82465
|
return true;
|
|
@@ -82573,7 +83387,7 @@ var init_jsonc = __esm(() => {
|
|
|
82573
83387
|
|
|
82574
83388
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
82575
83389
|
import { readFile as readFile7, readdir, stat as stat2 } from "node:fs/promises";
|
|
82576
|
-
import { join as join18, basename, resolve as
|
|
83390
|
+
import { join as join18, basename as basename2, resolve as resolve4 } from "node:path";
|
|
82577
83391
|
async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
82578
83392
|
const parentDir = join18(rootDir, cleaned.slice(0, -2));
|
|
82579
83393
|
try {
|
|
@@ -82583,7 +83397,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
82583
83397
|
if (!entry.isDirectory())
|
|
82584
83398
|
continue;
|
|
82585
83399
|
const dirPath = join18(parentDir, entry.name);
|
|
82586
|
-
if (
|
|
83400
|
+
if (resolve4(dirPath).startsWith(resolve4(rootDir))) {
|
|
82587
83401
|
dirs.push(dirPath);
|
|
82588
83402
|
}
|
|
82589
83403
|
}
|
|
@@ -82595,7 +83409,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
82595
83409
|
async function resolveLiteralPath(rootDir, cleaned) {
|
|
82596
83410
|
const dir = join18(rootDir, cleaned);
|
|
82597
83411
|
try {
|
|
82598
|
-
if (!
|
|
83412
|
+
if (!resolve4(dir).startsWith(resolve4(rootDir)))
|
|
82599
83413
|
return [];
|
|
82600
83414
|
const s = await stat2(dir);
|
|
82601
83415
|
if (s.isDirectory())
|
|
@@ -82616,7 +83430,7 @@ async function readPackageJson(dir) {
|
|
|
82616
83430
|
const content = await readFile7(join18(dir, "package.json"), "utf-8");
|
|
82617
83431
|
const pkg = JSON.parse(content);
|
|
82618
83432
|
return {
|
|
82619
|
-
name: pkg.name ||
|
|
83433
|
+
name: pkg.name || basename2(dir),
|
|
82620
83434
|
scripts: pkg.scripts && typeof pkg.scripts === "object" ? pkg.scripts : {}
|
|
82621
83435
|
};
|
|
82622
83436
|
} catch {
|
|
@@ -82701,7 +83515,7 @@ var init_workspace_resolver = () => {};
|
|
|
82701
83515
|
|
|
82702
83516
|
// src/infrastructure/services/workspace/command-discovery.ts
|
|
82703
83517
|
import { access as access4, readFile as readFile8 } from "node:fs/promises";
|
|
82704
|
-
import { join as join19, relative, basename as
|
|
83518
|
+
import { join as join19, relative as relative2, basename as basename3 } from "node:path";
|
|
82705
83519
|
async function detectPackageManager(workingDir) {
|
|
82706
83520
|
for (const { file, manager } of LOCKFILE_MAP) {
|
|
82707
83521
|
try {
|
|
@@ -82773,7 +83587,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
|
|
|
82773
83587
|
return commands;
|
|
82774
83588
|
}
|
|
82775
83589
|
async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
82776
|
-
let rootPackageName =
|
|
83590
|
+
let rootPackageName = basename3(workingDir);
|
|
82777
83591
|
const pkg = await readJsonFile(join19(workingDir, "package.json"), "root package.json");
|
|
82778
83592
|
if (!pkg)
|
|
82779
83593
|
return { commands: [], rootPackageName };
|
|
@@ -82819,7 +83633,7 @@ async function discoverCommands(workingDir) {
|
|
|
82819
83633
|
}
|
|
82820
83634
|
const subWorkspaces = await resolveSubWorkspaces(workingDir, pm);
|
|
82821
83635
|
for (const pkg of subWorkspaces) {
|
|
82822
|
-
const wsPath =
|
|
83636
|
+
const wsPath = relative2(workingDir, pkg.dir) || ".";
|
|
82823
83637
|
const pkgSubWorkspace = { type: "npm", path: wsPath, name: pkg.name };
|
|
82824
83638
|
await addSubWorkspaceCommands(commands, pm, pkg, wsPath, pkgSubWorkspace, turboTaskNames);
|
|
82825
83639
|
}
|
|
@@ -82859,14 +83673,14 @@ var init_command_discovery = __esm(() => {
|
|
|
82859
83673
|
});
|
|
82860
83674
|
|
|
82861
83675
|
// src/commands/machine/daemon-start/command-sync-heartbeat.ts
|
|
82862
|
-
import { createHash as
|
|
83676
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
82863
83677
|
var pushCommandsEffect, pushSingleWorkspaceCommandsEffect = (workingDir) => exports_Effect.gen(function* () {
|
|
82864
83678
|
const session2 = yield* DaemonSessionService;
|
|
82865
83679
|
const mutable = yield* DaemonMutableStateService;
|
|
82866
83680
|
const lastPushedGitState = yield* exports_Ref.get(mutable.lastPushedGitState);
|
|
82867
83681
|
const commands = yield* exports_Effect.promise(() => discoverCommands(workingDir));
|
|
82868
83682
|
const stateKey = `commands:${session2.machineId}::${workingDir}`;
|
|
82869
|
-
const commandsHash =
|
|
83683
|
+
const commandsHash = createHash6("md5").update(JSON.stringify(commands)).digest("hex");
|
|
82870
83684
|
if (lastPushedGitState.get(stateKey) === commandsHash) {
|
|
82871
83685
|
return;
|
|
82872
83686
|
}
|
|
@@ -82908,7 +83722,7 @@ var init_command_sync_heartbeat = __esm(() => {
|
|
|
82908
83722
|
});
|
|
82909
83723
|
|
|
82910
83724
|
// src/infrastructure/git/git-state-pipeline.ts
|
|
82911
|
-
import { createHash as
|
|
83725
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
82912
83726
|
|
|
82913
83727
|
class GitStatePipeline {
|
|
82914
83728
|
fields;
|
|
@@ -82940,7 +83754,7 @@ class GitStatePipeline {
|
|
|
82940
83754
|
const raw = values3.get(field.key) ?? field.defaultValue;
|
|
82941
83755
|
hashInput[field.key] = field.toHashable(raw);
|
|
82942
83756
|
}
|
|
82943
|
-
return
|
|
83757
|
+
return createHash7("md5").update(JSON.stringify(hashInput)).digest("hex");
|
|
82944
83758
|
}
|
|
82945
83759
|
toMutationArgs(values3, slim) {
|
|
82946
83760
|
const args2 = {};
|
|
@@ -82988,7 +83802,7 @@ function buildGitStateDeps(session2, lastPushedGitState) {
|
|
|
82988
83802
|
}
|
|
82989
83803
|
async function pushSingleWorkspaceGitStateImpl(ctx, workingDir) {
|
|
82990
83804
|
const stateKey = makeGitStateKey(ctx.machineId, workingDir);
|
|
82991
|
-
const isRepo = await
|
|
83805
|
+
const isRepo = await isGitRepo2(workingDir);
|
|
82992
83806
|
if (!isRepo) {
|
|
82993
83807
|
await pushNotFoundGitState(ctx, workingDir, stateKey);
|
|
82994
83808
|
return;
|
|
@@ -83133,7 +83947,7 @@ var lastFullPushMs, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummary
|
|
|
83133
83947
|
const mutable = yield* DaemonMutableStateService;
|
|
83134
83948
|
const lastPushedGitState = yield* exports_Ref.get(mutable.lastPushedGitState);
|
|
83135
83949
|
const stateKey = makeGitStateKey(session2.machineId, workingDir);
|
|
83136
|
-
const isRepo = yield* exports_Effect.promise(() =>
|
|
83950
|
+
const isRepo = yield* exports_Effect.promise(() => isGitRepo2(workingDir));
|
|
83137
83951
|
if (!isRepo) {
|
|
83138
83952
|
yield* pushObservedNotRepoEffect(session2, lastPushedGitState, stateKey, workingDir, reason);
|
|
83139
83953
|
return;
|
|
@@ -83270,9 +84084,7 @@ var init_git_heartbeat = __esm(() => {
|
|
|
83270
84084
|
});
|
|
83271
84085
|
|
|
83272
84086
|
// src/commands/machine/daemon-start/git-subscription.ts
|
|
83273
|
-
import {
|
|
83274
|
-
import { gzipSync as gzipSync2 } from "node:zlib";
|
|
83275
|
-
import { promisify as promisify4 } from "util";
|
|
84087
|
+
import { gzipSync as gzipSync4 } from "node:zlib";
|
|
83276
84088
|
function extractDiffStatFromShowOutput(content) {
|
|
83277
84089
|
for (const line of content.split(`
|
|
83278
84090
|
`)) {
|
|
@@ -83287,7 +84099,7 @@ async function processFullDiff(deps, req) {
|
|
|
83287
84099
|
if (result.status === "available" || result.status === "truncated") {
|
|
83288
84100
|
const diffStatResult = await getDiffStat(req.workingDir);
|
|
83289
84101
|
const diffStat = diffStatResult.status === "available" ? diffStatResult.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 };
|
|
83290
|
-
const compressed =
|
|
84102
|
+
const compressed = gzipSync4(Buffer.from(result.content));
|
|
83291
84103
|
const diffContentCompressed = compressed.toString("base64");
|
|
83292
84104
|
await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
|
|
83293
84105
|
sessionId: deps.sessionId,
|
|
@@ -83299,7 +84111,7 @@ async function processFullDiff(deps, req) {
|
|
|
83299
84111
|
});
|
|
83300
84112
|
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"})`);
|
|
83301
84113
|
} else {
|
|
83302
|
-
const emptyCompressed =
|
|
84114
|
+
const emptyCompressed = gzipSync4(Buffer.from("")).toString("base64");
|
|
83303
84115
|
await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
|
|
83304
84116
|
sessionId: deps.sessionId,
|
|
83305
84117
|
machineId: deps.machineId,
|
|
@@ -83349,25 +84161,24 @@ async function processPRAction(deps, req) {
|
|
|
83349
84161
|
if (!prNumber || !action) {
|
|
83350
84162
|
throw new Error("pr_action request missing prNumber or prAction");
|
|
83351
84163
|
}
|
|
83352
|
-
let
|
|
84164
|
+
let ghArgs;
|
|
83353
84165
|
switch (action) {
|
|
83354
84166
|
case "merge_squash":
|
|
83355
|
-
|
|
84167
|
+
ghArgs = ["pr", "merge", String(prNumber), "--squash", "--delete-branch"];
|
|
83356
84168
|
break;
|
|
83357
84169
|
case "merge_no_squash":
|
|
83358
|
-
|
|
84170
|
+
ghArgs = ["pr", "merge", String(prNumber), "--merge"];
|
|
83359
84171
|
break;
|
|
83360
84172
|
case "close":
|
|
83361
|
-
|
|
84173
|
+
ghArgs = ["pr", "close", String(prNumber)];
|
|
83362
84174
|
break;
|
|
83363
84175
|
default:
|
|
83364
84176
|
throw new Error(`Unknown PR action: ${action}`);
|
|
83365
84177
|
}
|
|
83366
|
-
const
|
|
83367
|
-
|
|
83368
|
-
|
|
83369
|
-
|
|
83370
|
-
});
|
|
84178
|
+
const result = await runGh(ghArgs, req.workingDir, { timeout: EXEC_TIMEOUT_MS });
|
|
84179
|
+
if ("error" in result) {
|
|
84180
|
+
throw result.error;
|
|
84181
|
+
}
|
|
83371
84182
|
console.log(`[${formatTimestamp()}] ✅ PR action: ${action} on #${prNumber}${result.stdout ? ` — ${result.stdout.trim()}` : ""}`);
|
|
83372
84183
|
exports_Runtime.runFork(deps.runtime)(pushGitStateEffect.pipe(exports_Effect.provide(exports_Layer.mergeAll(exports_Layer.succeed(DaemonSessionService, deps), DaemonMutableStateServiceLive({
|
|
83373
84184
|
lastPushedGitState: deps.lastPushedGitState,
|
|
@@ -83401,7 +84212,7 @@ async function processCommitDetail(deps, req) {
|
|
|
83401
84212
|
]);
|
|
83402
84213
|
await upsertCommitDetailResult(deps, req, result, metadata);
|
|
83403
84214
|
if (result.status === "available" || result.status === "truncated") {
|
|
83404
|
-
const compressed =
|
|
84215
|
+
const compressed = gzipSync4(Buffer.from(result.content));
|
|
83405
84216
|
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)`);
|
|
83406
84217
|
}
|
|
83407
84218
|
}
|
|
@@ -83432,7 +84243,7 @@ async function upsertCommitDetailResult(deps, req, result, metadata) {
|
|
|
83432
84243
|
return;
|
|
83433
84244
|
}
|
|
83434
84245
|
const diffStat = extractDiffStatFromShowOutput(result.content);
|
|
83435
|
-
const compressed =
|
|
84246
|
+
const compressed = gzipSync4(Buffer.from(result.content));
|
|
83436
84247
|
const diffContentCompressed = compressed.toString("base64");
|
|
83437
84248
|
await deps.backend.mutation(api.workspaces.upsertCommitDetailV2, {
|
|
83438
84249
|
...baseArgs,
|
|
@@ -83581,11 +84392,12 @@ var init_git_subscription = __esm(() => {
|
|
|
83581
84392
|
init_git_heartbeat();
|
|
83582
84393
|
init_api3();
|
|
83583
84394
|
init_git_reader();
|
|
84395
|
+
init_run_command();
|
|
83584
84396
|
init_convex_error();
|
|
83585
84397
|
});
|
|
83586
84398
|
|
|
83587
84399
|
// src/commands/machine/daemon-start/commit-detail-sync.ts
|
|
83588
|
-
import { gzipSync as
|
|
84400
|
+
import { gzipSync as gzipSync5 } from "node:zlib";
|
|
83589
84401
|
function upsertCommitDetailArgs(session2, workingDir, sha, metadata, overrides) {
|
|
83590
84402
|
return {
|
|
83591
84403
|
sessionId: session2.sessionId,
|
|
@@ -83614,7 +84426,7 @@ var seenShas, prefetchSingleShaEffect = (session2, workingDir, sha, commits) =>
|
|
|
83614
84426
|
return;
|
|
83615
84427
|
}
|
|
83616
84428
|
const diffStat = extractDiffStatFromShowOutput(result.content);
|
|
83617
|
-
const compressed =
|
|
84429
|
+
const compressed = gzipSync5(Buffer.from(result.content));
|
|
83618
84430
|
const diffContentCompressed = compressed.toString("base64");
|
|
83619
84431
|
yield* exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaces.upsertCommitDetailV2, upsertCommitDetailArgs(session2, workingDir, sha, metadata, {
|
|
83620
84432
|
status: "available",
|
|
@@ -84035,14 +84847,14 @@ var init_sse_event_buffer = __esm(() => {
|
|
|
84035
84847
|
}
|
|
84036
84848
|
_wake() {
|
|
84037
84849
|
if (this._waiter) {
|
|
84038
|
-
const
|
|
84850
|
+
const resolve5 = this._waiter;
|
|
84039
84851
|
this._waiter = null;
|
|
84040
|
-
|
|
84852
|
+
resolve5();
|
|
84041
84853
|
}
|
|
84042
84854
|
}
|
|
84043
84855
|
_waitForData() {
|
|
84044
|
-
return new Promise((
|
|
84045
|
-
this._waiter =
|
|
84856
|
+
return new Promise((resolve5) => {
|
|
84857
|
+
this._waiter = resolve5;
|
|
84046
84858
|
});
|
|
84047
84859
|
}
|
|
84048
84860
|
[Symbol.asyncIterator]() {
|
|
@@ -84097,8 +84909,8 @@ class OpencodeSdkSession {
|
|
|
84097
84909
|
async prompt(input) {
|
|
84098
84910
|
if (this.closed)
|
|
84099
84911
|
throw new Error("Session is closed");
|
|
84100
|
-
const idlePromise = new Promise((
|
|
84101
|
-
this._idleResolve =
|
|
84912
|
+
const idlePromise = new Promise((resolve5) => {
|
|
84913
|
+
this._idleResolve = resolve5;
|
|
84102
84914
|
});
|
|
84103
84915
|
const IDLE_TIMEOUT_MS = 300000;
|
|
84104
84916
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -84182,7 +84994,7 @@ var init_opencode_session = __esm(() => {
|
|
|
84182
84994
|
});
|
|
84183
84995
|
|
|
84184
84996
|
// src/infrastructure/harnesses/opencode-sdk/opencode-harness.ts
|
|
84185
|
-
import { spawn as
|
|
84997
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
84186
84998
|
function harnessEventSessionId(event) {
|
|
84187
84999
|
const p = event.properties;
|
|
84188
85000
|
if (!p)
|
|
@@ -84429,14 +85241,14 @@ class OpencodeSdkHarness {
|
|
|
84429
85241
|
}
|
|
84430
85242
|
this.sessionListeners.clear();
|
|
84431
85243
|
this.childProcess.kill("SIGTERM");
|
|
84432
|
-
await new Promise((
|
|
85244
|
+
await new Promise((resolve5) => {
|
|
84433
85245
|
const timeout3 = setTimeout(() => {
|
|
84434
85246
|
this.childProcess.kill("SIGKILL");
|
|
84435
|
-
|
|
85247
|
+
resolve5();
|
|
84436
85248
|
}, 5000);
|
|
84437
85249
|
this.childProcess.once("exit", () => {
|
|
84438
85250
|
clearTimeout(timeout3);
|
|
84439
|
-
|
|
85251
|
+
resolve5();
|
|
84440
85252
|
});
|
|
84441
85253
|
});
|
|
84442
85254
|
}
|
|
@@ -84456,7 +85268,7 @@ class OpencodeSdkHarness {
|
|
|
84456
85268
|
}
|
|
84457
85269
|
}
|
|
84458
85270
|
var OPENCODE_COMMAND3 = "opencode", SERVE_STARTUP_TIMEOUT_MS2 = 1e4, startOpencodeSdkHarness = async (config3) => {
|
|
84459
|
-
const childProcess =
|
|
85271
|
+
const childProcess = spawn6(OPENCODE_COMMAND3, ["serve", "--print-logs"], {
|
|
84460
85272
|
cwd: config3.workingDir,
|
|
84461
85273
|
stdio: ["pipe", "pipe", "pipe"],
|
|
84462
85274
|
shell: false,
|
|
@@ -85818,10 +86630,10 @@ class BufferedJournalFactory {
|
|
|
85818
86630
|
const waitForInProgress = () => {
|
|
85819
86631
|
if (!flushInProgress)
|
|
85820
86632
|
return Promise.resolve();
|
|
85821
|
-
return new Promise((
|
|
86633
|
+
return new Promise((resolve5) => {
|
|
85822
86634
|
const check3 = () => {
|
|
85823
86635
|
if (!flushInProgress)
|
|
85824
|
-
|
|
86636
|
+
resolve5();
|
|
85825
86637
|
else
|
|
85826
86638
|
setTimeout(check3, 10);
|
|
85827
86639
|
};
|
|
@@ -85939,21 +86751,64 @@ var init_start_subscriptions = __esm(() => {
|
|
|
85939
86751
|
init_convex_session_repository();
|
|
85940
86752
|
});
|
|
85941
86753
|
|
|
86754
|
+
// src/infrastructure/services/workspace/assert-registered-working-dir.ts
|
|
86755
|
+
async function assertRegisteredWorkingDir(session2, workingDir) {
|
|
86756
|
+
const workspaces = await getWorkspacesForMachine({
|
|
86757
|
+
workspaceListStore: session2.workspaceListStore,
|
|
86758
|
+
sessionId: session2.sessionId,
|
|
86759
|
+
machineId: session2.machineId,
|
|
86760
|
+
backend: session2.backend
|
|
86761
|
+
});
|
|
86762
|
+
if (!workspaces.some((w) => w.workingDir === workingDir)) {
|
|
86763
|
+
return { ok: false, error: "Workspace not registered for this machine" };
|
|
86764
|
+
}
|
|
86765
|
+
return { ok: true };
|
|
86766
|
+
}
|
|
86767
|
+
var init_assert_registered_working_dir = __esm(() => {
|
|
86768
|
+
init_workspace_cache();
|
|
86769
|
+
});
|
|
86770
|
+
|
|
85942
86771
|
// src/commands/machine/daemon-start/file-content-fulfillment.ts
|
|
85943
86772
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
85944
|
-
import {
|
|
85945
|
-
|
|
85946
|
-
|
|
85947
|
-
|
|
86773
|
+
import { gzipSync as gzipSync6 } from "node:zlib";
|
|
86774
|
+
function getErrorCause(error) {
|
|
86775
|
+
if (typeof error === "object" && error !== null && "cause" in error && error.cause !== undefined) {
|
|
86776
|
+
return error.cause;
|
|
86777
|
+
}
|
|
86778
|
+
return error;
|
|
86779
|
+
}
|
|
86780
|
+
function isENOENT(error) {
|
|
86781
|
+
const cause3 = getErrorCause(error);
|
|
86782
|
+
return typeof cause3 === "object" && cause3 !== null && "code" in cause3 && cause3.code === "ENOENT";
|
|
86783
|
+
}
|
|
86784
|
+
function isBinaryFile(path6) {
|
|
86785
|
+
const lastDot = path6.lastIndexOf(".");
|
|
85948
86786
|
if (lastDot === -1)
|
|
85949
86787
|
return false;
|
|
85950
|
-
return BINARY_EXTENSIONS.has(
|
|
86788
|
+
return BINARY_EXTENSIONS.has(path6.slice(lastDot).toLowerCase());
|
|
86789
|
+
}
|
|
86790
|
+
function gzipPlainText(text) {
|
|
86791
|
+
return gzipSync6(Buffer.from(text)).toString("base64");
|
|
86792
|
+
}
|
|
86793
|
+
function fulfillGzippedContentEffect(session2, workingDir, filePath, plainText, truncated) {
|
|
86794
|
+
return exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
86795
|
+
sessionId: session2.sessionId,
|
|
86796
|
+
machineId: session2.machineId,
|
|
86797
|
+
workingDir,
|
|
86798
|
+
filePath,
|
|
86799
|
+
data: { compression: "gzip", content: gzipPlainText(plainText) },
|
|
86800
|
+
encoding: "utf8",
|
|
86801
|
+
truncated
|
|
86802
|
+
})), () => exports_Effect.void);
|
|
85951
86803
|
}
|
|
85952
86804
|
var MAX_CONTENT_BYTES, BINARY_EXTENSIONS, fulfillFileContentRequestsEffect;
|
|
85953
86805
|
var init_file_content_fulfillment = __esm(() => {
|
|
85954
86806
|
init_esm();
|
|
85955
86807
|
init_daemon_services();
|
|
85956
86808
|
init_api3();
|
|
86809
|
+
init_assert_registered_working_dir();
|
|
86810
|
+
init_workspace_path_security();
|
|
86811
|
+
init_workspace_visibility_policy();
|
|
85957
86812
|
MAX_CONTENT_BYTES = 500 * 1024;
|
|
85958
86813
|
BINARY_EXTENSIONS = new Set([
|
|
85959
86814
|
".png",
|
|
@@ -86007,40 +86862,55 @@ var init_file_content_fulfillment = __esm(() => {
|
|
|
86007
86862
|
for (const request2 of requests) {
|
|
86008
86863
|
const startTime = Date.now();
|
|
86009
86864
|
const { workingDir, filePath } = request2;
|
|
86010
|
-
|
|
86011
|
-
|
|
86865
|
+
const registered = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => assertRegisteredWorkingDir(session2, workingDir)), () => exports_Effect.succeed({ ok: false, error: "Workspace check failed" }));
|
|
86866
|
+
if (!registered.ok) {
|
|
86867
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Rejected unregistered workspace: ${workingDir} (${registered.error})`);
|
|
86868
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[Error: workspace not registered]", false);
|
|
86012
86869
|
continue;
|
|
86013
86870
|
}
|
|
86014
|
-
const
|
|
86015
|
-
if (!
|
|
86016
|
-
console.warn(`[${formatTimestamp()}] ⚠️
|
|
86871
|
+
const resolved = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => resolvePathWithinWorkspace(workingDir, filePath)), () => exports_Effect.succeed({ ok: false, error: "Invalid file path" }));
|
|
86872
|
+
if (!resolved.ok) {
|
|
86873
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Rejected file path: ${filePath} (${resolved.error})`);
|
|
86874
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[Error reading file]", false);
|
|
86017
86875
|
continue;
|
|
86018
86876
|
}
|
|
86877
|
+
const absolutePath = resolved.absolutePath;
|
|
86019
86878
|
if (isBinaryFile(filePath)) {
|
|
86020
|
-
|
|
86021
|
-
yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
86022
|
-
sessionId: session2.sessionId,
|
|
86023
|
-
machineId: session2.machineId,
|
|
86024
|
-
workingDir,
|
|
86025
|
-
filePath,
|
|
86026
|
-
data: { compression: "gzip", content: binaryCompressed },
|
|
86027
|
-
encoding: "utf8",
|
|
86028
|
-
truncated: false
|
|
86029
|
-
})), () => exports_Effect.void);
|
|
86879
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[Binary file]", false);
|
|
86030
86880
|
const elapsed4 = Date.now() - startTime;
|
|
86031
86881
|
console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File content synced to Convex: ${filePath} [binary] (${elapsed4}ms)`);
|
|
86032
86882
|
continue;
|
|
86033
86883
|
}
|
|
86034
|
-
|
|
86884
|
+
if (!isPathContentReadable(filePath)) {
|
|
86885
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[File blocked: cannot open sensitive path in remote explorer]", false);
|
|
86886
|
+
const elapsed4 = Date.now() - startTime;
|
|
86887
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File content blocked: ${filePath} [secret] (${elapsed4}ms)`);
|
|
86888
|
+
continue;
|
|
86889
|
+
}
|
|
86890
|
+
const readOutcome = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => readFile9(absolutePath)).pipe(exports_Effect.map((buffer) => {
|
|
86035
86891
|
if (buffer.length > MAX_CONTENT_BYTES) {
|
|
86036
86892
|
return {
|
|
86893
|
+
kind: "ok",
|
|
86037
86894
|
content: buffer.subarray(0, MAX_CONTENT_BYTES).toString("utf8"),
|
|
86038
86895
|
truncated: true
|
|
86039
86896
|
};
|
|
86040
86897
|
}
|
|
86041
|
-
return {
|
|
86042
|
-
|
|
86043
|
-
|
|
86898
|
+
return {
|
|
86899
|
+
kind: "ok",
|
|
86900
|
+
content: buffer.toString("utf8"),
|
|
86901
|
+
truncated: false
|
|
86902
|
+
};
|
|
86903
|
+
})), (error) => isENOENT(error) ? exports_Effect.succeed({ kind: "missing" }) : exports_Effect.succeed({
|
|
86904
|
+
kind: "error",
|
|
86905
|
+
content: "[Error reading file]",
|
|
86906
|
+
truncated: false
|
|
86907
|
+
}));
|
|
86908
|
+
if (readOutcome.kind === "missing") {
|
|
86909
|
+
console.log(`[${formatTimestamp()}] ⏳ File not on disk yet, deferring content sync: ${filePath}`);
|
|
86910
|
+
continue;
|
|
86911
|
+
}
|
|
86912
|
+
const { content, truncated } = readOutcome.kind === "ok" ? readOutcome : { content: readOutcome.content, truncated: readOutcome.truncated };
|
|
86913
|
+
const compressed = gzipSync6(Buffer.from(content));
|
|
86044
86914
|
const contentCompressed = compressed.toString("base64");
|
|
86045
86915
|
yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
86046
86916
|
sessionId: session2.sessionId,
|
|
@@ -86094,217 +86964,272 @@ var init_file_content_subscription = __esm(() => {
|
|
|
86094
86964
|
init_convex_error();
|
|
86095
86965
|
});
|
|
86096
86966
|
|
|
86097
|
-
// src/
|
|
86098
|
-
|
|
86099
|
-
|
|
86100
|
-
|
|
86101
|
-
|
|
86102
|
-
|
|
86103
|
-
|
|
86104
|
-
|
|
86105
|
-
|
|
86106
|
-
|
|
86107
|
-
const
|
|
86108
|
-
|
|
86109
|
-
|
|
86110
|
-
|
|
86111
|
-
|
|
86112
|
-
|
|
86967
|
+
// src/commands/machine/daemon-start/file-write-errors.ts
|
|
86968
|
+
function unsupportedFileWriteOperationMessage(operation) {
|
|
86969
|
+
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).";
|
|
86970
|
+
}
|
|
86971
|
+
|
|
86972
|
+
// src/commands/machine/daemon-start/file-write-fulfillment.ts
|
|
86973
|
+
import { access as access5, mkdir as mkdir8, rename as rename3, rm as rm2, writeFile as writeFile7 } from "node:fs/promises";
|
|
86974
|
+
import { dirname as dirname9 } from "node:path";
|
|
86975
|
+
import { gzipSync as gzipSync7 } from "node:zlib";
|
|
86976
|
+
function isTerminalFileWriteError(errorMessage) {
|
|
86977
|
+
const terminalMessages = new Set([
|
|
86978
|
+
"Invalid file path",
|
|
86979
|
+
"Path escapes workspace",
|
|
86980
|
+
"Missing file data",
|
|
86981
|
+
"File content too large",
|
|
86982
|
+
"File already exists",
|
|
86983
|
+
"File does not exist",
|
|
86984
|
+
"Cannot delete workspace root",
|
|
86985
|
+
"Target path already exists",
|
|
86986
|
+
"Target path is required for rename",
|
|
86987
|
+
"Rename target must differ from source path",
|
|
86988
|
+
"Directory already exists",
|
|
86989
|
+
"Workspace not registered for this machine"
|
|
86990
|
+
]);
|
|
86991
|
+
if (errorMessage.startsWith("Unsupported file write operation"))
|
|
86992
|
+
return true;
|
|
86993
|
+
return terminalMessages.has(errorMessage);
|
|
86994
|
+
}
|
|
86995
|
+
function parentDirPath2(filePath) {
|
|
86996
|
+
const idx = filePath.lastIndexOf("/");
|
|
86997
|
+
return idx === -1 ? "" : filePath.slice(0, idx);
|
|
86998
|
+
}
|
|
86999
|
+
async function syncParentDirListingAfterWrite(session2, workingDir, filePath) {
|
|
87000
|
+
const dirPath = parentDirPath2(filePath);
|
|
87001
|
+
const listing = await listDirectory(workingDir, dirPath);
|
|
87002
|
+
const json = JSON.stringify(listing);
|
|
87003
|
+
const dataHash = computeDirListingContentHash(listing);
|
|
87004
|
+
const compressed = gzipSync7(Buffer.from(json)).toString("base64");
|
|
87005
|
+
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
|
|
87006
|
+
sessionId: session2.sessionId,
|
|
87007
|
+
machineId: session2.machineId,
|
|
87008
|
+
workingDir,
|
|
87009
|
+
dirPath,
|
|
87010
|
+
data: { compression: "gzip", content: compressed },
|
|
87011
|
+
dataHash,
|
|
87012
|
+
scannedAt: listing.scannedAt,
|
|
87013
|
+
truncated: listing.truncated,
|
|
87014
|
+
totalCount: listing.totalCount
|
|
87015
|
+
});
|
|
86113
87016
|
}
|
|
86114
|
-
async function
|
|
86115
|
-
|
|
86116
|
-
|
|
86117
|
-
|
|
86118
|
-
|
|
86119
|
-
|
|
86120
|
-
|
|
86121
|
-
return stdout.trim() === "true";
|
|
86122
|
-
} catch {
|
|
86123
|
-
return false;
|
|
86124
|
-
}
|
|
87017
|
+
async function completeWriteRequest(session2, requestId, result) {
|
|
87018
|
+
await session2.backend.mutation(api.workspaceFiles.completeFileWriteRequest, {
|
|
87019
|
+
sessionId: session2.sessionId,
|
|
87020
|
+
requestId,
|
|
87021
|
+
status: result.status,
|
|
87022
|
+
errorMessage: result.status === "error" ? result.errorMessage : undefined
|
|
87023
|
+
});
|
|
86125
87024
|
}
|
|
86126
|
-
async function
|
|
86127
|
-
|
|
86128
|
-
await walkSubtree(rootDir, "", collected, maxEntries, maxSubtreeBytes);
|
|
86129
|
-
return collected;
|
|
87025
|
+
async function fileExistsAt(absolutePath) {
|
|
87026
|
+
return access5(absolutePath).then(() => true).catch(() => false);
|
|
86130
87027
|
}
|
|
86131
|
-
|
|
86132
|
-
if (
|
|
86133
|
-
return
|
|
86134
|
-
const absDir = relDir ? path3.join(absRoot, relDir) : absRoot;
|
|
86135
|
-
let dirents;
|
|
86136
|
-
try {
|
|
86137
|
-
dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
|
|
86138
|
-
} catch {
|
|
86139
|
-
return 0;
|
|
87028
|
+
function decodeWritePayload(request2) {
|
|
87029
|
+
if (!request2.data) {
|
|
87030
|
+
return { ok: false, errorMessage: "Missing file data" };
|
|
86140
87031
|
}
|
|
86141
|
-
|
|
86142
|
-
|
|
86143
|
-
|
|
86144
|
-
|
|
86145
|
-
|
|
86146
|
-
|
|
86147
|
-
continue;
|
|
86148
|
-
const childRel = relDir ? `${relDir}/${ent.name}` : ent.name;
|
|
86149
|
-
if (ent.isDirectory()) {
|
|
86150
|
-
const subCollected = [];
|
|
86151
|
-
const subSize = await walkSubtree(absRoot, childRel, subCollected, maxEntries - collected.length - staged.length, maxSubtreeBytes);
|
|
86152
|
-
if (subSize === null) {
|
|
86153
|
-
continue;
|
|
86154
|
-
}
|
|
86155
|
-
subtreeBytes += subSize;
|
|
86156
|
-
if (subtreeBytes > maxSubtreeBytes) {
|
|
86157
|
-
return null;
|
|
86158
|
-
}
|
|
86159
|
-
staged.push(...subCollected);
|
|
86160
|
-
} else if (ent.isFile()) {
|
|
86161
|
-
try {
|
|
86162
|
-
const st = await fsPromises.stat(path3.join(absRoot, childRel));
|
|
86163
|
-
subtreeBytes += st.size;
|
|
86164
|
-
if (subtreeBytes > maxSubtreeBytes) {
|
|
86165
|
-
return null;
|
|
86166
|
-
}
|
|
86167
|
-
staged.push(childRel);
|
|
86168
|
-
} catch {}
|
|
86169
|
-
}
|
|
87032
|
+
return gunzipBase64Payload(request2.data.content, MAX_CONTENT_BYTES2);
|
|
87033
|
+
}
|
|
87034
|
+
async function validateWriteOperation(operation, absolutePath) {
|
|
87035
|
+
const exists3 = await fileExistsAt(absolutePath);
|
|
87036
|
+
if (operation === "create" && exists3) {
|
|
87037
|
+
return { ok: false, errorMessage: "File already exists" };
|
|
86170
87038
|
}
|
|
86171
|
-
|
|
86172
|
-
|
|
86173
|
-
break;
|
|
86174
|
-
collected.push(p);
|
|
87039
|
+
if (operation === "update" && !exists3) {
|
|
87040
|
+
return { ok: false, errorMessage: "File does not exist" };
|
|
86175
87041
|
}
|
|
86176
|
-
|
|
86177
|
-
}
|
|
86178
|
-
async function getGitFiles(rootDir) {
|
|
86179
|
-
const env2 = {
|
|
86180
|
-
...process.env,
|
|
86181
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
86182
|
-
GIT_PAGER: "cat",
|
|
86183
|
-
NO_COLOR: "1"
|
|
86184
|
-
};
|
|
86185
|
-
try {
|
|
86186
|
-
const tracked = await execAsync4("git ls-files", {
|
|
86187
|
-
cwd: rootDir,
|
|
86188
|
-
env: env2,
|
|
86189
|
-
maxBuffer: 10 * 1024 * 1024
|
|
86190
|
-
});
|
|
86191
|
-
const untracked = await execAsync4("git ls-files --others --exclude-standard", {
|
|
86192
|
-
cwd: rootDir,
|
|
86193
|
-
env: env2,
|
|
86194
|
-
maxBuffer: 10 * 1024 * 1024
|
|
86195
|
-
});
|
|
86196
|
-
const trackedFiles = parseLines(tracked.stdout);
|
|
86197
|
-
const untrackedFiles = parseLines(untracked.stdout);
|
|
86198
|
-
const allFiles = new Set([...trackedFiles, ...untrackedFiles]);
|
|
86199
|
-
return Array.from(allFiles);
|
|
86200
|
-
} catch {
|
|
86201
|
-
return [];
|
|
87042
|
+
if (operation === "delete" && !exists3) {
|
|
87043
|
+
return { ok: false, errorMessage: "File does not exist" };
|
|
86202
87044
|
}
|
|
87045
|
+
return { ok: true };
|
|
86203
87046
|
}
|
|
86204
|
-
function
|
|
86205
|
-
|
|
86206
|
-
|
|
86207
|
-
}
|
|
86208
|
-
|
|
86209
|
-
const segments = filePath.split("/");
|
|
86210
|
-
return segments.some((segment) => ALWAYS_EXCLUDE.has(segment));
|
|
86211
|
-
}
|
|
86212
|
-
function matchesExcludePattern(filePath) {
|
|
86213
|
-
return EXCLUDE_PATTERNS.some((pattern) => pattern.test(filePath));
|
|
87047
|
+
async function writePayloadToDisk(absolutePath, operation, content) {
|
|
87048
|
+
if (operation === "create") {
|
|
87049
|
+
await mkdir8(dirname9(absolutePath), { recursive: true });
|
|
87050
|
+
}
|
|
87051
|
+
await writeFile7(absolutePath, content);
|
|
86214
87052
|
}
|
|
86215
|
-
function
|
|
86216
|
-
const
|
|
86217
|
-
|
|
86218
|
-
|
|
86219
|
-
|
|
86220
|
-
|
|
86221
|
-
|
|
87053
|
+
async function fulfillOneFileWriteRequest(session2, request2) {
|
|
87054
|
+
const startTime = Date.now();
|
|
87055
|
+
const { workingDir, filePath, operation } = request2;
|
|
87056
|
+
const registered = await assertRegisteredWorkingDir(session2, workingDir);
|
|
87057
|
+
if (!registered.ok) {
|
|
87058
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87059
|
+
status: "error",
|
|
87060
|
+
errorMessage: registered.error
|
|
87061
|
+
});
|
|
87062
|
+
return;
|
|
86222
87063
|
}
|
|
86223
|
-
const
|
|
86224
|
-
|
|
86225
|
-
|
|
86226
|
-
|
|
86227
|
-
|
|
86228
|
-
|
|
87064
|
+
const resolved = await resolvePathWithinWorkspace(workingDir, filePath);
|
|
87065
|
+
if (!resolved.ok) {
|
|
87066
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87067
|
+
status: "error",
|
|
87068
|
+
errorMessage: resolved.error
|
|
87069
|
+
});
|
|
87070
|
+
return;
|
|
86229
87071
|
}
|
|
86230
|
-
|
|
86231
|
-
|
|
86232
|
-
|
|
86233
|
-
|
|
86234
|
-
|
|
87072
|
+
try {
|
|
87073
|
+
if (operation === "rename") {
|
|
87074
|
+
if (!request2.targetFilePath) {
|
|
87075
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87076
|
+
status: "error",
|
|
87077
|
+
errorMessage: "Target path is required for rename"
|
|
87078
|
+
});
|
|
87079
|
+
return;
|
|
87080
|
+
}
|
|
87081
|
+
if (request2.targetFilePath === filePath) {
|
|
87082
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87083
|
+
status: "error",
|
|
87084
|
+
errorMessage: "Rename target must differ from source path"
|
|
87085
|
+
});
|
|
87086
|
+
return;
|
|
87087
|
+
}
|
|
87088
|
+
const targetResolved = await resolvePathWithinWorkspace(workingDir, request2.targetFilePath);
|
|
87089
|
+
if (!targetResolved.ok) {
|
|
87090
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87091
|
+
status: "error",
|
|
87092
|
+
errorMessage: targetResolved.error
|
|
87093
|
+
});
|
|
87094
|
+
return;
|
|
87095
|
+
}
|
|
87096
|
+
const sourceExists = await fileExistsAt(resolved.absolutePath);
|
|
87097
|
+
if (!sourceExists) {
|
|
87098
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87099
|
+
status: "error",
|
|
87100
|
+
errorMessage: "File does not exist"
|
|
87101
|
+
});
|
|
87102
|
+
return;
|
|
87103
|
+
}
|
|
87104
|
+
const targetExists = await fileExistsAt(targetResolved.absolutePath);
|
|
87105
|
+
if (targetExists) {
|
|
87106
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87107
|
+
status: "error",
|
|
87108
|
+
errorMessage: "Target path already exists"
|
|
87109
|
+
});
|
|
87110
|
+
return;
|
|
87111
|
+
}
|
|
87112
|
+
await mkdir8(dirname9(targetResolved.absolutePath), { recursive: true });
|
|
87113
|
+
await rename3(resolved.absolutePath, targetResolved.absolutePath);
|
|
87114
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87115
|
+
if (parentDirPath2(filePath) !== parentDirPath2(request2.targetFilePath)) {
|
|
87116
|
+
await syncParentDirListingAfterWrite(session2, workingDir, request2.targetFilePath);
|
|
87117
|
+
}
|
|
87118
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87119
|
+
const elapsed4 = Date.now() - startTime;
|
|
87120
|
+
console.log(`[${formatTimestamp()}] ✏️ File rename fulfilled: ${filePath} → ${request2.targetFilePath} (${elapsed4}ms)`);
|
|
87121
|
+
return;
|
|
87122
|
+
}
|
|
87123
|
+
if (operation === "mkdir") {
|
|
87124
|
+
const exists3 = await fileExistsAt(resolved.absolutePath);
|
|
87125
|
+
if (exists3) {
|
|
87126
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87127
|
+
status: "error",
|
|
87128
|
+
errorMessage: "Directory already exists"
|
|
87129
|
+
});
|
|
87130
|
+
return;
|
|
87131
|
+
}
|
|
87132
|
+
await mkdir8(resolved.absolutePath, { recursive: true });
|
|
87133
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87134
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87135
|
+
const elapsed4 = Date.now() - startTime;
|
|
87136
|
+
console.log(`[${formatTimestamp()}] ✏️ Directory mkdir fulfilled: ${filePath} (${elapsed4}ms)`);
|
|
87137
|
+
return;
|
|
87138
|
+
}
|
|
87139
|
+
if (operation === "delete") {
|
|
87140
|
+
if (filePath === "") {
|
|
87141
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87142
|
+
status: "error",
|
|
87143
|
+
errorMessage: "Cannot delete workspace root"
|
|
87144
|
+
});
|
|
87145
|
+
return;
|
|
87146
|
+
}
|
|
87147
|
+
const operationCheck2 = await validateWriteOperation(operation, resolved.absolutePath);
|
|
87148
|
+
if (!operationCheck2.ok) {
|
|
87149
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87150
|
+
status: "error",
|
|
87151
|
+
errorMessage: operationCheck2.errorMessage
|
|
87152
|
+
});
|
|
87153
|
+
return;
|
|
87154
|
+
}
|
|
87155
|
+
await rm2(resolved.absolutePath, { recursive: true, force: false });
|
|
87156
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87157
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87158
|
+
const elapsed4 = Date.now() - startTime;
|
|
87159
|
+
console.log(`[${formatTimestamp()}] ✏️ File delete fulfilled: ${filePath} (${elapsed4}ms)`);
|
|
87160
|
+
return;
|
|
87161
|
+
}
|
|
87162
|
+
if (operation !== "create" && operation !== "update") {
|
|
87163
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87164
|
+
status: "error",
|
|
87165
|
+
errorMessage: unsupportedFileWriteOperationMessage(operation)
|
|
87166
|
+
});
|
|
87167
|
+
return;
|
|
87168
|
+
}
|
|
87169
|
+
const payload = decodeWritePayload(request2);
|
|
87170
|
+
if (!payload.ok) {
|
|
87171
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87172
|
+
status: "error",
|
|
87173
|
+
errorMessage: payload.errorMessage
|
|
87174
|
+
});
|
|
87175
|
+
return;
|
|
87176
|
+
}
|
|
87177
|
+
const operationCheck = await validateWriteOperation(operation, resolved.absolutePath);
|
|
87178
|
+
if (!operationCheck.ok) {
|
|
87179
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87180
|
+
status: "error",
|
|
87181
|
+
errorMessage: operationCheck.errorMessage
|
|
87182
|
+
});
|
|
87183
|
+
return;
|
|
87184
|
+
}
|
|
87185
|
+
await writePayloadToDisk(resolved.absolutePath, operation, payload.content);
|
|
87186
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87187
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87188
|
+
const elapsed3 = Date.now() - startTime;
|
|
87189
|
+
console.log(`[${formatTimestamp()}] ✏️ File write fulfilled: ${filePath} (${operation}, ${(payload.content.length / 1024).toFixed(1)}KB, ${elapsed3}ms)`);
|
|
87190
|
+
} catch (err) {
|
|
87191
|
+
const message = err instanceof Error ? err.message : "Write failed";
|
|
87192
|
+
if (isTerminalFileWriteError(message)) {
|
|
87193
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87194
|
+
status: "error",
|
|
87195
|
+
errorMessage: message
|
|
87196
|
+
});
|
|
87197
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write failed for ${filePath}: ${message}`);
|
|
87198
|
+
return;
|
|
87199
|
+
}
|
|
87200
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write transient failure for ${filePath}: ${message} (will retry)`);
|
|
86235
87201
|
}
|
|
86236
|
-
return entries2;
|
|
86237
87202
|
}
|
|
86238
|
-
var
|
|
86239
|
-
var
|
|
86240
|
-
|
|
86241
|
-
|
|
86242
|
-
|
|
86243
|
-
|
|
86244
|
-
|
|
86245
|
-
|
|
86246
|
-
|
|
86247
|
-
|
|
86248
|
-
|
|
86249
|
-
|
|
86250
|
-
|
|
86251
|
-
|
|
86252
|
-
|
|
86253
|
-
|
|
86254
|
-
|
|
86255
|
-
|
|
86256
|
-
|
|
86257
|
-
|
|
86258
|
-
|
|
86259
|
-
|
|
86260
|
-
|
|
86261
|
-
/\.next/i,
|
|
86262
|
-
/coverage/i,
|
|
86263
|
-
/__pycache__/i,
|
|
86264
|
-
/\.turbo/i,
|
|
86265
|
-
/\.cache/i,
|
|
86266
|
-
/\.tmp/i,
|
|
86267
|
-
/tmp/i,
|
|
86268
|
-
/\.DS_Store/i
|
|
86269
|
-
];
|
|
87203
|
+
var MAX_CONTENT_BYTES2, fulfillFileWriteRequestsEffect;
|
|
87204
|
+
var init_file_write_fulfillment = __esm(() => {
|
|
87205
|
+
init_esm();
|
|
87206
|
+
init_daemon_services();
|
|
87207
|
+
init_api3();
|
|
87208
|
+
init_assert_registered_working_dir();
|
|
87209
|
+
init_dir_listing_content_hash();
|
|
87210
|
+
init_dir_listing_scanner();
|
|
87211
|
+
init_workspace_path_security();
|
|
87212
|
+
MAX_CONTENT_BYTES2 = 512 * 1024;
|
|
87213
|
+
fulfillFileWriteRequestsEffect = exports_Effect.gen(function* () {
|
|
87214
|
+
const session2 = yield* DaemonSessionService;
|
|
87215
|
+
const requests = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.query(api.workspaceFiles.getPendingFileWriteRequests, {
|
|
87216
|
+
sessionId: session2.sessionId,
|
|
87217
|
+
machineId: session2.machineId
|
|
87218
|
+
})), () => exports_Effect.succeed([]));
|
|
87219
|
+
if (requests.length === 0)
|
|
87220
|
+
return;
|
|
87221
|
+
console.log(`[${formatTimestamp()}] ✏️ Received ${requests.length} pending file write request(s): ${requests.map((r) => r.filePath).join(", ")}`);
|
|
87222
|
+
for (const request2 of requests) {
|
|
87223
|
+
yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => fulfillOneFileWriteRequest(session2, request2)), () => exports_Effect.void);
|
|
87224
|
+
}
|
|
87225
|
+
});
|
|
86270
87226
|
});
|
|
86271
87227
|
|
|
86272
|
-
// src/commands/machine/daemon-start/file-
|
|
86273
|
-
|
|
86274
|
-
import { gzipSync as gzipSync5 } from "node:zlib";
|
|
86275
|
-
var fulfillFileTreeRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
86276
|
-
for (const request2 of requests) {
|
|
86277
|
-
const startTime = Date.now();
|
|
86278
|
-
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
86279
|
-
const tree = yield* exports_Effect.tryPromise(() => scanFileTree(request2.workingDir));
|
|
86280
|
-
const treeJson = JSON.stringify(tree);
|
|
86281
|
-
const treeHash = createHash6("md5").update(treeJson).digest("hex");
|
|
86282
|
-
const compressed = gzipSync5(Buffer.from(treeJson));
|
|
86283
|
-
const treeJsonCompressed = compressed.toString("base64");
|
|
86284
|
-
yield* exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.syncFileTreeV2, {
|
|
86285
|
-
sessionId: session2.sessionId,
|
|
86286
|
-
machineId: session2.machineId,
|
|
86287
|
-
workingDir: request2.workingDir,
|
|
86288
|
-
data: { compression: "gzip", content: treeJsonCompressed },
|
|
86289
|
-
dataHash: treeHash,
|
|
86290
|
-
scannedAt: tree.scannedAt
|
|
86291
|
-
}));
|
|
86292
|
-
yield* exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
|
|
86293
|
-
sessionId: session2.sessionId,
|
|
86294
|
-
machineId: session2.machineId,
|
|
86295
|
-
workingDir: request2.workingDir
|
|
86296
|
-
}));
|
|
86297
|
-
const elapsed3 = Date.now() - startTime;
|
|
86298
|
-
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree fulfilled: ${request2.workingDir} (${tree.entries.length} entries, ${(Buffer.byteLength(treeJson) / 1024).toFixed(1)}KB → ${(compressed.length / 1024).toFixed(1)}KB gzip, ${elapsed3}ms)`);
|
|
86299
|
-
}), (err) => {
|
|
86300
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File tree fulfillment failed for ${request2.workingDir}: ${getErrorMessage(err)}`);
|
|
86301
|
-
return exports_Effect.void;
|
|
86302
|
-
});
|
|
86303
|
-
}
|
|
86304
|
-
}), startFileTreeSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
87228
|
+
// src/commands/machine/daemon-start/file-write-subscription.ts
|
|
87229
|
+
var startFileWriteSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
86305
87230
|
const session2 = yield* DaemonSessionService;
|
|
86306
87231
|
let processing = false;
|
|
86307
|
-
const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.
|
|
87232
|
+
const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.getPendingFileWriteRequests, {
|
|
86308
87233
|
sessionId: session2.sessionId,
|
|
86309
87234
|
machineId: session2.machineId
|
|
86310
87235
|
}, (requests) => {
|
|
@@ -86313,27 +87238,27 @@ var fulfillFileTreeRequestsEffect = (session2, requests) => exports_Effect.gen(f
|
|
|
86313
87238
|
if (processing)
|
|
86314
87239
|
return;
|
|
86315
87240
|
processing = true;
|
|
86316
|
-
exports_Effect.runPromise(
|
|
86317
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File
|
|
87241
|
+
exports_Effect.runPromise(fulfillFileWriteRequestsEffect.pipe(exports_Effect.provideService(DaemonSessionService, session2))).catch((err) => {
|
|
87242
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write subscription processing failed: ${getErrorMessage(err)}`);
|
|
86318
87243
|
}).finally(() => {
|
|
86319
87244
|
processing = false;
|
|
86320
87245
|
});
|
|
86321
87246
|
}, (err) => {
|
|
86322
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File
|
|
87247
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write subscription error: ${getErrorMessage(err)}`);
|
|
86323
87248
|
});
|
|
86324
|
-
console.log(`[${formatTimestamp()}]
|
|
87249
|
+
console.log(`[${formatTimestamp()}] ✏️ File write subscription started (reactive)`);
|
|
86325
87250
|
return {
|
|
86326
87251
|
stop: () => {
|
|
86327
87252
|
unsubscribe();
|
|
86328
|
-
console.log(`[${formatTimestamp()}]
|
|
87253
|
+
console.log(`[${formatTimestamp()}] ✏️ File write subscription stopped`);
|
|
86329
87254
|
}
|
|
86330
87255
|
};
|
|
86331
87256
|
});
|
|
86332
|
-
var
|
|
87257
|
+
var init_file_write_subscription = __esm(() => {
|
|
86333
87258
|
init_esm();
|
|
86334
87259
|
init_daemon_services();
|
|
87260
|
+
init_file_write_fulfillment();
|
|
86335
87261
|
init_api3();
|
|
86336
|
-
init_file_tree_scanner();
|
|
86337
87262
|
init_convex_error();
|
|
86338
87263
|
});
|
|
86339
87264
|
|
|
@@ -88805,11 +89730,11 @@ class AgentProcessManager {
|
|
|
88805
89730
|
const initPrompt = await this.fetchInitPromptResult(opts, slot);
|
|
88806
89731
|
if (!initPrompt.ok)
|
|
88807
89732
|
return initPrompt.result;
|
|
88808
|
-
const
|
|
88809
|
-
if (!
|
|
88810
|
-
return
|
|
88811
|
-
await this.finalizeRunningSlot(key, slot, opts,
|
|
88812
|
-
return { success: true, pid:
|
|
89733
|
+
const spawn7 = await this.spawnAgentForEnsureRunning(key, slot, opts, initPrompt, wantResume);
|
|
89734
|
+
if (!spawn7.ok)
|
|
89735
|
+
return spawn7.result;
|
|
89736
|
+
await this.finalizeRunningSlot(key, slot, opts, spawn7.spawnResult, wantResume);
|
|
89737
|
+
return { success: true, pid: spawn7.spawnResult.pid };
|
|
88813
89738
|
} catch (e) {
|
|
88814
89739
|
this.resetSlotIdle(slot);
|
|
88815
89740
|
return { success: false, error: `Unexpected error: ${e.message}` };
|
|
@@ -90016,10 +90941,10 @@ function mergeDefs(...defs) {
|
|
|
90016
90941
|
function cloneDef(schema) {
|
|
90017
90942
|
return mergeDefs(schema._zod.def);
|
|
90018
90943
|
}
|
|
90019
|
-
function getElementAtPath(obj,
|
|
90020
|
-
if (!
|
|
90944
|
+
function getElementAtPath(obj, path6) {
|
|
90945
|
+
if (!path6)
|
|
90021
90946
|
return obj;
|
|
90022
|
-
return
|
|
90947
|
+
return path6.reduce((acc, key) => acc?.[key], obj);
|
|
90023
90948
|
}
|
|
90024
90949
|
function promiseAllObject(promisesObj) {
|
|
90025
90950
|
const keys3 = Object.keys(promisesObj);
|
|
@@ -90347,11 +91272,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
90347
91272
|
}
|
|
90348
91273
|
return false;
|
|
90349
91274
|
}
|
|
90350
|
-
function prefixIssues(
|
|
91275
|
+
function prefixIssues(path6, issues) {
|
|
90351
91276
|
return issues.map((iss) => {
|
|
90352
91277
|
var _a3;
|
|
90353
91278
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
90354
|
-
iss.path.unshift(
|
|
91279
|
+
iss.path.unshift(path6);
|
|
90355
91280
|
return iss;
|
|
90356
91281
|
});
|
|
90357
91282
|
}
|
|
@@ -90564,16 +91489,16 @@ function flattenError(error, mapper = (issue2) => issue2.message) {
|
|
|
90564
91489
|
}
|
|
90565
91490
|
function formatError2(error, mapper = (issue2) => issue2.message) {
|
|
90566
91491
|
const fieldErrors = { _errors: [] };
|
|
90567
|
-
const processError = (error2,
|
|
91492
|
+
const processError = (error2, path6 = []) => {
|
|
90568
91493
|
for (const issue2 of error2.issues) {
|
|
90569
91494
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
90570
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
91495
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
90571
91496
|
} else if (issue2.code === "invalid_key") {
|
|
90572
|
-
processError({ issues: issue2.issues }, [...
|
|
91497
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90573
91498
|
} else if (issue2.code === "invalid_element") {
|
|
90574
|
-
processError({ issues: issue2.issues }, [...
|
|
91499
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90575
91500
|
} else {
|
|
90576
|
-
const fullpath = [...
|
|
91501
|
+
const fullpath = [...path6, ...issue2.path];
|
|
90577
91502
|
if (fullpath.length === 0) {
|
|
90578
91503
|
fieldErrors._errors.push(mapper(issue2));
|
|
90579
91504
|
} else {
|
|
@@ -90600,17 +91525,17 @@ function formatError2(error, mapper = (issue2) => issue2.message) {
|
|
|
90600
91525
|
}
|
|
90601
91526
|
function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
90602
91527
|
const result = { errors: [] };
|
|
90603
|
-
const processError = (error2,
|
|
91528
|
+
const processError = (error2, path6 = []) => {
|
|
90604
91529
|
var _a3, _b2;
|
|
90605
91530
|
for (const issue2 of error2.issues) {
|
|
90606
91531
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
90607
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
91532
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
90608
91533
|
} else if (issue2.code === "invalid_key") {
|
|
90609
|
-
processError({ issues: issue2.issues }, [...
|
|
91534
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90610
91535
|
} else if (issue2.code === "invalid_element") {
|
|
90611
|
-
processError({ issues: issue2.issues }, [...
|
|
91536
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90612
91537
|
} else {
|
|
90613
|
-
const fullpath = [...
|
|
91538
|
+
const fullpath = [...path6, ...issue2.path];
|
|
90614
91539
|
if (fullpath.length === 0) {
|
|
90615
91540
|
result.errors.push(mapper(issue2));
|
|
90616
91541
|
continue;
|
|
@@ -90642,8 +91567,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
90642
91567
|
}
|
|
90643
91568
|
function toDotPath(_path) {
|
|
90644
91569
|
const segs = [];
|
|
90645
|
-
const
|
|
90646
|
-
for (const seg of
|
|
91570
|
+
const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
91571
|
+
for (const seg of path6) {
|
|
90647
91572
|
if (typeof seg === "number")
|
|
90648
91573
|
segs.push(`[${seg}]`);
|
|
90649
91574
|
else if (typeof seg === "symbol")
|
|
@@ -103646,13 +104571,13 @@ function resolveRef(ref, ctx) {
|
|
|
103646
104571
|
if (!ref.startsWith("#")) {
|
|
103647
104572
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
103648
104573
|
}
|
|
103649
|
-
const
|
|
103650
|
-
if (
|
|
104574
|
+
const path6 = ref.slice(1).split("/").filter(Boolean);
|
|
104575
|
+
if (path6.length === 0) {
|
|
103651
104576
|
return ctx.rootSchema;
|
|
103652
104577
|
}
|
|
103653
104578
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
103654
|
-
if (
|
|
103655
|
-
const key =
|
|
104579
|
+
if (path6[0] === defsKey) {
|
|
104580
|
+
const key = path6[1];
|
|
103656
104581
|
if (!key || !ctx.defs[key]) {
|
|
103657
104582
|
throw new Error(`Reference not found: ${ref}`);
|
|
103658
104583
|
}
|
|
@@ -105589,6 +106514,8 @@ var init_command_loop = __esm(() => {
|
|
|
105589
106514
|
init_featureFlags();
|
|
105590
106515
|
init_reliability();
|
|
105591
106516
|
init_esm();
|
|
106517
|
+
init_dir_listing_subscription();
|
|
106518
|
+
init_dir_listing_watch_subscription();
|
|
105592
106519
|
init_api3();
|
|
105593
106520
|
init_on_request_start_agent();
|
|
105594
106521
|
init_on_request_stop_agent();
|
|
@@ -105602,7 +106529,7 @@ var init_command_loop = __esm(() => {
|
|
|
105602
106529
|
init_daemon_services();
|
|
105603
106530
|
init_start_subscriptions();
|
|
105604
106531
|
init_file_content_subscription();
|
|
105605
|
-
|
|
106532
|
+
init_file_write_subscription();
|
|
105606
106533
|
init_git_heartbeat();
|
|
105607
106534
|
init_git_subscription();
|
|
105608
106535
|
init_command_runner();
|
|
@@ -105648,7 +106575,9 @@ var init_command_loop = __esm(() => {
|
|
|
105648
106575
|
heartbeatTimer.unref();
|
|
105649
106576
|
let gitSubscriptionHandle = null;
|
|
105650
106577
|
let fileContentSubscriptionHandle = null;
|
|
105651
|
-
let
|
|
106578
|
+
let fileWriteSubscriptionHandle = null;
|
|
106579
|
+
let dirListingSubscriptionHandle = null;
|
|
106580
|
+
let dirListingWatchSubscriptionHandle = null;
|
|
105652
106581
|
let workspaceListSubscriptionHandle = null;
|
|
105653
106582
|
let observedSyncSubscriptionHandle = null;
|
|
105654
106583
|
let logObserverSubscriptionHandle = null;
|
|
@@ -105716,7 +106645,9 @@ var init_command_loop = __esm(() => {
|
|
|
105716
106645
|
const stopSubscriptions = () => {
|
|
105717
106646
|
gitSubscriptionHandle?.stop();
|
|
105718
106647
|
fileContentSubscriptionHandle?.stop();
|
|
105719
|
-
|
|
106648
|
+
fileWriteSubscriptionHandle?.stop();
|
|
106649
|
+
dirListingSubscriptionHandle?.stop();
|
|
106650
|
+
dirListingWatchSubscriptionHandle?.stop();
|
|
105720
106651
|
workspaceListSubscriptionHandle?.stop();
|
|
105721
106652
|
observedSyncSubscriptionHandle?.stop();
|
|
105722
106653
|
taskMonitorHandle?.stop();
|
|
@@ -105760,7 +106691,9 @@ var init_command_loop = __esm(() => {
|
|
|
105760
106691
|
const wsClient2 = yield* exports_Effect.promise(() => getConvexWsClient());
|
|
105761
106692
|
gitSubscriptionHandle = yield* startGitRequestSubscriptionEffect(wsClient2);
|
|
105762
106693
|
fileContentSubscriptionHandle = yield* startFileContentSubscriptionEffect(wsClient2);
|
|
105763
|
-
|
|
106694
|
+
fileWriteSubscriptionHandle = yield* startFileWriteSubscriptionEffect(wsClient2);
|
|
106695
|
+
dirListingSubscriptionHandle = yield* startDirListingSubscriptionEffect(wsClient2);
|
|
106696
|
+
dirListingWatchSubscriptionHandle = yield* startDirListingWatchSubscriptionEffect(wsClient2);
|
|
105764
106697
|
workspaceListSubscriptionHandle = yield* startWorkspaceListSubscriptionEffect(wsClient2);
|
|
105765
106698
|
if (observedSyncEnabled) {
|
|
105766
106699
|
observedSyncSubscriptionHandle = yield* startObservedSyncSubscriptionEffect(wsClient2);
|
|
@@ -105962,7 +106895,7 @@ __export(exports_opencode_install, {
|
|
|
105962
106895
|
installTool: () => installTool
|
|
105963
106896
|
});
|
|
105964
106897
|
import * as os2 from "os";
|
|
105965
|
-
import * as
|
|
106898
|
+
import * as path6 from "path";
|
|
105966
106899
|
async function isChatroomInstalledDefault() {
|
|
105967
106900
|
try {
|
|
105968
106901
|
const { execSync: execSync3 } = await import("child_process");
|
|
@@ -106332,9 +107265,9 @@ After logging in, try this command again.\`;
|
|
|
106332
107265
|
const fsService = yield* OpenCodeInstallFsService;
|
|
106333
107266
|
const { checkExisting = true } = options;
|
|
106334
107267
|
const homeDir = os2.homedir();
|
|
106335
|
-
const toolDir =
|
|
106336
|
-
const toolPath =
|
|
106337
|
-
const handoffToolPath =
|
|
107268
|
+
const toolDir = path6.join(homeDir, ".config", "opencode", "tool");
|
|
107269
|
+
const toolPath = path6.join(toolDir, "chatroom.ts");
|
|
107270
|
+
const handoffToolPath = path6.join(toolDir, "chatroom-handoff.ts");
|
|
106338
107271
|
if (checkExisting) {
|
|
106339
107272
|
const existingFiles = [];
|
|
106340
107273
|
const toolExists = yield* fsService.access(toolPath);
|
|
@@ -106889,4 +107822,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
106889
107822
|
});
|
|
106890
107823
|
program2.parse();
|
|
106891
107824
|
|
|
106892
|
-
//# debugId=
|
|
107825
|
+
//# debugId=1F6FB9F04F102BC664756E2164756E21
|