chatroom-cli 1.59.1 → 1.60.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1355 -412
- package/dist/index.js.map +28 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -76485,6 +76485,14 @@ Keep one slice ≈ one focused review surface. Delegate slices incrementally —
|
|
|
76485
76485
|
}
|
|
76486
76486
|
var init_planner_to_builder = () => {};
|
|
76487
76487
|
|
|
76488
|
+
// ../../services/backend/prompts/utils/unresolved-decisions.ts
|
|
76489
|
+
function getUnresolvedDecisionsSectionBlock() {
|
|
76490
|
+
return `## Unresolved Decisions
|
|
76491
|
+
<!-- Decisions that need user input before work can proceed. -->
|
|
76492
|
+
- <decision or question — options considered, recommendation if any, or "Not Applicable">
|
|
76493
|
+
<Carry forward decisions still open from earlier handoffs in this chatroom. Remove items the user has resolved. Do not decide on the user's behalf unless they explicitly asked you to. Write \`Not Applicable\` only when there are truly no open decisions.>`;
|
|
76494
|
+
}
|
|
76495
|
+
|
|
76488
76496
|
// ../../services/backend/prompts/teams/duo/handoff-templates/planner-to-user.ts
|
|
76489
76497
|
function getPlannerToUserReportTemplate(roleGuidanceContext) {
|
|
76490
76498
|
return `${getHandoffRecipientVisibilityCallout("user")}
|
|
@@ -76549,6 +76557,8 @@ flowchart TD
|
|
|
76549
76557
|
## Code Change Verification
|
|
76550
76558
|
${CODE_CHANGE_VERIFICATION_CONFIRMATION}
|
|
76551
76559
|
|
|
76560
|
+
${getUnresolvedDecisionsSectionBlock()}
|
|
76561
|
+
|
|
76552
76562
|
## Notes / Next steps
|
|
76553
76563
|
<anything the user should know, follow-ups, or open questions, or "Not Applicable">
|
|
76554
76564
|
\`\`\``;
|
|
@@ -76647,6 +76657,8 @@ flowchart TD
|
|
|
76647
76657
|
## Code Change Verification
|
|
76648
76658
|
${CODE_CHANGE_VERIFICATION_CONFIRMATION}
|
|
76649
76659
|
|
|
76660
|
+
${getUnresolvedDecisionsSectionBlock()}
|
|
76661
|
+
|
|
76650
76662
|
## Notes / Next steps
|
|
76651
76663
|
<anything the user should know, follow-ups, or open questions, or "Not Applicable">
|
|
76652
76664
|
\`\`\``;
|
|
@@ -79917,6 +79929,765 @@ var init_daemon_services = __esm(() => {
|
|
|
79917
79929
|
};
|
|
79918
79930
|
});
|
|
79919
79931
|
|
|
79932
|
+
// src/commands/machine/daemon-start/utils.ts
|
|
79933
|
+
function formatTimestamp() {
|
|
79934
|
+
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
79935
|
+
}
|
|
79936
|
+
|
|
79937
|
+
// src/infrastructure/services/workspace/dir-listing-content-hash.ts
|
|
79938
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
79939
|
+
function computeDirListingContentHash(listing) {
|
|
79940
|
+
const payload = {
|
|
79941
|
+
entries: listing.entries,
|
|
79942
|
+
truncated: listing.truncated,
|
|
79943
|
+
totalCount: listing.totalCount
|
|
79944
|
+
};
|
|
79945
|
+
return createHash2("md5").update(JSON.stringify(payload)).digest("hex");
|
|
79946
|
+
}
|
|
79947
|
+
var init_dir_listing_content_hash = () => {};
|
|
79948
|
+
|
|
79949
|
+
// src/infrastructure/services/workspace/workspace-path-security.ts
|
|
79950
|
+
import { realpath } from "node:fs/promises";
|
|
79951
|
+
import { basename, dirname as dirname8, isAbsolute, relative, resolve as resolve3, sep } from "node:path";
|
|
79952
|
+
import { gunzipSync } from "node:zlib";
|
|
79953
|
+
function validateRelativePathSegments(filePath) {
|
|
79954
|
+
if (filePath.includes("\x00"))
|
|
79955
|
+
return { ok: false, error: "Invalid file path" };
|
|
79956
|
+
if (filePath.includes(".."))
|
|
79957
|
+
return { ok: false, error: "Invalid file path" };
|
|
79958
|
+
if (filePath.startsWith("/"))
|
|
79959
|
+
return { ok: false, error: "Invalid file path" };
|
|
79960
|
+
return { ok: true };
|
|
79961
|
+
}
|
|
79962
|
+
function isPathInsideRoot(workspaceRoot, targetPath) {
|
|
79963
|
+
const rel = relative(workspaceRoot, targetPath);
|
|
79964
|
+
if (rel === "")
|
|
79965
|
+
return true;
|
|
79966
|
+
if (rel.startsWith("..") || rel.includes(`..${sep}`))
|
|
79967
|
+
return false;
|
|
79968
|
+
if (isAbsolute(rel))
|
|
79969
|
+
return false;
|
|
79970
|
+
return true;
|
|
79971
|
+
}
|
|
79972
|
+
async function resolvePathWithinWorkspace(workingDir, filePath) {
|
|
79973
|
+
const basic = validateRelativePathSegments(filePath);
|
|
79974
|
+
if (!basic.ok)
|
|
79975
|
+
return basic;
|
|
79976
|
+
let workspaceRoot;
|
|
79977
|
+
try {
|
|
79978
|
+
workspaceRoot = await realpath(resolve3(workingDir));
|
|
79979
|
+
} catch {
|
|
79980
|
+
return { ok: false, error: "Working directory not found" };
|
|
79981
|
+
}
|
|
79982
|
+
const candidate = resolve3(workspaceRoot, filePath);
|
|
79983
|
+
if (!isPathInsideRoot(workspaceRoot, candidate)) {
|
|
79984
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
79985
|
+
}
|
|
79986
|
+
try {
|
|
79987
|
+
const resolved = await realpath(candidate);
|
|
79988
|
+
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
79989
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
79990
|
+
}
|
|
79991
|
+
return { ok: true, absolutePath: resolved };
|
|
79992
|
+
} catch (err) {
|
|
79993
|
+
const code2 = err?.code;
|
|
79994
|
+
if (code2 !== "ENOENT") {
|
|
79995
|
+
return { ok: false, error: "Invalid file path" };
|
|
79996
|
+
}
|
|
79997
|
+
const parent = dirname8(candidate);
|
|
79998
|
+
if (parent === workspaceRoot || isPathInsideRoot(workspaceRoot, parent)) {
|
|
79999
|
+
try {
|
|
80000
|
+
const parentReal = await realpath(parent);
|
|
80001
|
+
if (!isPathInsideRoot(workspaceRoot, parentReal)) {
|
|
80002
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
80003
|
+
}
|
|
80004
|
+
const resolved = resolve3(parentReal, basename(candidate));
|
|
80005
|
+
if (!isPathInsideRoot(workspaceRoot, resolved)) {
|
|
80006
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
80007
|
+
}
|
|
80008
|
+
return { ok: true, absolutePath: resolved };
|
|
80009
|
+
} catch {
|
|
80010
|
+
return { ok: true, absolutePath: candidate };
|
|
80011
|
+
}
|
|
80012
|
+
}
|
|
80013
|
+
return { ok: false, error: "Path escapes workspace" };
|
|
80014
|
+
}
|
|
80015
|
+
}
|
|
80016
|
+
function gunzipBase64Payload(base64, maxBytes) {
|
|
80017
|
+
let compressed;
|
|
80018
|
+
try {
|
|
80019
|
+
compressed = Buffer.from(base64, "base64");
|
|
80020
|
+
} catch {
|
|
80021
|
+
return { ok: false, errorMessage: "Missing file data" };
|
|
80022
|
+
}
|
|
80023
|
+
if (compressed.length > maxBytes * 10) {
|
|
80024
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
80025
|
+
}
|
|
80026
|
+
try {
|
|
80027
|
+
const content = gunzipSync(compressed, { maxOutputLength: maxBytes });
|
|
80028
|
+
if (content.length > maxBytes) {
|
|
80029
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
80030
|
+
}
|
|
80031
|
+
return { ok: true, content };
|
|
80032
|
+
} catch {
|
|
80033
|
+
return { ok: false, errorMessage: "File content too large" };
|
|
80034
|
+
}
|
|
80035
|
+
}
|
|
80036
|
+
var init_workspace_path_security = () => {};
|
|
80037
|
+
|
|
80038
|
+
// src/infrastructure/services/workspace/workspace-visibility-policy.ts
|
|
80039
|
+
import { exec as exec2, spawn as spawn3 } from "node:child_process";
|
|
80040
|
+
import { promisify as promisify2 } from "node:util";
|
|
80041
|
+
function isAlwaysExcludedDirName(name) {
|
|
80042
|
+
return ALWAYS_EXCLUDE_DIR_NAMES.has(name);
|
|
80043
|
+
}
|
|
80044
|
+
function isSecretPath(relativePath) {
|
|
80045
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
80046
|
+
return SECRET_PATH_PATTERNS.some((pattern) => pattern.test(normalized));
|
|
80047
|
+
}
|
|
80048
|
+
function hasExcludedDirSegment(relativePath) {
|
|
80049
|
+
const segments = relativePath.split("/");
|
|
80050
|
+
return segments.some((segment) => isAlwaysExcludedDirName(segment));
|
|
80051
|
+
}
|
|
80052
|
+
function isPathVisible(relativePath) {
|
|
80053
|
+
if (!relativePath)
|
|
80054
|
+
return true;
|
|
80055
|
+
return !isSecretPath(relativePath) && !hasExcludedDirSegment(relativePath);
|
|
80056
|
+
}
|
|
80057
|
+
function isPathContentReadable(relativePath) {
|
|
80058
|
+
return isPathVisible(relativePath);
|
|
80059
|
+
}
|
|
80060
|
+
async function isGitRepo(rootDir) {
|
|
80061
|
+
try {
|
|
80062
|
+
const { stdout } = await execAsync2("git rev-parse --is-inside-work-tree", {
|
|
80063
|
+
cwd: rootDir,
|
|
80064
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" },
|
|
80065
|
+
maxBuffer: 1024 * 1024
|
|
80066
|
+
});
|
|
80067
|
+
return stdout.trim() === "true";
|
|
80068
|
+
} catch {
|
|
80069
|
+
return false;
|
|
80070
|
+
}
|
|
80071
|
+
}
|
|
80072
|
+
async function filterGitIgnored(rootDir, relativePaths) {
|
|
80073
|
+
if (relativePaths.length === 0)
|
|
80074
|
+
return new Set;
|
|
80075
|
+
const inRepo = await isGitRepo(rootDir);
|
|
80076
|
+
if (!inRepo)
|
|
80077
|
+
return new Set;
|
|
80078
|
+
try {
|
|
80079
|
+
const stdout = await new Promise((resolve4, reject) => {
|
|
80080
|
+
const child = spawn3("git", ["check-ignore", "--stdin", "-z"], {
|
|
80081
|
+
cwd: rootDir,
|
|
80082
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" }
|
|
80083
|
+
});
|
|
80084
|
+
let output = "";
|
|
80085
|
+
child.stdout.on("data", (chunk2) => {
|
|
80086
|
+
output += chunk2.toString();
|
|
80087
|
+
});
|
|
80088
|
+
child.on("error", reject);
|
|
80089
|
+
child.on("close", () => resolve4(output));
|
|
80090
|
+
child.stdin.write(relativePaths.join(`
|
|
80091
|
+
`));
|
|
80092
|
+
child.stdin.end();
|
|
80093
|
+
});
|
|
80094
|
+
const ignored = new Set;
|
|
80095
|
+
if (!stdout)
|
|
80096
|
+
return ignored;
|
|
80097
|
+
for (const entry of stdout.split("\x00")) {
|
|
80098
|
+
const trimmed = entry.trim();
|
|
80099
|
+
if (trimmed)
|
|
80100
|
+
ignored.add(trimmed);
|
|
80101
|
+
}
|
|
80102
|
+
return ignored;
|
|
80103
|
+
} catch {
|
|
80104
|
+
return new Set;
|
|
80105
|
+
}
|
|
80106
|
+
}
|
|
80107
|
+
var execAsync2, ALWAYS_EXCLUDE_DIR_NAMES, SECRET_PATH_PATTERNS;
|
|
80108
|
+
var init_workspace_visibility_policy = __esm(() => {
|
|
80109
|
+
execAsync2 = promisify2(exec2);
|
|
80110
|
+
ALWAYS_EXCLUDE_DIR_NAMES = new Set([
|
|
80111
|
+
"node_modules",
|
|
80112
|
+
".git",
|
|
80113
|
+
"dist",
|
|
80114
|
+
"build",
|
|
80115
|
+
".next",
|
|
80116
|
+
"coverage",
|
|
80117
|
+
"__pycache__",
|
|
80118
|
+
".turbo",
|
|
80119
|
+
".cache",
|
|
80120
|
+
".tmp",
|
|
80121
|
+
"tmp",
|
|
80122
|
+
"_generated",
|
|
80123
|
+
".vercel"
|
|
80124
|
+
]);
|
|
80125
|
+
SECRET_PATH_PATTERNS = [
|
|
80126
|
+
/^\.env$/,
|
|
80127
|
+
/^\.env\./,
|
|
80128
|
+
/\.pem$/,
|
|
80129
|
+
/\.key$/,
|
|
80130
|
+
/id_rsa$/,
|
|
80131
|
+
/credentials\.json$/,
|
|
80132
|
+
/^secrets(\/|$)/,
|
|
80133
|
+
/^\.aws(\/|$)/
|
|
80134
|
+
];
|
|
80135
|
+
});
|
|
80136
|
+
|
|
80137
|
+
// src/infrastructure/services/workspace/dir-listing-scanner.ts
|
|
80138
|
+
import { promises as fsPromises } from "node:fs";
|
|
80139
|
+
import path3 from "node:path";
|
|
80140
|
+
async function listDirectory(rootDir, dirPath, options) {
|
|
80141
|
+
const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
80142
|
+
const scannedAt = Date.now();
|
|
80143
|
+
const absDir = dirPath ? path3.join(rootDir, dirPath) : rootDir;
|
|
80144
|
+
const resolvedRoot = path3.resolve(rootDir);
|
|
80145
|
+
const resolvedDir = path3.resolve(absDir);
|
|
80146
|
+
if (!isPathInsideRoot(resolvedRoot, resolvedDir)) {
|
|
80147
|
+
return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
|
|
80148
|
+
}
|
|
80149
|
+
let dirents;
|
|
80150
|
+
try {
|
|
80151
|
+
dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
|
|
80152
|
+
} catch {
|
|
80153
|
+
return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
|
|
80154
|
+
}
|
|
80155
|
+
const candidates = [];
|
|
80156
|
+
for (const ent of dirents) {
|
|
80157
|
+
if (isAlwaysExcludedDirName(ent.name))
|
|
80158
|
+
continue;
|
|
80159
|
+
const relativePath = dirPath ? `${dirPath}/${ent.name}` : ent.name;
|
|
80160
|
+
if (!isPathVisible(relativePath))
|
|
80161
|
+
continue;
|
|
80162
|
+
if (ent.isDirectory()) {
|
|
80163
|
+
candidates.push({ name: ent.name, path: relativePath, type: "directory" });
|
|
80164
|
+
} else if (ent.isFile()) {
|
|
80165
|
+
let size9;
|
|
80166
|
+
try {
|
|
80167
|
+
const st = await fsPromises.stat(path3.join(absDir, ent.name));
|
|
80168
|
+
size9 = st.size;
|
|
80169
|
+
} catch {}
|
|
80170
|
+
candidates.push({ name: ent.name, path: relativePath, type: "file", size: size9 });
|
|
80171
|
+
}
|
|
80172
|
+
}
|
|
80173
|
+
const ignored = await filterGitIgnored(rootDir, candidates.map((c) => c.path));
|
|
80174
|
+
const visible = candidates.filter((c) => !ignored.has(c.path));
|
|
80175
|
+
visible.sort((a, b) => {
|
|
80176
|
+
if (a.type === "directory" && b.type === "file")
|
|
80177
|
+
return -1;
|
|
80178
|
+
if (a.type === "file" && b.type === "directory")
|
|
80179
|
+
return 1;
|
|
80180
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
80181
|
+
});
|
|
80182
|
+
const totalCount = visible.length;
|
|
80183
|
+
const truncated = totalCount > maxEntries;
|
|
80184
|
+
const entries2 = visible.slice(0, maxEntries);
|
|
80185
|
+
return { dirPath, entries: entries2, scannedAt, truncated, totalCount };
|
|
80186
|
+
}
|
|
80187
|
+
var DEFAULT_MAX_ENTRIES = 500;
|
|
80188
|
+
var init_dir_listing_scanner = __esm(() => {
|
|
80189
|
+
init_workspace_path_security();
|
|
80190
|
+
init_workspace_visibility_policy();
|
|
80191
|
+
});
|
|
80192
|
+
|
|
80193
|
+
// src/infrastructure/services/workspace/dir-listing-sync.ts
|
|
80194
|
+
import { gzipSync } from "node:zlib";
|
|
80195
|
+
function listingCacheKey(workingDir, dirPath) {
|
|
80196
|
+
return `${workingDir}\x00${dirPath}`;
|
|
80197
|
+
}
|
|
80198
|
+
async function scanDirListingForSync(workingDir, dirPath) {
|
|
80199
|
+
const listing = await listDirectory(workingDir, dirPath);
|
|
80200
|
+
const dataHash = computeDirListingContentHash(listing);
|
|
80201
|
+
const cacheKey = listingCacheKey(workingDir, dirPath);
|
|
80202
|
+
if (lastSyncedContentHash.get(cacheKey) === dataHash)
|
|
80203
|
+
return null;
|
|
80204
|
+
const json = JSON.stringify(listing);
|
|
80205
|
+
return {
|
|
80206
|
+
dirPath,
|
|
80207
|
+
data: { compression: "gzip", content: gzipSync(Buffer.from(json)).toString("base64") },
|
|
80208
|
+
dataHash,
|
|
80209
|
+
scannedAt: listing.scannedAt,
|
|
80210
|
+
truncated: listing.truncated,
|
|
80211
|
+
totalCount: listing.totalCount
|
|
80212
|
+
};
|
|
80213
|
+
}
|
|
80214
|
+
async function scanDirListingsWithConcurrency(workingDir, dirPaths) {
|
|
80215
|
+
const items = [];
|
|
80216
|
+
let index = 0;
|
|
80217
|
+
async function worker() {
|
|
80218
|
+
while (index < dirPaths.length) {
|
|
80219
|
+
const currentIndex = index;
|
|
80220
|
+
index += 1;
|
|
80221
|
+
const dirPath = dirPaths[currentIndex];
|
|
80222
|
+
if (dirPath === undefined)
|
|
80223
|
+
continue;
|
|
80224
|
+
const item = await scanDirListingForSync(workingDir, dirPath);
|
|
80225
|
+
if (item)
|
|
80226
|
+
items.push(item);
|
|
80227
|
+
}
|
|
80228
|
+
}
|
|
80229
|
+
const workerCount = Math.min(SCAN_CONCURRENCY, dirPaths.length);
|
|
80230
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
80231
|
+
return items;
|
|
80232
|
+
}
|
|
80233
|
+
function markItemsSynced(workingDir, items) {
|
|
80234
|
+
for (const item of items) {
|
|
80235
|
+
lastSyncedContentHash.set(listingCacheKey(workingDir, item.dirPath), item.dataHash);
|
|
80236
|
+
}
|
|
80237
|
+
}
|
|
80238
|
+
async function syncDirListingToBackend(session2, workingDir, dirPath) {
|
|
80239
|
+
const item = await scanDirListingForSync(workingDir, dirPath);
|
|
80240
|
+
if (!item)
|
|
80241
|
+
return;
|
|
80242
|
+
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
|
|
80243
|
+
sessionId: session2.sessionId,
|
|
80244
|
+
machineId: session2.machineId,
|
|
80245
|
+
workingDir,
|
|
80246
|
+
dirPath: item.dirPath,
|
|
80247
|
+
data: item.data,
|
|
80248
|
+
dataHash: item.dataHash,
|
|
80249
|
+
scannedAt: item.scannedAt,
|
|
80250
|
+
truncated: item.truncated,
|
|
80251
|
+
totalCount: item.totalCount
|
|
80252
|
+
});
|
|
80253
|
+
markItemsSynced(workingDir, [item]);
|
|
80254
|
+
}
|
|
80255
|
+
async function syncDirListingsToBackend(session2, workingDir, dirPaths) {
|
|
80256
|
+
const unique = [...new Set(dirPaths)];
|
|
80257
|
+
if (unique.length === 0)
|
|
80258
|
+
return;
|
|
80259
|
+
if (unique.length === 1) {
|
|
80260
|
+
const dirPath = unique[0];
|
|
80261
|
+
if (dirPath !== undefined) {
|
|
80262
|
+
await syncDirListingToBackend(session2, workingDir, dirPath);
|
|
80263
|
+
}
|
|
80264
|
+
return;
|
|
80265
|
+
}
|
|
80266
|
+
const items = await scanDirListingsWithConcurrency(workingDir, unique);
|
|
80267
|
+
if (items.length === 0)
|
|
80268
|
+
return;
|
|
80269
|
+
for (let i2 = 0;i2 < items.length; i2 += MAX_BATCH_SIZE) {
|
|
80270
|
+
const chunk2 = items.slice(i2, i2 + MAX_BATCH_SIZE);
|
|
80271
|
+
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2Batch, {
|
|
80272
|
+
sessionId: session2.sessionId,
|
|
80273
|
+
machineId: session2.machineId,
|
|
80274
|
+
workingDir,
|
|
80275
|
+
items: chunk2
|
|
80276
|
+
});
|
|
80277
|
+
markItemsSynced(workingDir, chunk2);
|
|
80278
|
+
}
|
|
80279
|
+
}
|
|
80280
|
+
var MAX_BATCH_SIZE = 25, SCAN_CONCURRENCY = 4, lastSyncedContentHash;
|
|
80281
|
+
var init_dir_listing_sync = __esm(() => {
|
|
80282
|
+
init_dir_listing_content_hash();
|
|
80283
|
+
init_dir_listing_scanner();
|
|
80284
|
+
init_api3();
|
|
80285
|
+
lastSyncedContentHash = new Map;
|
|
80286
|
+
});
|
|
80287
|
+
|
|
80288
|
+
// src/infrastructure/services/workspace/workspace-file-search.ts
|
|
80289
|
+
import { promises as fsPromises2 } from "node:fs";
|
|
80290
|
+
import path4 from "node:path";
|
|
80291
|
+
async function searchWorkspaceFiles(rootDir, query, options) {
|
|
80292
|
+
const maxResults = options?.maxResults ?? DEFAULT_MAX_RESULTS;
|
|
80293
|
+
const scannedAt = Date.now();
|
|
80294
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
80295
|
+
const matches = [];
|
|
80296
|
+
let visitedDirs = 0;
|
|
80297
|
+
let truncated = false;
|
|
80298
|
+
async function visitDir(relDir) {
|
|
80299
|
+
if (visitedDirs >= MAX_VISIT_DIRS || matches.length >= maxResults) {
|
|
80300
|
+
truncated = true;
|
|
80301
|
+
return;
|
|
80302
|
+
}
|
|
80303
|
+
visitedDirs++;
|
|
80304
|
+
const absDir = relDir ? path4.join(rootDir, relDir) : rootDir;
|
|
80305
|
+
let dirents;
|
|
80306
|
+
try {
|
|
80307
|
+
dirents = await fsPromises2.readdir(absDir, { withFileTypes: true });
|
|
80308
|
+
} catch {
|
|
80309
|
+
return;
|
|
80310
|
+
}
|
|
80311
|
+
const fileCandidates = [];
|
|
80312
|
+
const subdirs = [];
|
|
80313
|
+
for (const ent of dirents) {
|
|
80314
|
+
if (isAlwaysExcludedDirName(ent.name))
|
|
80315
|
+
continue;
|
|
80316
|
+
const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
|
|
80317
|
+
if (!isPathVisible(relativePath))
|
|
80318
|
+
continue;
|
|
80319
|
+
if (ent.isDirectory()) {
|
|
80320
|
+
subdirs.push(relativePath);
|
|
80321
|
+
} else if (ent.isFile()) {
|
|
80322
|
+
fileCandidates.push(relativePath);
|
|
80323
|
+
}
|
|
80324
|
+
}
|
|
80325
|
+
const ignored = await filterGitIgnored(rootDir, fileCandidates);
|
|
80326
|
+
for (const filePath of fileCandidates) {
|
|
80327
|
+
if (ignored.has(filePath))
|
|
80328
|
+
continue;
|
|
80329
|
+
const fileName = path4.basename(filePath).toLowerCase();
|
|
80330
|
+
if (normalizedQuery === "" || fileName.includes(normalizedQuery)) {
|
|
80331
|
+
matches.push({ path: filePath, type: "file" });
|
|
80332
|
+
if (matches.length >= maxResults) {
|
|
80333
|
+
truncated = true;
|
|
80334
|
+
return;
|
|
80335
|
+
}
|
|
80336
|
+
}
|
|
80337
|
+
}
|
|
80338
|
+
for (const sub of subdirs) {
|
|
80339
|
+
if (matches.length >= maxResults || visitedDirs >= MAX_VISIT_DIRS) {
|
|
80340
|
+
truncated = true;
|
|
80341
|
+
return;
|
|
80342
|
+
}
|
|
80343
|
+
await visitDir(sub);
|
|
80344
|
+
}
|
|
80345
|
+
}
|
|
80346
|
+
await visitDir("");
|
|
80347
|
+
return {
|
|
80348
|
+
query,
|
|
80349
|
+
entries: matches,
|
|
80350
|
+
scannedAt,
|
|
80351
|
+
truncated,
|
|
80352
|
+
totalCount: matches.length
|
|
80353
|
+
};
|
|
80354
|
+
}
|
|
80355
|
+
var DEFAULT_MAX_RESULTS = 300, MAX_VISIT_DIRS = 2000;
|
|
80356
|
+
var init_workspace_file_search = __esm(() => {
|
|
80357
|
+
init_workspace_visibility_policy();
|
|
80358
|
+
});
|
|
80359
|
+
|
|
80360
|
+
// src/commands/machine/daemon-start/dir-listing-subscription.ts
|
|
80361
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
80362
|
+
import { gzipSync as gzipSync2 } from "node:zlib";
|
|
80363
|
+
function logSubscriptionWarn(label, err) {
|
|
80364
|
+
console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage(err)}`);
|
|
80365
|
+
}
|
|
80366
|
+
async function uploadDirListing(session2, workingDir, dirPath) {
|
|
80367
|
+
await syncDirListingToBackend(session2, workingDir, dirPath);
|
|
80368
|
+
await session2.backend.mutation(api.workspaceFiles.fulfillDirListingRequest, {
|
|
80369
|
+
sessionId: session2.sessionId,
|
|
80370
|
+
machineId: session2.machineId,
|
|
80371
|
+
workingDir,
|
|
80372
|
+
dirPath
|
|
80373
|
+
});
|
|
80374
|
+
}
|
|
80375
|
+
async function uploadFileSearch(session2, workingDir, query) {
|
|
80376
|
+
const result = await searchWorkspaceFiles(workingDir, query);
|
|
80377
|
+
const json = JSON.stringify(result);
|
|
80378
|
+
const dataHash = createHash3("md5").update(json).digest("hex");
|
|
80379
|
+
const compressed = gzipSync2(Buffer.from(json)).toString("base64");
|
|
80380
|
+
await session2.backend.mutation(api.workspaceFiles.syncFileSearchV2, {
|
|
80381
|
+
sessionId: session2.sessionId,
|
|
80382
|
+
machineId: session2.machineId,
|
|
80383
|
+
workingDir,
|
|
80384
|
+
query,
|
|
80385
|
+
data: { compression: "gzip", content: compressed },
|
|
80386
|
+
dataHash,
|
|
80387
|
+
scannedAt: result.scannedAt,
|
|
80388
|
+
truncated: result.truncated,
|
|
80389
|
+
totalCount: result.totalCount
|
|
80390
|
+
});
|
|
80391
|
+
await session2.backend.mutation(api.workspaceFiles.fulfillFileSearchRequest, {
|
|
80392
|
+
sessionId: session2.sessionId,
|
|
80393
|
+
machineId: session2.machineId,
|
|
80394
|
+
workingDir,
|
|
80395
|
+
query
|
|
80396
|
+
});
|
|
80397
|
+
}
|
|
80398
|
+
var fulfillDirListingRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
80399
|
+
for (const request2 of requests) {
|
|
80400
|
+
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
80401
|
+
const start3 = Date.now();
|
|
80402
|
+
yield* exports_Effect.tryPromise(() => uploadDirListing(session2, request2.workingDir, request2.dirPath));
|
|
80403
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing fulfilled: ${request2.workingDir}/${request2.dirPath || "(root)"} (${Date.now() - start3}ms)`);
|
|
80404
|
+
}), (err) => {
|
|
80405
|
+
logSubscriptionWarn(`Dir listing failed for ${request2.workingDir}/${request2.dirPath}`, err);
|
|
80406
|
+
return exports_Effect.void;
|
|
80407
|
+
});
|
|
80408
|
+
}
|
|
80409
|
+
}), fulfillFileSearchRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
|
|
80410
|
+
for (const request2 of requests) {
|
|
80411
|
+
yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
|
|
80412
|
+
const start3 = Date.now();
|
|
80413
|
+
yield* exports_Effect.tryPromise(() => uploadFileSearch(session2, request2.workingDir, request2.query));
|
|
80414
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD0D File search fulfilled: ${request2.workingDir} query="${request2.query}" (${Date.now() - start3}ms)`);
|
|
80415
|
+
}), (err) => {
|
|
80416
|
+
logSubscriptionWarn(`File search failed for ${request2.workingDir}`, err);
|
|
80417
|
+
return exports_Effect.void;
|
|
80418
|
+
});
|
|
80419
|
+
}
|
|
80420
|
+
}), startDirListingSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
80421
|
+
const session2 = yield* DaemonSessionService;
|
|
80422
|
+
let processingDir = false;
|
|
80423
|
+
let processingSearch = false;
|
|
80424
|
+
const unsubDir = wsClient2.onUpdate(api.workspaceFiles.getPendingDirListingRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
80425
|
+
if (!requests?.length || processingDir)
|
|
80426
|
+
return;
|
|
80427
|
+
processingDir = true;
|
|
80428
|
+
exports_Effect.runPromise(fulfillDirListingRequestsEffect(session2, requests)).catch((err) => {
|
|
80429
|
+
logSubscriptionWarn("Dir listing subscription processing failed", err);
|
|
80430
|
+
}).finally(() => {
|
|
80431
|
+
processingDir = false;
|
|
80432
|
+
});
|
|
80433
|
+
}, (err) => {
|
|
80434
|
+
logSubscriptionWarn("Dir listing subscription error", err);
|
|
80435
|
+
});
|
|
80436
|
+
const unsubSearch = wsClient2.onUpdate(api.workspaceFiles.getPendingFileSearchRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
|
|
80437
|
+
if (!requests?.length || processingSearch)
|
|
80438
|
+
return;
|
|
80439
|
+
processingSearch = true;
|
|
80440
|
+
exports_Effect.runPromise(fulfillFileSearchRequestsEffect(session2, requests)).catch((err) => {
|
|
80441
|
+
logSubscriptionWarn("File search subscription processing failed", err);
|
|
80442
|
+
}).finally(() => {
|
|
80443
|
+
processingSearch = false;
|
|
80444
|
+
});
|
|
80445
|
+
}, (err) => {
|
|
80446
|
+
logSubscriptionWarn("File search subscription error", err);
|
|
80447
|
+
});
|
|
80448
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription started (reactive)`);
|
|
80449
|
+
return {
|
|
80450
|
+
stop: () => {
|
|
80451
|
+
unsubDir();
|
|
80452
|
+
unsubSearch();
|
|
80453
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription stopped`);
|
|
80454
|
+
}
|
|
80455
|
+
};
|
|
80456
|
+
});
|
|
80457
|
+
var init_dir_listing_subscription = __esm(() => {
|
|
80458
|
+
init_esm();
|
|
80459
|
+
init_daemon_services();
|
|
80460
|
+
init_api3();
|
|
80461
|
+
init_dir_listing_sync();
|
|
80462
|
+
init_workspace_file_search();
|
|
80463
|
+
init_convex_error();
|
|
80464
|
+
});
|
|
80465
|
+
|
|
80466
|
+
// src/infrastructure/services/workspace/workspace-fs-watch-paths.ts
|
|
80467
|
+
function parentDirPath(relativePath) {
|
|
80468
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
80469
|
+
const idx = normalized.lastIndexOf("/");
|
|
80470
|
+
return idx === -1 ? "" : normalized.slice(0, idx);
|
|
80471
|
+
}
|
|
80472
|
+
function shouldIgnoreWatchRelativePath(relativePath) {
|
|
80473
|
+
const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
80474
|
+
if (!normalized || normalized === ".")
|
|
80475
|
+
return false;
|
|
80476
|
+
return hasExcludedDirSegment(normalized);
|
|
80477
|
+
}
|
|
80478
|
+
function dirsToRefreshForEvent(relativePath, isDirectory = false) {
|
|
80479
|
+
const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
80480
|
+
if (!normalized || normalized === ".")
|
|
80481
|
+
return [""];
|
|
80482
|
+
const dirs = new Set;
|
|
80483
|
+
dirs.add(parentDirPath(normalized));
|
|
80484
|
+
if (isDirectory)
|
|
80485
|
+
dirs.add(normalized);
|
|
80486
|
+
return [...dirs];
|
|
80487
|
+
}
|
|
80488
|
+
function filterDirsByActiveSet(dirs, activeDirPaths) {
|
|
80489
|
+
return dirs.filter((d) => activeDirPaths.has(d));
|
|
80490
|
+
}
|
|
80491
|
+
var init_workspace_fs_watch_paths = __esm(() => {
|
|
80492
|
+
init_workspace_visibility_policy();
|
|
80493
|
+
});
|
|
80494
|
+
|
|
80495
|
+
// src/infrastructure/services/workspace/workspace-fs-watcher.ts
|
|
80496
|
+
import { watch } from "node:fs";
|
|
80497
|
+
import path5 from "node:path";
|
|
80498
|
+
function isRecursiveWatchPlatform() {
|
|
80499
|
+
return process.platform === "darwin" || process.platform === "win32";
|
|
80500
|
+
}
|
|
80501
|
+
function normalizeFilename(filename) {
|
|
80502
|
+
if (filename == null)
|
|
80503
|
+
return null;
|
|
80504
|
+
const value = typeof filename === "string" ? filename : filename.toString();
|
|
80505
|
+
if (!value || value === "." || value === "..")
|
|
80506
|
+
return null;
|
|
80507
|
+
return value.replace(/\\/g, "/");
|
|
80508
|
+
}
|
|
80509
|
+
function createWorkspaceFsWatcher(options) {
|
|
80510
|
+
const absWorkingDir = path5.resolve(options.workingDir);
|
|
80511
|
+
const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
80512
|
+
let activeDirPaths = new Set(options.activeDirPaths);
|
|
80513
|
+
let stopped = false;
|
|
80514
|
+
let debounceTimer = null;
|
|
80515
|
+
const pendingDirs = new Set;
|
|
80516
|
+
let rootWatcher = null;
|
|
80517
|
+
const dirWatchers = new Map;
|
|
80518
|
+
const scheduleFlush = () => {
|
|
80519
|
+
if (debounceTimer)
|
|
80520
|
+
clearTimeout(debounceTimer);
|
|
80521
|
+
debounceTimer = setTimeout(() => {
|
|
80522
|
+
debounceTimer = null;
|
|
80523
|
+
if (pendingDirs.size === 0)
|
|
80524
|
+
return;
|
|
80525
|
+
const dirs = [...pendingDirs];
|
|
80526
|
+
pendingDirs.clear();
|
|
80527
|
+
Promise.resolve(options.onRefreshDirs(dirs));
|
|
80528
|
+
}, debounceMs);
|
|
80529
|
+
debounceTimer.unref?.();
|
|
80530
|
+
};
|
|
80531
|
+
const enqueueDirs = (dirs) => {
|
|
80532
|
+
for (const dir of dirs)
|
|
80533
|
+
pendingDirs.add(dir);
|
|
80534
|
+
scheduleFlush();
|
|
80535
|
+
};
|
|
80536
|
+
const handleRelativePath = (relativePath, isDirectory = false) => {
|
|
80537
|
+
if (stopped)
|
|
80538
|
+
return;
|
|
80539
|
+
if (shouldIgnoreWatchRelativePath(relativePath))
|
|
80540
|
+
return;
|
|
80541
|
+
const toRefresh = filterDirsByActiveSet(dirsToRefreshForEvent(relativePath, isDirectory), activeDirPaths);
|
|
80542
|
+
if (toRefresh.length > 0)
|
|
80543
|
+
enqueueDirs(toRefresh);
|
|
80544
|
+
};
|
|
80545
|
+
const onWatchEvent = (watchedDirPath, filename) => {
|
|
80546
|
+
const normalizedFilename = normalizeFilename(filename);
|
|
80547
|
+
if (!normalizedFilename)
|
|
80548
|
+
return;
|
|
80549
|
+
let relativePath;
|
|
80550
|
+
if (isRecursiveWatchPlatform()) {
|
|
80551
|
+
relativePath = normalizedFilename;
|
|
80552
|
+
} else if (watchedDirPath === "") {
|
|
80553
|
+
relativePath = normalizedFilename;
|
|
80554
|
+
} else {
|
|
80555
|
+
relativePath = `${watchedDirPath}/${normalizedFilename}`;
|
|
80556
|
+
}
|
|
80557
|
+
const isDirectory = relativePath.endsWith("/");
|
|
80558
|
+
handleRelativePath(relativePath.replace(/\/+$/, ""), isDirectory);
|
|
80559
|
+
};
|
|
80560
|
+
const closePerDirWatchers = () => {
|
|
80561
|
+
for (const watcher of dirWatchers.values())
|
|
80562
|
+
watcher.close();
|
|
80563
|
+
dirWatchers.clear();
|
|
80564
|
+
};
|
|
80565
|
+
const startPerDirWatch = (dirPath) => {
|
|
80566
|
+
if (dirPath === "" || dirWatchers.has(dirPath))
|
|
80567
|
+
return;
|
|
80568
|
+
const absDir = path5.join(absWorkingDir, dirPath);
|
|
80569
|
+
const watcher = watch(absDir, (_eventType, filename) => {
|
|
80570
|
+
onWatchEvent(dirPath, filename);
|
|
80571
|
+
});
|
|
80572
|
+
dirWatchers.set(dirPath, watcher);
|
|
80573
|
+
};
|
|
80574
|
+
const rewirePerDirWatches = () => {
|
|
80575
|
+
const wanted = new Set;
|
|
80576
|
+
for (const dirPath of activeDirPaths) {
|
|
80577
|
+
if (dirPath !== "")
|
|
80578
|
+
wanted.add(dirPath);
|
|
80579
|
+
}
|
|
80580
|
+
for (const [dirPath, watcher] of dirWatchers) {
|
|
80581
|
+
if (!wanted.has(dirPath)) {
|
|
80582
|
+
watcher.close();
|
|
80583
|
+
dirWatchers.delete(dirPath);
|
|
80584
|
+
}
|
|
80585
|
+
}
|
|
80586
|
+
for (const dirPath of wanted) {
|
|
80587
|
+
if (!dirWatchers.has(dirPath))
|
|
80588
|
+
startPerDirWatch(dirPath);
|
|
80589
|
+
}
|
|
80590
|
+
};
|
|
80591
|
+
const startWatching = () => {
|
|
80592
|
+
if (isRecursiveWatchPlatform()) {
|
|
80593
|
+
rootWatcher = watch(absWorkingDir, { recursive: true }, (_eventType, filename) => {
|
|
80594
|
+
onWatchEvent("", filename);
|
|
80595
|
+
});
|
|
80596
|
+
return;
|
|
80597
|
+
}
|
|
80598
|
+
rootWatcher = watch(absWorkingDir, (_eventType, filename) => {
|
|
80599
|
+
onWatchEvent("", filename);
|
|
80600
|
+
});
|
|
80601
|
+
rewirePerDirWatches();
|
|
80602
|
+
};
|
|
80603
|
+
startWatching();
|
|
80604
|
+
return {
|
|
80605
|
+
updateActiveDirPaths: (paths) => {
|
|
80606
|
+
activeDirPaths = new Set(paths);
|
|
80607
|
+
if (!isRecursiveWatchPlatform() && !stopped) {
|
|
80608
|
+
rewirePerDirWatches();
|
|
80609
|
+
}
|
|
80610
|
+
},
|
|
80611
|
+
stop: () => {
|
|
80612
|
+
stopped = true;
|
|
80613
|
+
if (debounceTimer) {
|
|
80614
|
+
clearTimeout(debounceTimer);
|
|
80615
|
+
debounceTimer = null;
|
|
80616
|
+
}
|
|
80617
|
+
rootWatcher?.close();
|
|
80618
|
+
rootWatcher = null;
|
|
80619
|
+
closePerDirWatchers();
|
|
80620
|
+
pendingDirs.clear();
|
|
80621
|
+
}
|
|
80622
|
+
};
|
|
80623
|
+
}
|
|
80624
|
+
var DEFAULT_DEBOUNCE_MS = 400;
|
|
80625
|
+
var init_workspace_fs_watcher = __esm(() => {
|
|
80626
|
+
init_workspace_fs_watch_paths();
|
|
80627
|
+
});
|
|
80628
|
+
|
|
80629
|
+
// src/commands/machine/daemon-start/dir-listing-watch-subscription.ts
|
|
80630
|
+
var startDirListingWatchSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
80631
|
+
const session2 = yield* DaemonSessionService;
|
|
80632
|
+
const watchers = new Map;
|
|
80633
|
+
const applyTargets = (targets) => {
|
|
80634
|
+
const nextWorkingDirs = new Set(targets.map((t) => t.workingDir));
|
|
80635
|
+
for (const [workingDir, handle] of watchers) {
|
|
80636
|
+
if (!nextWorkingDirs.has(workingDir)) {
|
|
80637
|
+
handle.stop();
|
|
80638
|
+
watchers.delete(workingDir);
|
|
80639
|
+
}
|
|
80640
|
+
}
|
|
80641
|
+
for (const target of targets) {
|
|
80642
|
+
const activeSet = new Set(target.activeDirPaths);
|
|
80643
|
+
const existing = watchers.get(target.workingDir);
|
|
80644
|
+
if (existing) {
|
|
80645
|
+
existing.updateActiveDirPaths(activeSet);
|
|
80646
|
+
continue;
|
|
80647
|
+
}
|
|
80648
|
+
const handle = createWorkspaceFsWatcher({
|
|
80649
|
+
workingDir: target.workingDir,
|
|
80650
|
+
activeDirPaths: activeSet,
|
|
80651
|
+
onRefreshDirs: async (dirPaths) => {
|
|
80652
|
+
try {
|
|
80653
|
+
await syncDirListingsToBackend(session2, target.workingDir, dirPaths);
|
|
80654
|
+
} catch (err) {
|
|
80655
|
+
console.warn(`[${formatTimestamp()}] ⚠️ FS watch sync failed for ${target.workingDir}: ${getErrorMessage(err)}`);
|
|
80656
|
+
}
|
|
80657
|
+
}
|
|
80658
|
+
});
|
|
80659
|
+
watchers.set(target.workingDir, handle);
|
|
80660
|
+
}
|
|
80661
|
+
};
|
|
80662
|
+
let stopped = false;
|
|
80663
|
+
const unsub = wsClient2.onUpdate(api.workspaceFiles.listDirListingWatchTargets, { sessionId: session2.sessionId, machineId: session2.machineId }, (targets) => {
|
|
80664
|
+
if (stopped)
|
|
80665
|
+
return;
|
|
80666
|
+
applyTargets(targets ?? []);
|
|
80667
|
+
}, (err) => {
|
|
80668
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Dir listing watch subscription error: ${getErrorMessage(err)}`);
|
|
80669
|
+
});
|
|
80670
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription started`);
|
|
80671
|
+
return {
|
|
80672
|
+
stop: () => {
|
|
80673
|
+
stopped = true;
|
|
80674
|
+
unsub();
|
|
80675
|
+
for (const handle of watchers.values())
|
|
80676
|
+
handle.stop();
|
|
80677
|
+
watchers.clear();
|
|
80678
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription stopped`);
|
|
80679
|
+
}
|
|
80680
|
+
};
|
|
80681
|
+
});
|
|
80682
|
+
var init_dir_listing_watch_subscription = __esm(() => {
|
|
80683
|
+
init_esm();
|
|
80684
|
+
init_daemon_services();
|
|
80685
|
+
init_api3();
|
|
80686
|
+
init_dir_listing_sync();
|
|
80687
|
+
init_workspace_fs_watcher();
|
|
80688
|
+
init_convex_error();
|
|
80689
|
+
});
|
|
80690
|
+
|
|
79920
80691
|
// src/events/daemon/agent/on-request-start-agent.ts
|
|
79921
80692
|
function notifyAgentStartFailed(backend2, opts) {
|
|
79922
80693
|
backend2.mutation(api.machines.emitAgentStartFailed, opts).catch((err) => {
|
|
@@ -80016,13 +80787,8 @@ var init_on_request_stop_agent = __esm(() => {
|
|
|
80016
80787
|
init_stop_agent();
|
|
80017
80788
|
});
|
|
80018
80789
|
|
|
80019
|
-
// src/commands/machine/daemon-start/utils.ts
|
|
80020
|
-
function formatTimestamp() {
|
|
80021
|
-
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
80022
|
-
}
|
|
80023
|
-
|
|
80024
80790
|
// src/commands/machine/daemon-start/handlers/orphan-tracker.ts
|
|
80025
|
-
import { createHash as
|
|
80791
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
80026
80792
|
import {
|
|
80027
80793
|
appendFileSync,
|
|
80028
80794
|
existsSync as existsSync5,
|
|
@@ -80036,7 +80802,7 @@ import { homedir as homedir5 } from "node:os";
|
|
|
80036
80802
|
import { join as join15 } from "node:path";
|
|
80037
80803
|
function getUrlHash() {
|
|
80038
80804
|
const url2 = getConvexUrl();
|
|
80039
|
-
return
|
|
80805
|
+
return createHash4("sha256").update(url2).digest("hex").substring(0, 8);
|
|
80040
80806
|
}
|
|
80041
80807
|
function getChildPidsFilePath() {
|
|
80042
80808
|
const dir = join15(homedir5(), ".chatroom");
|
|
@@ -80230,19 +80996,19 @@ class ProcessManager {
|
|
|
80230
80996
|
this.pendingStops.clear();
|
|
80231
80997
|
}
|
|
80232
80998
|
waitForExit(runId, ms) {
|
|
80233
|
-
return new Promise((
|
|
80999
|
+
return new Promise((resolve4) => {
|
|
80234
81000
|
const interval = 100;
|
|
80235
81001
|
let elapsed3 = 0;
|
|
80236
81002
|
const timer = setInterval(() => {
|
|
80237
81003
|
if (!this.runningProcesses.has(runId)) {
|
|
80238
81004
|
clearInterval(timer);
|
|
80239
|
-
|
|
81005
|
+
resolve4(true);
|
|
80240
81006
|
return;
|
|
80241
81007
|
}
|
|
80242
81008
|
elapsed3 += interval;
|
|
80243
81009
|
if (elapsed3 >= ms) {
|
|
80244
81010
|
clearInterval(timer);
|
|
80245
|
-
|
|
81011
|
+
resolve4(false);
|
|
80246
81012
|
}
|
|
80247
81013
|
}, interval);
|
|
80248
81014
|
});
|
|
@@ -80277,9 +81043,9 @@ var init_killer = __esm(() => {
|
|
|
80277
81043
|
});
|
|
80278
81044
|
|
|
80279
81045
|
// ../../services/backend/src/output-encoding.ts
|
|
80280
|
-
import { gunzipSync, gzipSync } from "node:zlib";
|
|
81046
|
+
import { gunzipSync as gunzipSync2, gzipSync as gzipSync3 } from "node:zlib";
|
|
80281
81047
|
function encodeOutput(plain) {
|
|
80282
|
-
const compressed =
|
|
81048
|
+
const compressed = gzipSync3(Buffer.from(plain, "utf-8"));
|
|
80283
81049
|
return {
|
|
80284
81050
|
compression: "gzip",
|
|
80285
81051
|
content: compressed.toString("base64")
|
|
@@ -80457,7 +81223,7 @@ var init_output_store = __esm(() => {
|
|
|
80457
81223
|
});
|
|
80458
81224
|
|
|
80459
81225
|
// src/commands/machine/daemon-start/handlers/process/spawner.ts
|
|
80460
|
-
import { spawn as
|
|
81226
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
80461
81227
|
async function flushTailV2(deps, tracked, force = false) {
|
|
80462
81228
|
if (!force && !isRunLogObserved(tracked.runId))
|
|
80463
81229
|
return;
|
|
@@ -80540,7 +81306,7 @@ async function spawnCommandProcess(deps, event, commandKey) {
|
|
|
80540
81306
|
tempDirReady = true;
|
|
80541
81307
|
}
|
|
80542
81308
|
const store = createOutputStore(runIdStr);
|
|
80543
|
-
const child =
|
|
81309
|
+
const child = spawn4("sh", ["-c", script], {
|
|
80544
81310
|
cwd: workingDir,
|
|
80545
81311
|
env: buildChatroomSpawnEnv(deps.convexUrl),
|
|
80546
81312
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -80802,8 +81568,8 @@ var init_command_runner = __esm(() => {
|
|
|
80802
81568
|
}).catch((err) => {
|
|
80803
81569
|
console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as killed on shutdown: ${getErrorMessage(err)}`);
|
|
80804
81570
|
})));
|
|
80805
|
-
yield* exports_Effect.promise(() => new Promise((
|
|
80806
|
-
const t = setTimeout(
|
|
81571
|
+
yield* exports_Effect.promise(() => new Promise((resolve4) => {
|
|
81572
|
+
const t = setTimeout(resolve4, 3000);
|
|
80807
81573
|
t.unref?.();
|
|
80808
81574
|
}));
|
|
80809
81575
|
for (const [, tracked] of trackedEntries) {
|
|
@@ -80815,8 +81581,8 @@ var init_command_runner = __esm(() => {
|
|
|
80815
81581
|
clearTrackedPids();
|
|
80816
81582
|
yield* exports_Effect.promise(() => Promise.race([
|
|
80817
81583
|
statusUpdates,
|
|
80818
|
-
new Promise((
|
|
80819
|
-
const t = setTimeout(
|
|
81584
|
+
new Promise((resolve4) => {
|
|
81585
|
+
const t = setTimeout(resolve4, 2000);
|
|
80820
81586
|
t.unref?.();
|
|
80821
81587
|
})
|
|
80822
81588
|
]));
|
|
@@ -80851,28 +81617,81 @@ var init_on_daemon_shutdown = __esm(() => {
|
|
|
80851
81617
|
connected: false
|
|
80852
81618
|
}).catch(() => {}));
|
|
80853
81619
|
});
|
|
80854
|
-
});
|
|
80855
|
-
|
|
80856
|
-
// src/infrastructure/git/types.ts
|
|
80857
|
-
function makeGitStateKey(machineId, workingDir) {
|
|
80858
|
-
return `${machineId}::${workingDir}`;
|
|
81620
|
+
});
|
|
81621
|
+
|
|
81622
|
+
// src/infrastructure/git/types.ts
|
|
81623
|
+
function makeGitStateKey(machineId, workingDir) {
|
|
81624
|
+
return `${machineId}::${workingDir}`;
|
|
81625
|
+
}
|
|
81626
|
+
var FULL_DIFF_MAX_BYTES = 500000, COMMITS_PER_PAGE = 20;
|
|
81627
|
+
|
|
81628
|
+
// src/infrastructure/git/run-command.ts
|
|
81629
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
81630
|
+
function runCommandSpawn(command, args2, cwd, options) {
|
|
81631
|
+
return new Promise((resolve4) => {
|
|
81632
|
+
const child = spawn5(command, args2, {
|
|
81633
|
+
cwd,
|
|
81634
|
+
env: options?.env ?? DEFAULT_GIT_ENV,
|
|
81635
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
81636
|
+
});
|
|
81637
|
+
let stdout = "";
|
|
81638
|
+
let stderr = "";
|
|
81639
|
+
const maxBuffer = options?.maxBuffer ?? 10 * 1024 * 1024;
|
|
81640
|
+
const onData = (chunk2, target) => {
|
|
81641
|
+
const str = chunk2.toString();
|
|
81642
|
+
if (target === "stdout")
|
|
81643
|
+
stdout += str;
|
|
81644
|
+
else
|
|
81645
|
+
stderr += str;
|
|
81646
|
+
if (stdout.length + stderr.length > maxBuffer) {
|
|
81647
|
+
child.kill("SIGTERM");
|
|
81648
|
+
}
|
|
81649
|
+
};
|
|
81650
|
+
child.stdout?.on("data", (c) => onData(c, "stdout"));
|
|
81651
|
+
child.stderr?.on("data", (c) => onData(c, "stderr"));
|
|
81652
|
+
const timer = options?.timeout ? setTimeout(() => child.kill("SIGTERM"), options.timeout) : undefined;
|
|
81653
|
+
child.on("close", (code2) => {
|
|
81654
|
+
if (timer)
|
|
81655
|
+
clearTimeout(timer);
|
|
81656
|
+
if (code2 === 0)
|
|
81657
|
+
resolve4({ stdout, stderr });
|
|
81658
|
+
else {
|
|
81659
|
+
resolve4({
|
|
81660
|
+
error: Object.assign(new Error(stderr || stdout || `exit ${code2}`), {
|
|
81661
|
+
code: code2 ?? undefined
|
|
81662
|
+
})
|
|
81663
|
+
});
|
|
81664
|
+
}
|
|
81665
|
+
});
|
|
81666
|
+
child.on("error", (err) => {
|
|
81667
|
+
if (timer)
|
|
81668
|
+
clearTimeout(timer);
|
|
81669
|
+
resolve4({ error: err });
|
|
81670
|
+
});
|
|
81671
|
+
});
|
|
80859
81672
|
}
|
|
80860
|
-
|
|
81673
|
+
function runGit(args2, cwd, options) {
|
|
81674
|
+
return runCommandSpawn("git", args2, cwd, options);
|
|
81675
|
+
}
|
|
81676
|
+
function runGh(args2, cwd, options) {
|
|
81677
|
+
return runCommandSpawn("gh", args2, cwd, {
|
|
81678
|
+
timeout: options?.timeout,
|
|
81679
|
+
env: { ...process.env, NO_COLOR: "1" }
|
|
81680
|
+
});
|
|
81681
|
+
}
|
|
81682
|
+
var DEFAULT_GIT_ENV;
|
|
81683
|
+
var init_run_command = __esm(() => {
|
|
81684
|
+
DEFAULT_GIT_ENV = {
|
|
81685
|
+
...process.env,
|
|
81686
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
81687
|
+
GIT_PAGER: "cat",
|
|
81688
|
+
NO_COLOR: "1"
|
|
81689
|
+
};
|
|
81690
|
+
});
|
|
80861
81691
|
|
|
80862
81692
|
// 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
|
-
}
|
|
81693
|
+
function repoArgs(repoSlug) {
|
|
81694
|
+
return repoSlug ? ["--repo", repoSlug] : [];
|
|
80876
81695
|
}
|
|
80877
81696
|
function isGitNotInstalled(message) {
|
|
80878
81697
|
return message.includes("command not found") || message.includes("ENOENT") || message.includes("not found") || message.includes("'git' is not recognized");
|
|
@@ -80898,14 +81717,14 @@ function classifyError(errMessage) {
|
|
|
80898
81717
|
}
|
|
80899
81718
|
return { status: "error", message: errMessage.trim() };
|
|
80900
81719
|
}
|
|
80901
|
-
async function
|
|
80902
|
-
const result = await runGit("rev-parse --git-dir", workingDir);
|
|
81720
|
+
async function isGitRepo2(workingDir) {
|
|
81721
|
+
const result = await runGit(["rev-parse", "--git-dir"], workingDir);
|
|
80903
81722
|
if ("error" in result)
|
|
80904
81723
|
return false;
|
|
80905
81724
|
return result.stdout.trim().length > 0;
|
|
80906
81725
|
}
|
|
80907
81726
|
async function getBranch(workingDir) {
|
|
80908
|
-
const result = await runGit("rev-parse --abbrev-ref HEAD", workingDir);
|
|
81727
|
+
const result = await runGit(["rev-parse", "--abbrev-ref", "HEAD"], workingDir);
|
|
80909
81728
|
if ("error" in result) {
|
|
80910
81729
|
const errMsg = result.error.message;
|
|
80911
81730
|
if (errMsg.includes("unknown revision") || errMsg.includes("No such file or directory") || errMsg.includes("does not have any commits")) {
|
|
@@ -80920,7 +81739,7 @@ async function getBranch(workingDir) {
|
|
|
80920
81739
|
return { status: "available", branch };
|
|
80921
81740
|
}
|
|
80922
81741
|
async function isDirty(workingDir) {
|
|
80923
|
-
const result = await runGit("status --porcelain", workingDir);
|
|
81742
|
+
const result = await runGit(["status", "--porcelain"], workingDir);
|
|
80924
81743
|
if ("error" in result)
|
|
80925
81744
|
return false;
|
|
80926
81745
|
return result.stdout.trim().length > 0;
|
|
@@ -80936,7 +81755,7 @@ function parseDiffStatLine(statLine) {
|
|
|
80936
81755
|
};
|
|
80937
81756
|
}
|
|
80938
81757
|
async function getDiffStat(workingDir) {
|
|
80939
|
-
const result = await runGit("diff HEAD --stat", workingDir);
|
|
81758
|
+
const result = await runGit(["diff", "HEAD", "--stat"], workingDir);
|
|
80940
81759
|
if ("error" in result) {
|
|
80941
81760
|
const errMsg = result.error.message;
|
|
80942
81761
|
if (isEmptyRepo(result.error.message)) {
|
|
@@ -80965,7 +81784,9 @@ async function getDiffStat(workingDir) {
|
|
|
80965
81784
|
return { status: "available", diffStat };
|
|
80966
81785
|
}
|
|
80967
81786
|
async function getFullDiff(workingDir) {
|
|
80968
|
-
const result = await runGit("diff HEAD", workingDir
|
|
81787
|
+
const result = await runGit(["diff", "HEAD"], workingDir, {
|
|
81788
|
+
maxBuffer: FULL_DIFF_MAX_BYTES + 64 * 1024
|
|
81789
|
+
});
|
|
80969
81790
|
if ("error" in result) {
|
|
80970
81791
|
const errMsg = result.error.message;
|
|
80971
81792
|
if (isEmptyRepo(errMsg)) {
|
|
@@ -80990,8 +81811,7 @@ async function getFullDiff(workingDir) {
|
|
|
80990
81811
|
}
|
|
80991
81812
|
async function getPRDiffByNumber(cwd, prNumber) {
|
|
80992
81813
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
80993
|
-
const
|
|
80994
|
-
const result = await runCommand(`gh pr diff ${prNumber}${repoFlag}`, cwd);
|
|
81814
|
+
const result = await runGh(["pr", "diff", String(prNumber), ...repoArgs(repoSlug)], cwd);
|
|
80995
81815
|
if ("error" in result) {
|
|
80996
81816
|
return { status: "error", message: result.error.message };
|
|
80997
81817
|
}
|
|
@@ -81008,8 +81828,11 @@ async function getPRDiffByNumber(cwd, prNumber) {
|
|
|
81008
81828
|
}
|
|
81009
81829
|
async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
|
|
81010
81830
|
const format4 = "%H%x1f%h%x1f%s%x1f%b%x1f%an%x1f%aI%x1e";
|
|
81011
|
-
const
|
|
81012
|
-
|
|
81831
|
+
const logArgs = ["log", `-${count3}`];
|
|
81832
|
+
if (skip > 0)
|
|
81833
|
+
logArgs.push(`--skip=${skip}`);
|
|
81834
|
+
logArgs.push(`--format=${format4}`);
|
|
81835
|
+
const result = await runGit(logArgs, workingDir);
|
|
81013
81836
|
if ("error" in result) {
|
|
81014
81837
|
return [];
|
|
81015
81838
|
}
|
|
@@ -81031,7 +81854,7 @@ async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
|
|
|
81031
81854
|
return commits;
|
|
81032
81855
|
}
|
|
81033
81856
|
async function getCommitDetail(workingDir, sha) {
|
|
81034
|
-
const result = await runGit(
|
|
81857
|
+
const result = await runGit(["show", sha, "--format=", "--stat", "-p"], workingDir);
|
|
81035
81858
|
if ("error" in result) {
|
|
81036
81859
|
const errMsg = result.error.message;
|
|
81037
81860
|
const classified = classifyError(errMsg);
|
|
@@ -81052,7 +81875,7 @@ async function getCommitDetail(workingDir, sha) {
|
|
|
81052
81875
|
}
|
|
81053
81876
|
async function getCommitMetadata(workingDir, sha) {
|
|
81054
81877
|
const format4 = "%s%x1f%b%x1f%an%x1f%aI";
|
|
81055
|
-
const result = await runGit(
|
|
81878
|
+
const result = await runGit(["log", "-1", `--format=${format4}`, sha], workingDir);
|
|
81056
81879
|
if ("error" in result)
|
|
81057
81880
|
return null;
|
|
81058
81881
|
const output = result.stdout.trim();
|
|
@@ -81065,18 +81888,6 @@ async function getCommitMetadata(workingDir, sha) {
|
|
|
81065
81888
|
const body = rawBody.trim();
|
|
81066
81889
|
return { message, ...body ? { body } : {}, author, date };
|
|
81067
81890
|
}
|
|
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
81891
|
function parseRepoSlug(remoteUrl) {
|
|
81081
81892
|
const trimmed = remoteUrl.trim();
|
|
81082
81893
|
const httpsMatch = trimmed.match(/https?:\/\/[^/]+\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
@@ -81090,7 +81901,7 @@ function parseRepoSlug(remoteUrl) {
|
|
|
81090
81901
|
return null;
|
|
81091
81902
|
}
|
|
81092
81903
|
async function getOriginRepoSlug(cwd) {
|
|
81093
|
-
const result = await runGit("remote get-url origin", cwd);
|
|
81904
|
+
const result = await runGit(["remote", "get-url", "origin"], cwd);
|
|
81094
81905
|
if ("error" in result)
|
|
81095
81906
|
return null;
|
|
81096
81907
|
const url2 = result.stdout.trim();
|
|
@@ -81100,9 +81911,22 @@ async function getOriginRepoSlug(cwd) {
|
|
|
81100
81911
|
}
|
|
81101
81912
|
async function getOpenPRsForBranch(cwd, branch) {
|
|
81102
81913
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
81103
|
-
const repoFlag = repoSlug ? ` --repo ${JSON.stringify(repoSlug)}` : "";
|
|
81104
81914
|
const repoOwner = repoSlug?.split("/")[0] ?? null;
|
|
81105
|
-
const result = await
|
|
81915
|
+
const result = await runGh([
|
|
81916
|
+
"pr",
|
|
81917
|
+
"list",
|
|
81918
|
+
"--head",
|
|
81919
|
+
branch,
|
|
81920
|
+
"--state",
|
|
81921
|
+
"open",
|
|
81922
|
+
"--author",
|
|
81923
|
+
"@me",
|
|
81924
|
+
"--json",
|
|
81925
|
+
"number,title,url,headRefName,state,headRepositoryOwner",
|
|
81926
|
+
"--limit",
|
|
81927
|
+
"5",
|
|
81928
|
+
...repoArgs(repoSlug)
|
|
81929
|
+
], cwd);
|
|
81106
81930
|
if ("error" in result) {
|
|
81107
81931
|
return [];
|
|
81108
81932
|
}
|
|
@@ -81133,8 +81957,17 @@ function isGHPRItem(item) {
|
|
|
81133
81957
|
}
|
|
81134
81958
|
async function getAllPRs(cwd) {
|
|
81135
81959
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
81136
|
-
const
|
|
81137
|
-
|
|
81960
|
+
const result = await runGh([
|
|
81961
|
+
"pr",
|
|
81962
|
+
"list",
|
|
81963
|
+
"--limit",
|
|
81964
|
+
"20",
|
|
81965
|
+
"--state",
|
|
81966
|
+
"all",
|
|
81967
|
+
"--json",
|
|
81968
|
+
"number,title,state,headRefName,baseRefName,url,author,createdAt,updatedAt,mergedAt,closedAt,isDraft",
|
|
81969
|
+
...repoArgs(repoSlug)
|
|
81970
|
+
], cwd);
|
|
81138
81971
|
if ("error" in result) {
|
|
81139
81972
|
return [];
|
|
81140
81973
|
}
|
|
@@ -81168,8 +82001,7 @@ async function getAllPRs(cwd) {
|
|
|
81168
82001
|
}
|
|
81169
82002
|
async function getPRCommits(cwd, prNumber) {
|
|
81170
82003
|
const repoSlug = await getOriginRepoSlug(cwd);
|
|
81171
|
-
const
|
|
81172
|
-
const result = await runCommand(`gh pr view ${prNumber} --json commits${repoFlag}`, cwd);
|
|
82004
|
+
const result = await runGh(["pr", "view", String(prNumber), "--json", "commits", ...repoArgs(repoSlug)], cwd);
|
|
81173
82005
|
if ("error" in result) {
|
|
81174
82006
|
return [];
|
|
81175
82007
|
}
|
|
@@ -81206,7 +82038,7 @@ async function getPRCommits(cwd, prNumber) {
|
|
|
81206
82038
|
}
|
|
81207
82039
|
}
|
|
81208
82040
|
async function getRemotes(cwd) {
|
|
81209
|
-
const result = await runGit("remote -v", cwd);
|
|
82041
|
+
const result = await runGit(["remote", "-v"], cwd);
|
|
81210
82042
|
if ("error" in result)
|
|
81211
82043
|
return [];
|
|
81212
82044
|
if (!result.stdout.trim())
|
|
@@ -81230,14 +82062,14 @@ async function getRemotes(cwd) {
|
|
|
81230
82062
|
return remotes;
|
|
81231
82063
|
}
|
|
81232
82064
|
async function getCommitsAhead(workingDir) {
|
|
81233
|
-
const result = await runGit("rev-list --count @{upstream}..HEAD", workingDir);
|
|
82065
|
+
const result = await runGit(["rev-list", "--count", "@{upstream}..HEAD"], workingDir);
|
|
81234
82066
|
if ("error" in result)
|
|
81235
82067
|
return 0;
|
|
81236
82068
|
const count3 = parseInt(result.stdout.trim(), 10);
|
|
81237
82069
|
return Number.isNaN(count3) ? 0 : count3;
|
|
81238
82070
|
}
|
|
81239
82071
|
async function getCommitsBehind(workingDir) {
|
|
81240
|
-
const result = await runGit("rev-list --count HEAD..@{upstream}", workingDir);
|
|
82072
|
+
const result = await runGit(["rev-list", "--count", "HEAD..@{upstream}"], workingDir);
|
|
81241
82073
|
if ("error" in result)
|
|
81242
82074
|
return 0;
|
|
81243
82075
|
const count3 = parseInt(result.stdout.trim(), 10);
|
|
@@ -81249,8 +82081,18 @@ async function getCommitStatusChecks(cwd, ref) {
|
|
|
81249
82081
|
return null;
|
|
81250
82082
|
try {
|
|
81251
82083
|
const [checkRunsResult, legacyStatusesResult] = await Promise.all([
|
|
81252
|
-
|
|
81253
|
-
|
|
82084
|
+
runGh([
|
|
82085
|
+
"api",
|
|
82086
|
+
`repos/${repoSlug}/commits/${encodeURIComponent(ref)}/check-runs`,
|
|
82087
|
+
"--jq",
|
|
82088
|
+
"{check_runs: [.check_runs[] | {name: .name, status: .status, conclusion: .conclusion}], total_count: .total_count}"
|
|
82089
|
+
], cwd),
|
|
82090
|
+
runGh([
|
|
82091
|
+
"api",
|
|
82092
|
+
`repos/${repoSlug}/commits/${encodeURIComponent(ref)}/statuses`,
|
|
82093
|
+
"--jq",
|
|
82094
|
+
"[group_by(.context)[] | max_by(.created_at) | {context: .context, state: .state, target_url: .target_url}]"
|
|
82095
|
+
], cwd)
|
|
81254
82096
|
]);
|
|
81255
82097
|
if ("error" in checkRunsResult || "error" in legacyStatusesResult)
|
|
81256
82098
|
return null;
|
|
@@ -81303,49 +82145,34 @@ async function getCommitStatusChecks(cwd, ref) {
|
|
|
81303
82145
|
return null;
|
|
81304
82146
|
}
|
|
81305
82147
|
}
|
|
81306
|
-
var execAsync2;
|
|
81307
82148
|
var init_git_reader = __esm(() => {
|
|
81308
|
-
|
|
82149
|
+
init_run_command();
|
|
81309
82150
|
});
|
|
81310
82151
|
|
|
81311
82152
|
// 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
82153
|
function classifyError2(errMessage) {
|
|
81327
82154
|
return { status: "error", message: errMessage.trim() };
|
|
81328
82155
|
}
|
|
81329
82156
|
async function discardFile(workingDir, filePath) {
|
|
81330
|
-
const result = await
|
|
82157
|
+
const result = await runGit(["checkout", "--", filePath], workingDir);
|
|
81331
82158
|
if ("error" in result) {
|
|
81332
82159
|
return classifyError2(result.error.message);
|
|
81333
82160
|
}
|
|
81334
82161
|
return { status: "available" };
|
|
81335
82162
|
}
|
|
81336
82163
|
async function discardAllChanges(workingDir) {
|
|
81337
|
-
const checkoutResult = await
|
|
82164
|
+
const checkoutResult = await runGit(["checkout", "--", "."], workingDir);
|
|
81338
82165
|
if ("error" in checkoutResult) {
|
|
81339
82166
|
return classifyError2(checkoutResult.error.message);
|
|
81340
82167
|
}
|
|
81341
|
-
const cleanResult = await
|
|
82168
|
+
const cleanResult = await runGit(["clean", "-fd"], workingDir);
|
|
81342
82169
|
if ("error" in cleanResult) {
|
|
81343
82170
|
return classifyError2(cleanResult.error.message);
|
|
81344
82171
|
}
|
|
81345
82172
|
return { status: "available" };
|
|
81346
82173
|
}
|
|
81347
82174
|
async function gitPull(workingDir) {
|
|
81348
|
-
const result = await
|
|
82175
|
+
const result = await runGit(["pull"], workingDir);
|
|
81349
82176
|
if ("error" in result) {
|
|
81350
82177
|
const message = result.error.message;
|
|
81351
82178
|
if (message.includes("no tracking branch")) {
|
|
@@ -81372,7 +82199,7 @@ async function gitPull(workingDir) {
|
|
|
81372
82199
|
return { status: "available" };
|
|
81373
82200
|
}
|
|
81374
82201
|
async function gitPush(workingDir) {
|
|
81375
|
-
const result = await
|
|
82202
|
+
const result = await runGit(["push"], workingDir);
|
|
81376
82203
|
if ("error" in result) {
|
|
81377
82204
|
const message = result.error.message;
|
|
81378
82205
|
if (message.includes("no upstream branch")) {
|
|
@@ -81402,9 +82229,8 @@ async function gitSync(workingDir) {
|
|
|
81402
82229
|
}
|
|
81403
82230
|
return gitPush(workingDir);
|
|
81404
82231
|
}
|
|
81405
|
-
var execAsync3;
|
|
81406
82232
|
var init_git_writer = __esm(() => {
|
|
81407
|
-
|
|
82233
|
+
init_run_command();
|
|
81408
82234
|
});
|
|
81409
82235
|
|
|
81410
82236
|
// src/infrastructure/git/index.ts
|
|
@@ -81414,7 +82240,7 @@ var init_git = __esm(() => {
|
|
|
81414
82240
|
});
|
|
81415
82241
|
|
|
81416
82242
|
// src/infrastructure/local-actions/execute-local-action.ts
|
|
81417
|
-
import { exec as
|
|
82243
|
+
import { exec as exec3 } from "node:child_process";
|
|
81418
82244
|
import { access as access3 } from "node:fs/promises";
|
|
81419
82245
|
function escapeShellArg(arg) {
|
|
81420
82246
|
return `"${arg.replace(/"/g, "\\\"")}"`;
|
|
@@ -81423,14 +82249,14 @@ function resolveWhichCommand(name) {
|
|
|
81423
82249
|
return process.platform === "win32" ? `where ${name}` : `which ${name}`;
|
|
81424
82250
|
}
|
|
81425
82251
|
function isCliAvailable(cliName) {
|
|
81426
|
-
return new Promise((
|
|
81427
|
-
|
|
81428
|
-
|
|
82252
|
+
return new Promise((resolve4) => {
|
|
82253
|
+
exec3(resolveWhichCommand(cliName), (err) => {
|
|
82254
|
+
resolve4(!err);
|
|
81429
82255
|
});
|
|
81430
82256
|
});
|
|
81431
82257
|
}
|
|
81432
82258
|
function execFireAndForget(command, logTag) {
|
|
81433
|
-
|
|
82259
|
+
exec3(command, (err) => {
|
|
81434
82260
|
if (err) {
|
|
81435
82261
|
console.warn(`[${logTag}] exec failed: ${err.message}`);
|
|
81436
82262
|
}
|
|
@@ -81546,13 +82372,13 @@ var init_local_actions = __esm(() => {
|
|
|
81546
82372
|
});
|
|
81547
82373
|
|
|
81548
82374
|
// src/commands/machine/pid.ts
|
|
81549
|
-
import { createHash as
|
|
82375
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
81550
82376
|
import { existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
81551
82377
|
import { homedir as homedir6 } from "node:os";
|
|
81552
82378
|
import { join as join17 } from "node:path";
|
|
81553
82379
|
function getUrlHash2() {
|
|
81554
82380
|
const url2 = getConvexUrl();
|
|
81555
|
-
return
|
|
82381
|
+
return createHash5("sha256").update(url2).digest("hex").substring(0, 8);
|
|
81556
82382
|
}
|
|
81557
82383
|
function getPidFileName() {
|
|
81558
82384
|
return `daemon-${getUrlHash2()}.pid`;
|
|
@@ -81645,7 +82471,7 @@ async function waitForLockOrTimeout(deadline, intervalMs, sleep5) {
|
|
|
81645
82471
|
async function acquireLockWithRetry(options) {
|
|
81646
82472
|
const intervalMs = options?.intervalMs ?? LOCK_RETRY_INTERVAL_MS;
|
|
81647
82473
|
const maxWaitMs = options?.maxWaitMs ?? LOCK_RETRY_MAX_WAIT_MS;
|
|
81648
|
-
const sleep5 = options?.sleep ?? ((ms) => new Promise((
|
|
82474
|
+
const sleep5 = options?.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
|
|
81649
82475
|
const deadline = Date.now() + maxWaitMs;
|
|
81650
82476
|
if (await waitForLockOrTimeout(deadline, intervalMs, sleep5)) {
|
|
81651
82477
|
return true;
|
|
@@ -82573,7 +83399,7 @@ var init_jsonc = __esm(() => {
|
|
|
82573
83399
|
|
|
82574
83400
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
82575
83401
|
import { readFile as readFile7, readdir, stat as stat2 } from "node:fs/promises";
|
|
82576
|
-
import { join as join18, basename, resolve as
|
|
83402
|
+
import { join as join18, basename as basename2, resolve as resolve4 } from "node:path";
|
|
82577
83403
|
async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
82578
83404
|
const parentDir = join18(rootDir, cleaned.slice(0, -2));
|
|
82579
83405
|
try {
|
|
@@ -82583,7 +83409,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
82583
83409
|
if (!entry.isDirectory())
|
|
82584
83410
|
continue;
|
|
82585
83411
|
const dirPath = join18(parentDir, entry.name);
|
|
82586
|
-
if (
|
|
83412
|
+
if (resolve4(dirPath).startsWith(resolve4(rootDir))) {
|
|
82587
83413
|
dirs.push(dirPath);
|
|
82588
83414
|
}
|
|
82589
83415
|
}
|
|
@@ -82595,7 +83421,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
|
|
|
82595
83421
|
async function resolveLiteralPath(rootDir, cleaned) {
|
|
82596
83422
|
const dir = join18(rootDir, cleaned);
|
|
82597
83423
|
try {
|
|
82598
|
-
if (!
|
|
83424
|
+
if (!resolve4(dir).startsWith(resolve4(rootDir)))
|
|
82599
83425
|
return [];
|
|
82600
83426
|
const s = await stat2(dir);
|
|
82601
83427
|
if (s.isDirectory())
|
|
@@ -82616,7 +83442,7 @@ async function readPackageJson(dir) {
|
|
|
82616
83442
|
const content = await readFile7(join18(dir, "package.json"), "utf-8");
|
|
82617
83443
|
const pkg = JSON.parse(content);
|
|
82618
83444
|
return {
|
|
82619
|
-
name: pkg.name ||
|
|
83445
|
+
name: pkg.name || basename2(dir),
|
|
82620
83446
|
scripts: pkg.scripts && typeof pkg.scripts === "object" ? pkg.scripts : {}
|
|
82621
83447
|
};
|
|
82622
83448
|
} catch {
|
|
@@ -82701,7 +83527,7 @@ var init_workspace_resolver = () => {};
|
|
|
82701
83527
|
|
|
82702
83528
|
// src/infrastructure/services/workspace/command-discovery.ts
|
|
82703
83529
|
import { access as access4, readFile as readFile8 } from "node:fs/promises";
|
|
82704
|
-
import { join as join19, relative, basename as
|
|
83530
|
+
import { join as join19, relative as relative2, basename as basename3 } from "node:path";
|
|
82705
83531
|
async function detectPackageManager(workingDir) {
|
|
82706
83532
|
for (const { file, manager } of LOCKFILE_MAP) {
|
|
82707
83533
|
try {
|
|
@@ -82773,7 +83599,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
|
|
|
82773
83599
|
return commands;
|
|
82774
83600
|
}
|
|
82775
83601
|
async function readRootPackageJson(workingDir, pm, scriptPrefix) {
|
|
82776
|
-
let rootPackageName =
|
|
83602
|
+
let rootPackageName = basename3(workingDir);
|
|
82777
83603
|
const pkg = await readJsonFile(join19(workingDir, "package.json"), "root package.json");
|
|
82778
83604
|
if (!pkg)
|
|
82779
83605
|
return { commands: [], rootPackageName };
|
|
@@ -82819,7 +83645,7 @@ async function discoverCommands(workingDir) {
|
|
|
82819
83645
|
}
|
|
82820
83646
|
const subWorkspaces = await resolveSubWorkspaces(workingDir, pm);
|
|
82821
83647
|
for (const pkg of subWorkspaces) {
|
|
82822
|
-
const wsPath =
|
|
83648
|
+
const wsPath = relative2(workingDir, pkg.dir) || ".";
|
|
82823
83649
|
const pkgSubWorkspace = { type: "npm", path: wsPath, name: pkg.name };
|
|
82824
83650
|
await addSubWorkspaceCommands(commands, pm, pkg, wsPath, pkgSubWorkspace, turboTaskNames);
|
|
82825
83651
|
}
|
|
@@ -82859,14 +83685,14 @@ var init_command_discovery = __esm(() => {
|
|
|
82859
83685
|
});
|
|
82860
83686
|
|
|
82861
83687
|
// src/commands/machine/daemon-start/command-sync-heartbeat.ts
|
|
82862
|
-
import { createHash as
|
|
83688
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
82863
83689
|
var pushCommandsEffect, pushSingleWorkspaceCommandsEffect = (workingDir) => exports_Effect.gen(function* () {
|
|
82864
83690
|
const session2 = yield* DaemonSessionService;
|
|
82865
83691
|
const mutable = yield* DaemonMutableStateService;
|
|
82866
83692
|
const lastPushedGitState = yield* exports_Ref.get(mutable.lastPushedGitState);
|
|
82867
83693
|
const commands = yield* exports_Effect.promise(() => discoverCommands(workingDir));
|
|
82868
83694
|
const stateKey = `commands:${session2.machineId}::${workingDir}`;
|
|
82869
|
-
const commandsHash =
|
|
83695
|
+
const commandsHash = createHash6("md5").update(JSON.stringify(commands)).digest("hex");
|
|
82870
83696
|
if (lastPushedGitState.get(stateKey) === commandsHash) {
|
|
82871
83697
|
return;
|
|
82872
83698
|
}
|
|
@@ -82908,7 +83734,7 @@ var init_command_sync_heartbeat = __esm(() => {
|
|
|
82908
83734
|
});
|
|
82909
83735
|
|
|
82910
83736
|
// src/infrastructure/git/git-state-pipeline.ts
|
|
82911
|
-
import { createHash as
|
|
83737
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
82912
83738
|
|
|
82913
83739
|
class GitStatePipeline {
|
|
82914
83740
|
fields;
|
|
@@ -82940,7 +83766,7 @@ class GitStatePipeline {
|
|
|
82940
83766
|
const raw = values3.get(field.key) ?? field.defaultValue;
|
|
82941
83767
|
hashInput[field.key] = field.toHashable(raw);
|
|
82942
83768
|
}
|
|
82943
|
-
return
|
|
83769
|
+
return createHash7("md5").update(JSON.stringify(hashInput)).digest("hex");
|
|
82944
83770
|
}
|
|
82945
83771
|
toMutationArgs(values3, slim) {
|
|
82946
83772
|
const args2 = {};
|
|
@@ -82988,7 +83814,7 @@ function buildGitStateDeps(session2, lastPushedGitState) {
|
|
|
82988
83814
|
}
|
|
82989
83815
|
async function pushSingleWorkspaceGitStateImpl(ctx, workingDir) {
|
|
82990
83816
|
const stateKey = makeGitStateKey(ctx.machineId, workingDir);
|
|
82991
|
-
const isRepo = await
|
|
83817
|
+
const isRepo = await isGitRepo2(workingDir);
|
|
82992
83818
|
if (!isRepo) {
|
|
82993
83819
|
await pushNotFoundGitState(ctx, workingDir, stateKey);
|
|
82994
83820
|
return;
|
|
@@ -83133,7 +83959,7 @@ var lastFullPushMs, branchField, GIT_STATE_FIELDS, pushSingleWorkspaceGitSummary
|
|
|
83133
83959
|
const mutable = yield* DaemonMutableStateService;
|
|
83134
83960
|
const lastPushedGitState = yield* exports_Ref.get(mutable.lastPushedGitState);
|
|
83135
83961
|
const stateKey = makeGitStateKey(session2.machineId, workingDir);
|
|
83136
|
-
const isRepo = yield* exports_Effect.promise(() =>
|
|
83962
|
+
const isRepo = yield* exports_Effect.promise(() => isGitRepo2(workingDir));
|
|
83137
83963
|
if (!isRepo) {
|
|
83138
83964
|
yield* pushObservedNotRepoEffect(session2, lastPushedGitState, stateKey, workingDir, reason);
|
|
83139
83965
|
return;
|
|
@@ -83270,9 +84096,7 @@ var init_git_heartbeat = __esm(() => {
|
|
|
83270
84096
|
});
|
|
83271
84097
|
|
|
83272
84098
|
// 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";
|
|
84099
|
+
import { gzipSync as gzipSync4 } from "node:zlib";
|
|
83276
84100
|
function extractDiffStatFromShowOutput(content) {
|
|
83277
84101
|
for (const line of content.split(`
|
|
83278
84102
|
`)) {
|
|
@@ -83287,7 +84111,7 @@ async function processFullDiff(deps, req) {
|
|
|
83287
84111
|
if (result.status === "available" || result.status === "truncated") {
|
|
83288
84112
|
const diffStatResult = await getDiffStat(req.workingDir);
|
|
83289
84113
|
const diffStat = diffStatResult.status === "available" ? diffStatResult.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 };
|
|
83290
|
-
const compressed =
|
|
84114
|
+
const compressed = gzipSync4(Buffer.from(result.content));
|
|
83291
84115
|
const diffContentCompressed = compressed.toString("base64");
|
|
83292
84116
|
await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
|
|
83293
84117
|
sessionId: deps.sessionId,
|
|
@@ -83299,7 +84123,7 @@ async function processFullDiff(deps, req) {
|
|
|
83299
84123
|
});
|
|
83300
84124
|
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
84125
|
} else {
|
|
83302
|
-
const emptyCompressed =
|
|
84126
|
+
const emptyCompressed = gzipSync4(Buffer.from("")).toString("base64");
|
|
83303
84127
|
await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
|
|
83304
84128
|
sessionId: deps.sessionId,
|
|
83305
84129
|
machineId: deps.machineId,
|
|
@@ -83349,25 +84173,24 @@ async function processPRAction(deps, req) {
|
|
|
83349
84173
|
if (!prNumber || !action) {
|
|
83350
84174
|
throw new Error("pr_action request missing prNumber or prAction");
|
|
83351
84175
|
}
|
|
83352
|
-
let
|
|
84176
|
+
let ghArgs;
|
|
83353
84177
|
switch (action) {
|
|
83354
84178
|
case "merge_squash":
|
|
83355
|
-
|
|
84179
|
+
ghArgs = ["pr", "merge", String(prNumber), "--squash", "--delete-branch"];
|
|
83356
84180
|
break;
|
|
83357
84181
|
case "merge_no_squash":
|
|
83358
|
-
|
|
84182
|
+
ghArgs = ["pr", "merge", String(prNumber), "--merge"];
|
|
83359
84183
|
break;
|
|
83360
84184
|
case "close":
|
|
83361
|
-
|
|
84185
|
+
ghArgs = ["pr", "close", String(prNumber)];
|
|
83362
84186
|
break;
|
|
83363
84187
|
default:
|
|
83364
84188
|
throw new Error(`Unknown PR action: ${action}`);
|
|
83365
84189
|
}
|
|
83366
|
-
const
|
|
83367
|
-
|
|
83368
|
-
|
|
83369
|
-
|
|
83370
|
-
});
|
|
84190
|
+
const result = await runGh(ghArgs, req.workingDir, { timeout: EXEC_TIMEOUT_MS });
|
|
84191
|
+
if ("error" in result) {
|
|
84192
|
+
throw result.error;
|
|
84193
|
+
}
|
|
83371
84194
|
console.log(`[${formatTimestamp()}] ✅ PR action: ${action} on #${prNumber}${result.stdout ? ` — ${result.stdout.trim()}` : ""}`);
|
|
83372
84195
|
exports_Runtime.runFork(deps.runtime)(pushGitStateEffect.pipe(exports_Effect.provide(exports_Layer.mergeAll(exports_Layer.succeed(DaemonSessionService, deps), DaemonMutableStateServiceLive({
|
|
83373
84196
|
lastPushedGitState: deps.lastPushedGitState,
|
|
@@ -83401,7 +84224,7 @@ async function processCommitDetail(deps, req) {
|
|
|
83401
84224
|
]);
|
|
83402
84225
|
await upsertCommitDetailResult(deps, req, result, metadata);
|
|
83403
84226
|
if (result.status === "available" || result.status === "truncated") {
|
|
83404
|
-
const compressed =
|
|
84227
|
+
const compressed = gzipSync4(Buffer.from(result.content));
|
|
83405
84228
|
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
84229
|
}
|
|
83407
84230
|
}
|
|
@@ -83432,7 +84255,7 @@ async function upsertCommitDetailResult(deps, req, result, metadata) {
|
|
|
83432
84255
|
return;
|
|
83433
84256
|
}
|
|
83434
84257
|
const diffStat = extractDiffStatFromShowOutput(result.content);
|
|
83435
|
-
const compressed =
|
|
84258
|
+
const compressed = gzipSync4(Buffer.from(result.content));
|
|
83436
84259
|
const diffContentCompressed = compressed.toString("base64");
|
|
83437
84260
|
await deps.backend.mutation(api.workspaces.upsertCommitDetailV2, {
|
|
83438
84261
|
...baseArgs,
|
|
@@ -83581,11 +84404,12 @@ var init_git_subscription = __esm(() => {
|
|
|
83581
84404
|
init_git_heartbeat();
|
|
83582
84405
|
init_api3();
|
|
83583
84406
|
init_git_reader();
|
|
84407
|
+
init_run_command();
|
|
83584
84408
|
init_convex_error();
|
|
83585
84409
|
});
|
|
83586
84410
|
|
|
83587
84411
|
// src/commands/machine/daemon-start/commit-detail-sync.ts
|
|
83588
|
-
import { gzipSync as
|
|
84412
|
+
import { gzipSync as gzipSync5 } from "node:zlib";
|
|
83589
84413
|
function upsertCommitDetailArgs(session2, workingDir, sha, metadata, overrides) {
|
|
83590
84414
|
return {
|
|
83591
84415
|
sessionId: session2.sessionId,
|
|
@@ -83614,7 +84438,7 @@ var seenShas, prefetchSingleShaEffect = (session2, workingDir, sha, commits) =>
|
|
|
83614
84438
|
return;
|
|
83615
84439
|
}
|
|
83616
84440
|
const diffStat = extractDiffStatFromShowOutput(result.content);
|
|
83617
|
-
const compressed =
|
|
84441
|
+
const compressed = gzipSync5(Buffer.from(result.content));
|
|
83618
84442
|
const diffContentCompressed = compressed.toString("base64");
|
|
83619
84443
|
yield* exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaces.upsertCommitDetailV2, upsertCommitDetailArgs(session2, workingDir, sha, metadata, {
|
|
83620
84444
|
status: "available",
|
|
@@ -84035,14 +84859,14 @@ var init_sse_event_buffer = __esm(() => {
|
|
|
84035
84859
|
}
|
|
84036
84860
|
_wake() {
|
|
84037
84861
|
if (this._waiter) {
|
|
84038
|
-
const
|
|
84862
|
+
const resolve5 = this._waiter;
|
|
84039
84863
|
this._waiter = null;
|
|
84040
|
-
|
|
84864
|
+
resolve5();
|
|
84041
84865
|
}
|
|
84042
84866
|
}
|
|
84043
84867
|
_waitForData() {
|
|
84044
|
-
return new Promise((
|
|
84045
|
-
this._waiter =
|
|
84868
|
+
return new Promise((resolve5) => {
|
|
84869
|
+
this._waiter = resolve5;
|
|
84046
84870
|
});
|
|
84047
84871
|
}
|
|
84048
84872
|
[Symbol.asyncIterator]() {
|
|
@@ -84097,8 +84921,8 @@ class OpencodeSdkSession {
|
|
|
84097
84921
|
async prompt(input) {
|
|
84098
84922
|
if (this.closed)
|
|
84099
84923
|
throw new Error("Session is closed");
|
|
84100
|
-
const idlePromise = new Promise((
|
|
84101
|
-
this._idleResolve =
|
|
84924
|
+
const idlePromise = new Promise((resolve5) => {
|
|
84925
|
+
this._idleResolve = resolve5;
|
|
84102
84926
|
});
|
|
84103
84927
|
const IDLE_TIMEOUT_MS = 300000;
|
|
84104
84928
|
const timeoutPromise = new Promise((_, reject) => {
|
|
@@ -84182,7 +85006,7 @@ var init_opencode_session = __esm(() => {
|
|
|
84182
85006
|
});
|
|
84183
85007
|
|
|
84184
85008
|
// src/infrastructure/harnesses/opencode-sdk/opencode-harness.ts
|
|
84185
|
-
import { spawn as
|
|
85009
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
84186
85010
|
function harnessEventSessionId(event) {
|
|
84187
85011
|
const p = event.properties;
|
|
84188
85012
|
if (!p)
|
|
@@ -84429,14 +85253,14 @@ class OpencodeSdkHarness {
|
|
|
84429
85253
|
}
|
|
84430
85254
|
this.sessionListeners.clear();
|
|
84431
85255
|
this.childProcess.kill("SIGTERM");
|
|
84432
|
-
await new Promise((
|
|
85256
|
+
await new Promise((resolve5) => {
|
|
84433
85257
|
const timeout3 = setTimeout(() => {
|
|
84434
85258
|
this.childProcess.kill("SIGKILL");
|
|
84435
|
-
|
|
85259
|
+
resolve5();
|
|
84436
85260
|
}, 5000);
|
|
84437
85261
|
this.childProcess.once("exit", () => {
|
|
84438
85262
|
clearTimeout(timeout3);
|
|
84439
|
-
|
|
85263
|
+
resolve5();
|
|
84440
85264
|
});
|
|
84441
85265
|
});
|
|
84442
85266
|
}
|
|
@@ -84456,7 +85280,7 @@ class OpencodeSdkHarness {
|
|
|
84456
85280
|
}
|
|
84457
85281
|
}
|
|
84458
85282
|
var OPENCODE_COMMAND3 = "opencode", SERVE_STARTUP_TIMEOUT_MS2 = 1e4, startOpencodeSdkHarness = async (config3) => {
|
|
84459
|
-
const childProcess =
|
|
85283
|
+
const childProcess = spawn6(OPENCODE_COMMAND3, ["serve", "--print-logs"], {
|
|
84460
85284
|
cwd: config3.workingDir,
|
|
84461
85285
|
stdio: ["pipe", "pipe", "pipe"],
|
|
84462
85286
|
shell: false,
|
|
@@ -85818,10 +86642,10 @@ class BufferedJournalFactory {
|
|
|
85818
86642
|
const waitForInProgress = () => {
|
|
85819
86643
|
if (!flushInProgress)
|
|
85820
86644
|
return Promise.resolve();
|
|
85821
|
-
return new Promise((
|
|
86645
|
+
return new Promise((resolve5) => {
|
|
85822
86646
|
const check3 = () => {
|
|
85823
86647
|
if (!flushInProgress)
|
|
85824
|
-
|
|
86648
|
+
resolve5();
|
|
85825
86649
|
else
|
|
85826
86650
|
setTimeout(check3, 10);
|
|
85827
86651
|
};
|
|
@@ -85939,21 +86763,64 @@ var init_start_subscriptions = __esm(() => {
|
|
|
85939
86763
|
init_convex_session_repository();
|
|
85940
86764
|
});
|
|
85941
86765
|
|
|
86766
|
+
// src/infrastructure/services/workspace/assert-registered-working-dir.ts
|
|
86767
|
+
async function assertRegisteredWorkingDir(session2, workingDir) {
|
|
86768
|
+
const workspaces = await getWorkspacesForMachine({
|
|
86769
|
+
workspaceListStore: session2.workspaceListStore,
|
|
86770
|
+
sessionId: session2.sessionId,
|
|
86771
|
+
machineId: session2.machineId,
|
|
86772
|
+
backend: session2.backend
|
|
86773
|
+
});
|
|
86774
|
+
if (!workspaces.some((w) => w.workingDir === workingDir)) {
|
|
86775
|
+
return { ok: false, error: "Workspace not registered for this machine" };
|
|
86776
|
+
}
|
|
86777
|
+
return { ok: true };
|
|
86778
|
+
}
|
|
86779
|
+
var init_assert_registered_working_dir = __esm(() => {
|
|
86780
|
+
init_workspace_cache();
|
|
86781
|
+
});
|
|
86782
|
+
|
|
85942
86783
|
// src/commands/machine/daemon-start/file-content-fulfillment.ts
|
|
85943
86784
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
85944
|
-
import {
|
|
85945
|
-
|
|
85946
|
-
|
|
85947
|
-
|
|
86785
|
+
import { gzipSync as gzipSync6 } from "node:zlib";
|
|
86786
|
+
function getErrorCause(error) {
|
|
86787
|
+
if (typeof error === "object" && error !== null && "cause" in error && error.cause !== undefined) {
|
|
86788
|
+
return error.cause;
|
|
86789
|
+
}
|
|
86790
|
+
return error;
|
|
86791
|
+
}
|
|
86792
|
+
function isENOENT(error) {
|
|
86793
|
+
const cause3 = getErrorCause(error);
|
|
86794
|
+
return typeof cause3 === "object" && cause3 !== null && "code" in cause3 && cause3.code === "ENOENT";
|
|
86795
|
+
}
|
|
86796
|
+
function isBinaryFile(path6) {
|
|
86797
|
+
const lastDot = path6.lastIndexOf(".");
|
|
85948
86798
|
if (lastDot === -1)
|
|
85949
86799
|
return false;
|
|
85950
|
-
return BINARY_EXTENSIONS.has(
|
|
86800
|
+
return BINARY_EXTENSIONS.has(path6.slice(lastDot).toLowerCase());
|
|
86801
|
+
}
|
|
86802
|
+
function gzipPlainText(text) {
|
|
86803
|
+
return gzipSync6(Buffer.from(text)).toString("base64");
|
|
86804
|
+
}
|
|
86805
|
+
function fulfillGzippedContentEffect(session2, workingDir, filePath, plainText, truncated) {
|
|
86806
|
+
return exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
86807
|
+
sessionId: session2.sessionId,
|
|
86808
|
+
machineId: session2.machineId,
|
|
86809
|
+
workingDir,
|
|
86810
|
+
filePath,
|
|
86811
|
+
data: { compression: "gzip", content: gzipPlainText(plainText) },
|
|
86812
|
+
encoding: "utf8",
|
|
86813
|
+
truncated
|
|
86814
|
+
})), () => exports_Effect.void);
|
|
85951
86815
|
}
|
|
85952
86816
|
var MAX_CONTENT_BYTES, BINARY_EXTENSIONS, fulfillFileContentRequestsEffect;
|
|
85953
86817
|
var init_file_content_fulfillment = __esm(() => {
|
|
85954
86818
|
init_esm();
|
|
85955
86819
|
init_daemon_services();
|
|
85956
86820
|
init_api3();
|
|
86821
|
+
init_assert_registered_working_dir();
|
|
86822
|
+
init_workspace_path_security();
|
|
86823
|
+
init_workspace_visibility_policy();
|
|
85957
86824
|
MAX_CONTENT_BYTES = 500 * 1024;
|
|
85958
86825
|
BINARY_EXTENSIONS = new Set([
|
|
85959
86826
|
".png",
|
|
@@ -86007,40 +86874,55 @@ var init_file_content_fulfillment = __esm(() => {
|
|
|
86007
86874
|
for (const request2 of requests) {
|
|
86008
86875
|
const startTime = Date.now();
|
|
86009
86876
|
const { workingDir, filePath } = request2;
|
|
86010
|
-
|
|
86011
|
-
|
|
86877
|
+
const registered = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => assertRegisteredWorkingDir(session2, workingDir)), () => exports_Effect.succeed({ ok: false, error: "Workspace check failed" }));
|
|
86878
|
+
if (!registered.ok) {
|
|
86879
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Rejected unregistered workspace: ${workingDir} (${registered.error})`);
|
|
86880
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[Error: workspace not registered]", false);
|
|
86012
86881
|
continue;
|
|
86013
86882
|
}
|
|
86014
|
-
const
|
|
86015
|
-
if (!
|
|
86016
|
-
console.warn(`[${formatTimestamp()}] ⚠️
|
|
86883
|
+
const resolved = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => resolvePathWithinWorkspace(workingDir, filePath)), () => exports_Effect.succeed({ ok: false, error: "Invalid file path" }));
|
|
86884
|
+
if (!resolved.ok) {
|
|
86885
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Rejected file path: ${filePath} (${resolved.error})`);
|
|
86886
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[Error reading file]", false);
|
|
86017
86887
|
continue;
|
|
86018
86888
|
}
|
|
86889
|
+
const absolutePath = resolved.absolutePath;
|
|
86019
86890
|
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);
|
|
86891
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[Binary file]", false);
|
|
86030
86892
|
const elapsed4 = Date.now() - startTime;
|
|
86031
86893
|
console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File content synced to Convex: ${filePath} [binary] (${elapsed4}ms)`);
|
|
86032
86894
|
continue;
|
|
86033
86895
|
}
|
|
86034
|
-
|
|
86896
|
+
if (!isPathContentReadable(filePath)) {
|
|
86897
|
+
yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[File blocked: cannot open sensitive path in remote explorer]", false);
|
|
86898
|
+
const elapsed4 = Date.now() - startTime;
|
|
86899
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File content blocked: ${filePath} [secret] (${elapsed4}ms)`);
|
|
86900
|
+
continue;
|
|
86901
|
+
}
|
|
86902
|
+
const readOutcome = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => readFile9(absolutePath)).pipe(exports_Effect.map((buffer) => {
|
|
86035
86903
|
if (buffer.length > MAX_CONTENT_BYTES) {
|
|
86036
86904
|
return {
|
|
86905
|
+
kind: "ok",
|
|
86037
86906
|
content: buffer.subarray(0, MAX_CONTENT_BYTES).toString("utf8"),
|
|
86038
86907
|
truncated: true
|
|
86039
86908
|
};
|
|
86040
86909
|
}
|
|
86041
|
-
return {
|
|
86042
|
-
|
|
86043
|
-
|
|
86910
|
+
return {
|
|
86911
|
+
kind: "ok",
|
|
86912
|
+
content: buffer.toString("utf8"),
|
|
86913
|
+
truncated: false
|
|
86914
|
+
};
|
|
86915
|
+
})), (error) => isENOENT(error) ? exports_Effect.succeed({ kind: "missing" }) : exports_Effect.succeed({
|
|
86916
|
+
kind: "error",
|
|
86917
|
+
content: "[Error reading file]",
|
|
86918
|
+
truncated: false
|
|
86919
|
+
}));
|
|
86920
|
+
if (readOutcome.kind === "missing") {
|
|
86921
|
+
console.log(`[${formatTimestamp()}] ⏳ File not on disk yet, deferring content sync: ${filePath}`);
|
|
86922
|
+
continue;
|
|
86923
|
+
}
|
|
86924
|
+
const { content, truncated } = readOutcome.kind === "ok" ? readOutcome : { content: readOutcome.content, truncated: readOutcome.truncated };
|
|
86925
|
+
const compressed = gzipSync6(Buffer.from(content));
|
|
86044
86926
|
const contentCompressed = compressed.toString("base64");
|
|
86045
86927
|
yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
|
|
86046
86928
|
sessionId: session2.sessionId,
|
|
@@ -86094,217 +86976,272 @@ var init_file_content_subscription = __esm(() => {
|
|
|
86094
86976
|
init_convex_error();
|
|
86095
86977
|
});
|
|
86096
86978
|
|
|
86097
|
-
// src/
|
|
86098
|
-
|
|
86099
|
-
|
|
86100
|
-
|
|
86101
|
-
|
|
86102
|
-
|
|
86103
|
-
|
|
86104
|
-
|
|
86105
|
-
|
|
86106
|
-
|
|
86107
|
-
const
|
|
86108
|
-
|
|
86109
|
-
|
|
86110
|
-
|
|
86111
|
-
|
|
86112
|
-
|
|
86979
|
+
// src/commands/machine/daemon-start/file-write-errors.ts
|
|
86980
|
+
function unsupportedFileWriteOperationMessage(operation) {
|
|
86981
|
+
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).";
|
|
86982
|
+
}
|
|
86983
|
+
|
|
86984
|
+
// src/commands/machine/daemon-start/file-write-fulfillment.ts
|
|
86985
|
+
import { access as access5, mkdir as mkdir8, rename as rename3, rm as rm2, writeFile as writeFile7 } from "node:fs/promises";
|
|
86986
|
+
import { dirname as dirname9 } from "node:path";
|
|
86987
|
+
import { gzipSync as gzipSync7 } from "node:zlib";
|
|
86988
|
+
function isTerminalFileWriteError(errorMessage) {
|
|
86989
|
+
const terminalMessages = new Set([
|
|
86990
|
+
"Invalid file path",
|
|
86991
|
+
"Path escapes workspace",
|
|
86992
|
+
"Missing file data",
|
|
86993
|
+
"File content too large",
|
|
86994
|
+
"File already exists",
|
|
86995
|
+
"File does not exist",
|
|
86996
|
+
"Cannot delete workspace root",
|
|
86997
|
+
"Target path already exists",
|
|
86998
|
+
"Target path is required for rename",
|
|
86999
|
+
"Rename target must differ from source path",
|
|
87000
|
+
"Directory already exists",
|
|
87001
|
+
"Workspace not registered for this machine"
|
|
87002
|
+
]);
|
|
87003
|
+
if (errorMessage.startsWith("Unsupported file write operation"))
|
|
87004
|
+
return true;
|
|
87005
|
+
return terminalMessages.has(errorMessage);
|
|
87006
|
+
}
|
|
87007
|
+
function parentDirPath2(filePath) {
|
|
87008
|
+
const idx = filePath.lastIndexOf("/");
|
|
87009
|
+
return idx === -1 ? "" : filePath.slice(0, idx);
|
|
87010
|
+
}
|
|
87011
|
+
async function syncParentDirListingAfterWrite(session2, workingDir, filePath) {
|
|
87012
|
+
const dirPath = parentDirPath2(filePath);
|
|
87013
|
+
const listing = await listDirectory(workingDir, dirPath);
|
|
87014
|
+
const json = JSON.stringify(listing);
|
|
87015
|
+
const dataHash = computeDirListingContentHash(listing);
|
|
87016
|
+
const compressed = gzipSync7(Buffer.from(json)).toString("base64");
|
|
87017
|
+
await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
|
|
87018
|
+
sessionId: session2.sessionId,
|
|
87019
|
+
machineId: session2.machineId,
|
|
87020
|
+
workingDir,
|
|
87021
|
+
dirPath,
|
|
87022
|
+
data: { compression: "gzip", content: compressed },
|
|
87023
|
+
dataHash,
|
|
87024
|
+
scannedAt: listing.scannedAt,
|
|
87025
|
+
truncated: listing.truncated,
|
|
87026
|
+
totalCount: listing.totalCount
|
|
87027
|
+
});
|
|
86113
87028
|
}
|
|
86114
|
-
async function
|
|
86115
|
-
|
|
86116
|
-
|
|
86117
|
-
|
|
86118
|
-
|
|
86119
|
-
|
|
86120
|
-
|
|
86121
|
-
return stdout.trim() === "true";
|
|
86122
|
-
} catch {
|
|
86123
|
-
return false;
|
|
86124
|
-
}
|
|
87029
|
+
async function completeWriteRequest(session2, requestId, result) {
|
|
87030
|
+
await session2.backend.mutation(api.workspaceFiles.completeFileWriteRequest, {
|
|
87031
|
+
sessionId: session2.sessionId,
|
|
87032
|
+
requestId,
|
|
87033
|
+
status: result.status,
|
|
87034
|
+
errorMessage: result.status === "error" ? result.errorMessage : undefined
|
|
87035
|
+
});
|
|
86125
87036
|
}
|
|
86126
|
-
async function
|
|
86127
|
-
|
|
86128
|
-
await walkSubtree(rootDir, "", collected, maxEntries, maxSubtreeBytes);
|
|
86129
|
-
return collected;
|
|
87037
|
+
async function fileExistsAt(absolutePath) {
|
|
87038
|
+
return access5(absolutePath).then(() => true).catch(() => false);
|
|
86130
87039
|
}
|
|
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;
|
|
87040
|
+
function decodeWritePayload(request2) {
|
|
87041
|
+
if (!request2.data) {
|
|
87042
|
+
return { ok: false, errorMessage: "Missing file data" };
|
|
86140
87043
|
}
|
|
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
|
-
}
|
|
87044
|
+
return gunzipBase64Payload(request2.data.content, MAX_CONTENT_BYTES2);
|
|
87045
|
+
}
|
|
87046
|
+
async function validateWriteOperation(operation, absolutePath) {
|
|
87047
|
+
const exists3 = await fileExistsAt(absolutePath);
|
|
87048
|
+
if (operation === "create" && exists3) {
|
|
87049
|
+
return { ok: false, errorMessage: "File already exists" };
|
|
86170
87050
|
}
|
|
86171
|
-
|
|
86172
|
-
|
|
86173
|
-
break;
|
|
86174
|
-
collected.push(p);
|
|
87051
|
+
if (operation === "update" && !exists3) {
|
|
87052
|
+
return { ok: false, errorMessage: "File does not exist" };
|
|
86175
87053
|
}
|
|
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 [];
|
|
87054
|
+
if (operation === "delete" && !exists3) {
|
|
87055
|
+
return { ok: false, errorMessage: "File does not exist" };
|
|
86202
87056
|
}
|
|
87057
|
+
return { ok: true };
|
|
86203
87058
|
}
|
|
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));
|
|
87059
|
+
async function writePayloadToDisk(absolutePath, operation, content) {
|
|
87060
|
+
if (operation === "create") {
|
|
87061
|
+
await mkdir8(dirname9(absolutePath), { recursive: true });
|
|
87062
|
+
}
|
|
87063
|
+
await writeFile7(absolutePath, content);
|
|
86214
87064
|
}
|
|
86215
|
-
function
|
|
86216
|
-
const
|
|
86217
|
-
|
|
86218
|
-
|
|
86219
|
-
|
|
86220
|
-
|
|
86221
|
-
|
|
87065
|
+
async function fulfillOneFileWriteRequest(session2, request2) {
|
|
87066
|
+
const startTime = Date.now();
|
|
87067
|
+
const { workingDir, filePath, operation } = request2;
|
|
87068
|
+
const registered = await assertRegisteredWorkingDir(session2, workingDir);
|
|
87069
|
+
if (!registered.ok) {
|
|
87070
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87071
|
+
status: "error",
|
|
87072
|
+
errorMessage: registered.error
|
|
87073
|
+
});
|
|
87074
|
+
return;
|
|
86222
87075
|
}
|
|
86223
|
-
const
|
|
86224
|
-
|
|
86225
|
-
|
|
86226
|
-
|
|
86227
|
-
|
|
86228
|
-
|
|
87076
|
+
const resolved = await resolvePathWithinWorkspace(workingDir, filePath);
|
|
87077
|
+
if (!resolved.ok) {
|
|
87078
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87079
|
+
status: "error",
|
|
87080
|
+
errorMessage: resolved.error
|
|
87081
|
+
});
|
|
87082
|
+
return;
|
|
86229
87083
|
}
|
|
86230
|
-
|
|
86231
|
-
|
|
86232
|
-
|
|
86233
|
-
|
|
86234
|
-
|
|
87084
|
+
try {
|
|
87085
|
+
if (operation === "rename") {
|
|
87086
|
+
if (!request2.targetFilePath) {
|
|
87087
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87088
|
+
status: "error",
|
|
87089
|
+
errorMessage: "Target path is required for rename"
|
|
87090
|
+
});
|
|
87091
|
+
return;
|
|
87092
|
+
}
|
|
87093
|
+
if (request2.targetFilePath === filePath) {
|
|
87094
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87095
|
+
status: "error",
|
|
87096
|
+
errorMessage: "Rename target must differ from source path"
|
|
87097
|
+
});
|
|
87098
|
+
return;
|
|
87099
|
+
}
|
|
87100
|
+
const targetResolved = await resolvePathWithinWorkspace(workingDir, request2.targetFilePath);
|
|
87101
|
+
if (!targetResolved.ok) {
|
|
87102
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87103
|
+
status: "error",
|
|
87104
|
+
errorMessage: targetResolved.error
|
|
87105
|
+
});
|
|
87106
|
+
return;
|
|
87107
|
+
}
|
|
87108
|
+
const sourceExists = await fileExistsAt(resolved.absolutePath);
|
|
87109
|
+
if (!sourceExists) {
|
|
87110
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87111
|
+
status: "error",
|
|
87112
|
+
errorMessage: "File does not exist"
|
|
87113
|
+
});
|
|
87114
|
+
return;
|
|
87115
|
+
}
|
|
87116
|
+
const targetExists = await fileExistsAt(targetResolved.absolutePath);
|
|
87117
|
+
if (targetExists) {
|
|
87118
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87119
|
+
status: "error",
|
|
87120
|
+
errorMessage: "Target path already exists"
|
|
87121
|
+
});
|
|
87122
|
+
return;
|
|
87123
|
+
}
|
|
87124
|
+
await mkdir8(dirname9(targetResolved.absolutePath), { recursive: true });
|
|
87125
|
+
await rename3(resolved.absolutePath, targetResolved.absolutePath);
|
|
87126
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87127
|
+
if (parentDirPath2(filePath) !== parentDirPath2(request2.targetFilePath)) {
|
|
87128
|
+
await syncParentDirListingAfterWrite(session2, workingDir, request2.targetFilePath);
|
|
87129
|
+
}
|
|
87130
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87131
|
+
const elapsed4 = Date.now() - startTime;
|
|
87132
|
+
console.log(`[${formatTimestamp()}] ✏️ File rename fulfilled: ${filePath} → ${request2.targetFilePath} (${elapsed4}ms)`);
|
|
87133
|
+
return;
|
|
87134
|
+
}
|
|
87135
|
+
if (operation === "mkdir") {
|
|
87136
|
+
const exists3 = await fileExistsAt(resolved.absolutePath);
|
|
87137
|
+
if (exists3) {
|
|
87138
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87139
|
+
status: "error",
|
|
87140
|
+
errorMessage: "Directory already exists"
|
|
87141
|
+
});
|
|
87142
|
+
return;
|
|
87143
|
+
}
|
|
87144
|
+
await mkdir8(resolved.absolutePath, { recursive: true });
|
|
87145
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87146
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87147
|
+
const elapsed4 = Date.now() - startTime;
|
|
87148
|
+
console.log(`[${formatTimestamp()}] ✏️ Directory mkdir fulfilled: ${filePath} (${elapsed4}ms)`);
|
|
87149
|
+
return;
|
|
87150
|
+
}
|
|
87151
|
+
if (operation === "delete") {
|
|
87152
|
+
if (filePath === "") {
|
|
87153
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87154
|
+
status: "error",
|
|
87155
|
+
errorMessage: "Cannot delete workspace root"
|
|
87156
|
+
});
|
|
87157
|
+
return;
|
|
87158
|
+
}
|
|
87159
|
+
const operationCheck2 = await validateWriteOperation(operation, resolved.absolutePath);
|
|
87160
|
+
if (!operationCheck2.ok) {
|
|
87161
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87162
|
+
status: "error",
|
|
87163
|
+
errorMessage: operationCheck2.errorMessage
|
|
87164
|
+
});
|
|
87165
|
+
return;
|
|
87166
|
+
}
|
|
87167
|
+
await rm2(resolved.absolutePath, { recursive: true, force: false });
|
|
87168
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87169
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87170
|
+
const elapsed4 = Date.now() - startTime;
|
|
87171
|
+
console.log(`[${formatTimestamp()}] ✏️ File delete fulfilled: ${filePath} (${elapsed4}ms)`);
|
|
87172
|
+
return;
|
|
87173
|
+
}
|
|
87174
|
+
if (operation !== "create" && operation !== "update") {
|
|
87175
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87176
|
+
status: "error",
|
|
87177
|
+
errorMessage: unsupportedFileWriteOperationMessage(operation)
|
|
87178
|
+
});
|
|
87179
|
+
return;
|
|
87180
|
+
}
|
|
87181
|
+
const payload = decodeWritePayload(request2);
|
|
87182
|
+
if (!payload.ok) {
|
|
87183
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87184
|
+
status: "error",
|
|
87185
|
+
errorMessage: payload.errorMessage
|
|
87186
|
+
});
|
|
87187
|
+
return;
|
|
87188
|
+
}
|
|
87189
|
+
const operationCheck = await validateWriteOperation(operation, resolved.absolutePath);
|
|
87190
|
+
if (!operationCheck.ok) {
|
|
87191
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87192
|
+
status: "error",
|
|
87193
|
+
errorMessage: operationCheck.errorMessage
|
|
87194
|
+
});
|
|
87195
|
+
return;
|
|
87196
|
+
}
|
|
87197
|
+
await writePayloadToDisk(resolved.absolutePath, operation, payload.content);
|
|
87198
|
+
await syncParentDirListingAfterWrite(session2, workingDir, filePath);
|
|
87199
|
+
await completeWriteRequest(session2, request2._id, { status: "done" });
|
|
87200
|
+
const elapsed3 = Date.now() - startTime;
|
|
87201
|
+
console.log(`[${formatTimestamp()}] ✏️ File write fulfilled: ${filePath} (${operation}, ${(payload.content.length / 1024).toFixed(1)}KB, ${elapsed3}ms)`);
|
|
87202
|
+
} catch (err) {
|
|
87203
|
+
const message = err instanceof Error ? err.message : "Write failed";
|
|
87204
|
+
if (isTerminalFileWriteError(message)) {
|
|
87205
|
+
await completeWriteRequest(session2, request2._id, {
|
|
87206
|
+
status: "error",
|
|
87207
|
+
errorMessage: message
|
|
87208
|
+
});
|
|
87209
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write failed for ${filePath}: ${message}`);
|
|
87210
|
+
return;
|
|
87211
|
+
}
|
|
87212
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write transient failure for ${filePath}: ${message} (will retry)`);
|
|
86235
87213
|
}
|
|
86236
|
-
return entries2;
|
|
86237
87214
|
}
|
|
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
|
-
];
|
|
87215
|
+
var MAX_CONTENT_BYTES2, fulfillFileWriteRequestsEffect;
|
|
87216
|
+
var init_file_write_fulfillment = __esm(() => {
|
|
87217
|
+
init_esm();
|
|
87218
|
+
init_daemon_services();
|
|
87219
|
+
init_api3();
|
|
87220
|
+
init_assert_registered_working_dir();
|
|
87221
|
+
init_dir_listing_content_hash();
|
|
87222
|
+
init_dir_listing_scanner();
|
|
87223
|
+
init_workspace_path_security();
|
|
87224
|
+
MAX_CONTENT_BYTES2 = 512 * 1024;
|
|
87225
|
+
fulfillFileWriteRequestsEffect = exports_Effect.gen(function* () {
|
|
87226
|
+
const session2 = yield* DaemonSessionService;
|
|
87227
|
+
const requests = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.query(api.workspaceFiles.getPendingFileWriteRequests, {
|
|
87228
|
+
sessionId: session2.sessionId,
|
|
87229
|
+
machineId: session2.machineId
|
|
87230
|
+
})), () => exports_Effect.succeed([]));
|
|
87231
|
+
if (requests.length === 0)
|
|
87232
|
+
return;
|
|
87233
|
+
console.log(`[${formatTimestamp()}] ✏️ Received ${requests.length} pending file write request(s): ${requests.map((r) => r.filePath).join(", ")}`);
|
|
87234
|
+
for (const request2 of requests) {
|
|
87235
|
+
yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => fulfillOneFileWriteRequest(session2, request2)), () => exports_Effect.void);
|
|
87236
|
+
}
|
|
87237
|
+
});
|
|
86270
87238
|
});
|
|
86271
87239
|
|
|
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* () {
|
|
87240
|
+
// src/commands/machine/daemon-start/file-write-subscription.ts
|
|
87241
|
+
var startFileWriteSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
86305
87242
|
const session2 = yield* DaemonSessionService;
|
|
86306
87243
|
let processing = false;
|
|
86307
|
-
const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.
|
|
87244
|
+
const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.getPendingFileWriteRequests, {
|
|
86308
87245
|
sessionId: session2.sessionId,
|
|
86309
87246
|
machineId: session2.machineId
|
|
86310
87247
|
}, (requests) => {
|
|
@@ -86313,27 +87250,27 @@ var fulfillFileTreeRequestsEffect = (session2, requests) => exports_Effect.gen(f
|
|
|
86313
87250
|
if (processing)
|
|
86314
87251
|
return;
|
|
86315
87252
|
processing = true;
|
|
86316
|
-
exports_Effect.runPromise(
|
|
86317
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File
|
|
87253
|
+
exports_Effect.runPromise(fulfillFileWriteRequestsEffect.pipe(exports_Effect.provideService(DaemonSessionService, session2))).catch((err) => {
|
|
87254
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write subscription processing failed: ${getErrorMessage(err)}`);
|
|
86318
87255
|
}).finally(() => {
|
|
86319
87256
|
processing = false;
|
|
86320
87257
|
});
|
|
86321
87258
|
}, (err) => {
|
|
86322
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File
|
|
87259
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File write subscription error: ${getErrorMessage(err)}`);
|
|
86323
87260
|
});
|
|
86324
|
-
console.log(`[${formatTimestamp()}]
|
|
87261
|
+
console.log(`[${formatTimestamp()}] ✏️ File write subscription started (reactive)`);
|
|
86325
87262
|
return {
|
|
86326
87263
|
stop: () => {
|
|
86327
87264
|
unsubscribe();
|
|
86328
|
-
console.log(`[${formatTimestamp()}]
|
|
87265
|
+
console.log(`[${formatTimestamp()}] ✏️ File write subscription stopped`);
|
|
86329
87266
|
}
|
|
86330
87267
|
};
|
|
86331
87268
|
});
|
|
86332
|
-
var
|
|
87269
|
+
var init_file_write_subscription = __esm(() => {
|
|
86333
87270
|
init_esm();
|
|
86334
87271
|
init_daemon_services();
|
|
87272
|
+
init_file_write_fulfillment();
|
|
86335
87273
|
init_api3();
|
|
86336
|
-
init_file_tree_scanner();
|
|
86337
87274
|
init_convex_error();
|
|
86338
87275
|
});
|
|
86339
87276
|
|
|
@@ -88805,11 +89742,11 @@ class AgentProcessManager {
|
|
|
88805
89742
|
const initPrompt = await this.fetchInitPromptResult(opts, slot);
|
|
88806
89743
|
if (!initPrompt.ok)
|
|
88807
89744
|
return initPrompt.result;
|
|
88808
|
-
const
|
|
88809
|
-
if (!
|
|
88810
|
-
return
|
|
88811
|
-
await this.finalizeRunningSlot(key, slot, opts,
|
|
88812
|
-
return { success: true, pid:
|
|
89745
|
+
const spawn7 = await this.spawnAgentForEnsureRunning(key, slot, opts, initPrompt, wantResume);
|
|
89746
|
+
if (!spawn7.ok)
|
|
89747
|
+
return spawn7.result;
|
|
89748
|
+
await this.finalizeRunningSlot(key, slot, opts, spawn7.spawnResult, wantResume);
|
|
89749
|
+
return { success: true, pid: spawn7.spawnResult.pid };
|
|
88813
89750
|
} catch (e) {
|
|
88814
89751
|
this.resetSlotIdle(slot);
|
|
88815
89752
|
return { success: false, error: `Unexpected error: ${e.message}` };
|
|
@@ -90016,10 +90953,10 @@ function mergeDefs(...defs) {
|
|
|
90016
90953
|
function cloneDef(schema) {
|
|
90017
90954
|
return mergeDefs(schema._zod.def);
|
|
90018
90955
|
}
|
|
90019
|
-
function getElementAtPath(obj,
|
|
90020
|
-
if (!
|
|
90956
|
+
function getElementAtPath(obj, path6) {
|
|
90957
|
+
if (!path6)
|
|
90021
90958
|
return obj;
|
|
90022
|
-
return
|
|
90959
|
+
return path6.reduce((acc, key) => acc?.[key], obj);
|
|
90023
90960
|
}
|
|
90024
90961
|
function promiseAllObject(promisesObj) {
|
|
90025
90962
|
const keys3 = Object.keys(promisesObj);
|
|
@@ -90347,11 +91284,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
90347
91284
|
}
|
|
90348
91285
|
return false;
|
|
90349
91286
|
}
|
|
90350
|
-
function prefixIssues(
|
|
91287
|
+
function prefixIssues(path6, issues) {
|
|
90351
91288
|
return issues.map((iss) => {
|
|
90352
91289
|
var _a3;
|
|
90353
91290
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
90354
|
-
iss.path.unshift(
|
|
91291
|
+
iss.path.unshift(path6);
|
|
90355
91292
|
return iss;
|
|
90356
91293
|
});
|
|
90357
91294
|
}
|
|
@@ -90564,16 +91501,16 @@ function flattenError(error, mapper = (issue2) => issue2.message) {
|
|
|
90564
91501
|
}
|
|
90565
91502
|
function formatError2(error, mapper = (issue2) => issue2.message) {
|
|
90566
91503
|
const fieldErrors = { _errors: [] };
|
|
90567
|
-
const processError = (error2,
|
|
91504
|
+
const processError = (error2, path6 = []) => {
|
|
90568
91505
|
for (const issue2 of error2.issues) {
|
|
90569
91506
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
90570
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
91507
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
90571
91508
|
} else if (issue2.code === "invalid_key") {
|
|
90572
|
-
processError({ issues: issue2.issues }, [...
|
|
91509
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90573
91510
|
} else if (issue2.code === "invalid_element") {
|
|
90574
|
-
processError({ issues: issue2.issues }, [...
|
|
91511
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90575
91512
|
} else {
|
|
90576
|
-
const fullpath = [...
|
|
91513
|
+
const fullpath = [...path6, ...issue2.path];
|
|
90577
91514
|
if (fullpath.length === 0) {
|
|
90578
91515
|
fieldErrors._errors.push(mapper(issue2));
|
|
90579
91516
|
} else {
|
|
@@ -90600,17 +91537,17 @@ function formatError2(error, mapper = (issue2) => issue2.message) {
|
|
|
90600
91537
|
}
|
|
90601
91538
|
function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
90602
91539
|
const result = { errors: [] };
|
|
90603
|
-
const processError = (error2,
|
|
91540
|
+
const processError = (error2, path6 = []) => {
|
|
90604
91541
|
var _a3, _b2;
|
|
90605
91542
|
for (const issue2 of error2.issues) {
|
|
90606
91543
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
90607
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
91544
|
+
issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
|
|
90608
91545
|
} else if (issue2.code === "invalid_key") {
|
|
90609
|
-
processError({ issues: issue2.issues }, [...
|
|
91546
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90610
91547
|
} else if (issue2.code === "invalid_element") {
|
|
90611
|
-
processError({ issues: issue2.issues }, [...
|
|
91548
|
+
processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
|
|
90612
91549
|
} else {
|
|
90613
|
-
const fullpath = [...
|
|
91550
|
+
const fullpath = [...path6, ...issue2.path];
|
|
90614
91551
|
if (fullpath.length === 0) {
|
|
90615
91552
|
result.errors.push(mapper(issue2));
|
|
90616
91553
|
continue;
|
|
@@ -90642,8 +91579,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
90642
91579
|
}
|
|
90643
91580
|
function toDotPath(_path) {
|
|
90644
91581
|
const segs = [];
|
|
90645
|
-
const
|
|
90646
|
-
for (const seg of
|
|
91582
|
+
const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
91583
|
+
for (const seg of path6) {
|
|
90647
91584
|
if (typeof seg === "number")
|
|
90648
91585
|
segs.push(`[${seg}]`);
|
|
90649
91586
|
else if (typeof seg === "symbol")
|
|
@@ -103646,13 +104583,13 @@ function resolveRef(ref, ctx) {
|
|
|
103646
104583
|
if (!ref.startsWith("#")) {
|
|
103647
104584
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
103648
104585
|
}
|
|
103649
|
-
const
|
|
103650
|
-
if (
|
|
104586
|
+
const path6 = ref.slice(1).split("/").filter(Boolean);
|
|
104587
|
+
if (path6.length === 0) {
|
|
103651
104588
|
return ctx.rootSchema;
|
|
103652
104589
|
}
|
|
103653
104590
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
103654
|
-
if (
|
|
103655
|
-
const key =
|
|
104591
|
+
if (path6[0] === defsKey) {
|
|
104592
|
+
const key = path6[1];
|
|
103656
104593
|
if (!key || !ctx.defs[key]) {
|
|
103657
104594
|
throw new Error(`Reference not found: ${ref}`);
|
|
103658
104595
|
}
|
|
@@ -105253,7 +106190,7 @@ async function reviveNativeTasks(tasks, localHealth, now, cooldown, runtime4, ef
|
|
|
105253
106190
|
runNativeReviveEffect(full, runtime4, effectContext2, agentMgr);
|
|
105254
106191
|
}
|
|
105255
106192
|
}
|
|
105256
|
-
async function processTasksUpdate(tasks, runtime4, effectContext2, cooldown, agentMgr, sessionDeps, machineId,
|
|
106193
|
+
async function processTasksUpdate(tasks, runtime4, effectContext2, cooldown, agentMgr, sessionDeps, machineId, _pass) {
|
|
105257
106194
|
if (tasks.length === 0)
|
|
105258
106195
|
return;
|
|
105259
106196
|
const now = Date.now();
|
|
@@ -105270,9 +106207,7 @@ async function processTasksUpdate(tasks, runtime4, effectContext2, cooldown, age
|
|
|
105270
106207
|
sessionDeps,
|
|
105271
106208
|
machineId
|
|
105272
106209
|
});
|
|
105273
|
-
|
|
105274
|
-
await nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
|
|
105275
|
-
}
|
|
106210
|
+
await nudgeStuckTasks(tasks, now, cooldown, runtime4, effectContext2, agentMgr, sessionDeps, machineId);
|
|
105276
106211
|
}
|
|
105277
106212
|
var startTaskMonitorEffect = (wsClient2) => exports_Effect.gen(function* () {
|
|
105278
106213
|
const session2 = yield* DaemonSessionService;
|
|
@@ -105589,6 +106524,8 @@ var init_command_loop = __esm(() => {
|
|
|
105589
106524
|
init_featureFlags();
|
|
105590
106525
|
init_reliability();
|
|
105591
106526
|
init_esm();
|
|
106527
|
+
init_dir_listing_subscription();
|
|
106528
|
+
init_dir_listing_watch_subscription();
|
|
105592
106529
|
init_api3();
|
|
105593
106530
|
init_on_request_start_agent();
|
|
105594
106531
|
init_on_request_stop_agent();
|
|
@@ -105602,7 +106539,7 @@ var init_command_loop = __esm(() => {
|
|
|
105602
106539
|
init_daemon_services();
|
|
105603
106540
|
init_start_subscriptions();
|
|
105604
106541
|
init_file_content_subscription();
|
|
105605
|
-
|
|
106542
|
+
init_file_write_subscription();
|
|
105606
106543
|
init_git_heartbeat();
|
|
105607
106544
|
init_git_subscription();
|
|
105608
106545
|
init_command_runner();
|
|
@@ -105648,7 +106585,9 @@ var init_command_loop = __esm(() => {
|
|
|
105648
106585
|
heartbeatTimer.unref();
|
|
105649
106586
|
let gitSubscriptionHandle = null;
|
|
105650
106587
|
let fileContentSubscriptionHandle = null;
|
|
105651
|
-
let
|
|
106588
|
+
let fileWriteSubscriptionHandle = null;
|
|
106589
|
+
let dirListingSubscriptionHandle = null;
|
|
106590
|
+
let dirListingWatchSubscriptionHandle = null;
|
|
105652
106591
|
let workspaceListSubscriptionHandle = null;
|
|
105653
106592
|
let observedSyncSubscriptionHandle = null;
|
|
105654
106593
|
let logObserverSubscriptionHandle = null;
|
|
@@ -105716,7 +106655,9 @@ var init_command_loop = __esm(() => {
|
|
|
105716
106655
|
const stopSubscriptions = () => {
|
|
105717
106656
|
gitSubscriptionHandle?.stop();
|
|
105718
106657
|
fileContentSubscriptionHandle?.stop();
|
|
105719
|
-
|
|
106658
|
+
fileWriteSubscriptionHandle?.stop();
|
|
106659
|
+
dirListingSubscriptionHandle?.stop();
|
|
106660
|
+
dirListingWatchSubscriptionHandle?.stop();
|
|
105720
106661
|
workspaceListSubscriptionHandle?.stop();
|
|
105721
106662
|
observedSyncSubscriptionHandle?.stop();
|
|
105722
106663
|
taskMonitorHandle?.stop();
|
|
@@ -105760,7 +106701,9 @@ var init_command_loop = __esm(() => {
|
|
|
105760
106701
|
const wsClient2 = yield* exports_Effect.promise(() => getConvexWsClient());
|
|
105761
106702
|
gitSubscriptionHandle = yield* startGitRequestSubscriptionEffect(wsClient2);
|
|
105762
106703
|
fileContentSubscriptionHandle = yield* startFileContentSubscriptionEffect(wsClient2);
|
|
105763
|
-
|
|
106704
|
+
fileWriteSubscriptionHandle = yield* startFileWriteSubscriptionEffect(wsClient2);
|
|
106705
|
+
dirListingSubscriptionHandle = yield* startDirListingSubscriptionEffect(wsClient2);
|
|
106706
|
+
dirListingWatchSubscriptionHandle = yield* startDirListingWatchSubscriptionEffect(wsClient2);
|
|
105764
106707
|
workspaceListSubscriptionHandle = yield* startWorkspaceListSubscriptionEffect(wsClient2);
|
|
105765
106708
|
if (observedSyncEnabled) {
|
|
105766
106709
|
observedSyncSubscriptionHandle = yield* startObservedSyncSubscriptionEffect(wsClient2);
|
|
@@ -105962,7 +106905,7 @@ __export(exports_opencode_install, {
|
|
|
105962
106905
|
installTool: () => installTool
|
|
105963
106906
|
});
|
|
105964
106907
|
import * as os2 from "os";
|
|
105965
|
-
import * as
|
|
106908
|
+
import * as path6 from "path";
|
|
105966
106909
|
async function isChatroomInstalledDefault() {
|
|
105967
106910
|
try {
|
|
105968
106911
|
const { execSync: execSync3 } = await import("child_process");
|
|
@@ -106332,9 +107275,9 @@ After logging in, try this command again.\`;
|
|
|
106332
107275
|
const fsService = yield* OpenCodeInstallFsService;
|
|
106333
107276
|
const { checkExisting = true } = options;
|
|
106334
107277
|
const homeDir = os2.homedir();
|
|
106335
|
-
const toolDir =
|
|
106336
|
-
const toolPath =
|
|
106337
|
-
const handoffToolPath =
|
|
107278
|
+
const toolDir = path6.join(homeDir, ".config", "opencode", "tool");
|
|
107279
|
+
const toolPath = path6.join(toolDir, "chatroom.ts");
|
|
107280
|
+
const handoffToolPath = path6.join(toolDir, "chatroom-handoff.ts");
|
|
106338
107281
|
if (checkExisting) {
|
|
106339
107282
|
const existingFiles = [];
|
|
106340
107283
|
const toolExists = yield* fsService.access(toolPath);
|
|
@@ -106889,4 +107832,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
106889
107832
|
});
|
|
106890
107833
|
program2.parse();
|
|
106891
107834
|
|
|
106892
|
-
//# debugId=
|
|
107835
|
+
//# debugId=5B3A6F0DA9D185F964756E2164756E21
|