chatroom-cli 1.23.8 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +253 -146
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -52767,7 +52767,7 @@ async function viewStep(chatroomId, options, deps) {
|
|
|
52767
52767
|
}
|
|
52768
52768
|
if (spec.skills) {
|
|
52769
52769
|
console.log("");
|
|
52770
|
-
console.log("Skills:");
|
|
52770
|
+
console.log("Skills (activate before starting):");
|
|
52771
52771
|
console.log(spec.skills);
|
|
52772
52772
|
}
|
|
52773
52773
|
if (spec.requirements) {
|
|
@@ -54411,6 +54411,45 @@ async function getAllPRs(cwd) {
|
|
|
54411
54411
|
return [];
|
|
54412
54412
|
}
|
|
54413
54413
|
}
|
|
54414
|
+
async function getPRCommits(cwd, prNumber) {
|
|
54415
|
+
const repoSlug = await getOriginRepoSlug(cwd);
|
|
54416
|
+
const repoFlag = repoSlug ? ` --repo ${JSON.stringify(repoSlug)}` : "";
|
|
54417
|
+
const result = await runCommand(`gh pr view ${prNumber} --json commits${repoFlag}`, cwd);
|
|
54418
|
+
if ("error" in result) {
|
|
54419
|
+
return [];
|
|
54420
|
+
}
|
|
54421
|
+
const output = result.stdout.trim();
|
|
54422
|
+
if (!output)
|
|
54423
|
+
return [];
|
|
54424
|
+
try {
|
|
54425
|
+
const parsed = JSON.parse(output);
|
|
54426
|
+
if (typeof parsed !== "object" || parsed === null || !("commits" in parsed))
|
|
54427
|
+
return [];
|
|
54428
|
+
const commits = parsed.commits;
|
|
54429
|
+
if (!Array.isArray(commits))
|
|
54430
|
+
return [];
|
|
54431
|
+
return commits.map((c) => {
|
|
54432
|
+
const commit = c;
|
|
54433
|
+
const oid = typeof commit.oid === "string" ? commit.oid : "";
|
|
54434
|
+
const headline = typeof commit.messageHeadline === "string" ? commit.messageHeadline : "";
|
|
54435
|
+
const date = typeof commit.committedDate === "string" ? commit.committedDate : "";
|
|
54436
|
+
let authorLogin = "";
|
|
54437
|
+
if (Array.isArray(commit.authors) && commit.authors.length > 0) {
|
|
54438
|
+
const first = commit.authors[0];
|
|
54439
|
+
authorLogin = typeof first.login === "string" ? first.login : typeof first.name === "string" ? first.name : "";
|
|
54440
|
+
}
|
|
54441
|
+
return {
|
|
54442
|
+
sha: oid,
|
|
54443
|
+
shortSha: oid.slice(0, 7),
|
|
54444
|
+
message: headline,
|
|
54445
|
+
author: authorLogin,
|
|
54446
|
+
date
|
|
54447
|
+
};
|
|
54448
|
+
});
|
|
54449
|
+
} catch {
|
|
54450
|
+
return [];
|
|
54451
|
+
}
|
|
54452
|
+
}
|
|
54414
54453
|
async function getRemotes(cwd) {
|
|
54415
54454
|
const result = await runGit("remote -v", cwd);
|
|
54416
54455
|
if ("error" in result)
|
|
@@ -54442,6 +54481,43 @@ async function getCommitsAhead(workingDir) {
|
|
|
54442
54481
|
const count = parseInt(result.stdout.trim(), 10);
|
|
54443
54482
|
return Number.isNaN(count) ? 0 : count;
|
|
54444
54483
|
}
|
|
54484
|
+
async function getCommitStatusChecks(cwd, ref) {
|
|
54485
|
+
const repoSlug = await getOriginRepoSlug(cwd);
|
|
54486
|
+
if (!repoSlug)
|
|
54487
|
+
return null;
|
|
54488
|
+
try {
|
|
54489
|
+
const [checkRunsResult, statusResult] = await Promise.all([
|
|
54490
|
+
runCommand(`gh api repos/${repoSlug}/commits/${encodeURIComponent(ref)}/check-runs --jq '{check_runs: [.check_runs[] | {name: .name, status: .status, conclusion: .conclusion}], total_count: .total_count}'`, cwd),
|
|
54491
|
+
runCommand(`gh api repos/${repoSlug}/commits/${encodeURIComponent(ref)}/status --jq '.state'`, cwd)
|
|
54492
|
+
]);
|
|
54493
|
+
if ("error" in checkRunsResult || "error" in statusResult)
|
|
54494
|
+
return null;
|
|
54495
|
+
const checkRunsData = JSON.parse(checkRunsResult.stdout.trim());
|
|
54496
|
+
const combinedState = statusResult.stdout.trim() || "pending";
|
|
54497
|
+
let state = combinedState;
|
|
54498
|
+
if (checkRunsData.total_count > 0) {
|
|
54499
|
+
const conclusions = checkRunsData.check_runs.map((cr) => cr.conclusion);
|
|
54500
|
+
if (conclusions.some((c) => c === "failure" || c === "timed_out")) {
|
|
54501
|
+
state = "failure";
|
|
54502
|
+
} else if (conclusions.every((c) => c === "success" || c === "skipped" || c === "neutral")) {
|
|
54503
|
+
state = "success";
|
|
54504
|
+
} else if (checkRunsData.check_runs.some((cr) => cr.status !== "completed")) {
|
|
54505
|
+
state = "pending";
|
|
54506
|
+
}
|
|
54507
|
+
}
|
|
54508
|
+
return {
|
|
54509
|
+
state,
|
|
54510
|
+
checkRuns: checkRunsData.check_runs.map((cr) => ({
|
|
54511
|
+
name: cr.name,
|
|
54512
|
+
status: cr.status,
|
|
54513
|
+
conclusion: cr.conclusion
|
|
54514
|
+
})),
|
|
54515
|
+
totalCount: checkRunsData.total_count
|
|
54516
|
+
};
|
|
54517
|
+
} catch {
|
|
54518
|
+
return null;
|
|
54519
|
+
}
|
|
54520
|
+
}
|
|
54445
54521
|
var execAsync2;
|
|
54446
54522
|
var init_git_reader = __esm(() => {
|
|
54447
54523
|
execAsync2 = promisify2(exec2);
|
|
@@ -54597,6 +54673,21 @@ async function processPRAction(ctx, req) {
|
|
|
54597
54673
|
console.warn(`[${formatTimestamp()}] ⚠️ Failed to refresh git state after PR action: ${getErrorMessage(err)}`);
|
|
54598
54674
|
});
|
|
54599
54675
|
}
|
|
54676
|
+
async function processPRCommits(ctx, req) {
|
|
54677
|
+
const prNumber = req.prNumber;
|
|
54678
|
+
if (!prNumber) {
|
|
54679
|
+
throw new Error("pr_commits request missing prNumber");
|
|
54680
|
+
}
|
|
54681
|
+
const commits = await getPRCommits(req.workingDir, prNumber);
|
|
54682
|
+
await ctx.deps.backend.mutation(api.workspaces.upsertPRCommits, {
|
|
54683
|
+
sessionId: ctx.sessionId,
|
|
54684
|
+
machineId: ctx.machineId,
|
|
54685
|
+
workingDir: req.workingDir,
|
|
54686
|
+
prNumber,
|
|
54687
|
+
commits
|
|
54688
|
+
});
|
|
54689
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCCB PR commits pushed: ${req.workingDir} (#${prNumber}, ${commits.length} commits)`);
|
|
54690
|
+
}
|
|
54600
54691
|
async function processCommitDetail(ctx, req) {
|
|
54601
54692
|
if (!req.sha) {
|
|
54602
54693
|
throw new Error("commit_detail request missing sha");
|
|
@@ -54694,6 +54785,9 @@ async function processRequests(ctx, requests, processedRequestIds, dedupTtlMs) {
|
|
|
54694
54785
|
case "pr_action":
|
|
54695
54786
|
await processPRAction(ctx, req);
|
|
54696
54787
|
break;
|
|
54788
|
+
case "pr_commits":
|
|
54789
|
+
await processPRCommits(ctx, req);
|
|
54790
|
+
break;
|
|
54697
54791
|
}
|
|
54698
54792
|
await ctx.deps.backend.mutation(api.workspaces.updateRequestStatus, {
|
|
54699
54793
|
sessionId: ctx.sessionId,
|
|
@@ -54784,11 +54878,12 @@ async function pushSingleWorkspaceGitState(ctx, workingDir) {
|
|
|
54784
54878
|
}
|
|
54785
54879
|
const openPRs = await getOpenPRsForBranch(workingDir, branchResult.branch);
|
|
54786
54880
|
const allPRs = await getAllPRs(workingDir);
|
|
54881
|
+
const headCommitStatus = await getCommitStatusChecks(workingDir, branchResult.branch);
|
|
54787
54882
|
const branch = branchResult.branch;
|
|
54788
54883
|
const isDirty2 = dirtyResult;
|
|
54789
54884
|
const diffStat = diffStatResult.status === "available" ? diffStatResult.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 };
|
|
54790
54885
|
const hasMoreCommits = commits.length >= COMMITS_PER_PAGE;
|
|
54791
|
-
const stateHash = createHash3("md5").update(JSON.stringify({ branch, isDirty: isDirty2, diffStat, commitsAhead, shas: commits.map((c) => c.sha), prs: openPRs.map((pr) => pr.number), allPrs: allPRs.map((pr) => `${pr.number}:${pr.state}`), remotes: remotes.map((r) => `${r.name}:${r.url}`) })).digest("hex");
|
|
54886
|
+
const stateHash = createHash3("md5").update(JSON.stringify({ branch, isDirty: isDirty2, diffStat, commitsAhead, shas: commits.map((c) => c.sha), prs: openPRs.map((pr) => pr.number), allPrs: allPRs.map((pr) => `${pr.number}:${pr.state}`), remotes: remotes.map((r) => `${r.name}:${r.url}`), headCommitStatus })).digest("hex");
|
|
54792
54887
|
if (ctx.lastPushedGitState.get(stateKey) === stateHash) {
|
|
54793
54888
|
return;
|
|
54794
54889
|
}
|
|
@@ -54805,7 +54900,8 @@ async function pushSingleWorkspaceGitState(ctx, workingDir) {
|
|
|
54805
54900
|
openPullRequests: openPRs,
|
|
54806
54901
|
allPullRequests: allPRs,
|
|
54807
54902
|
remotes,
|
|
54808
|
-
commitsAhead
|
|
54903
|
+
commitsAhead,
|
|
54904
|
+
headCommitStatus
|
|
54809
54905
|
});
|
|
54810
54906
|
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
54811
54907
|
console.log(`[${formatTimestamp()}] \uD83D\uDD00 Git state pushed: ${workingDir} (${branch}${isDirty2 ? ", dirty" : ", clean"})`);
|
|
@@ -54887,142 +54983,6 @@ var init_git_heartbeat = __esm(() => {
|
|
|
54887
54983
|
init_convex_error();
|
|
54888
54984
|
});
|
|
54889
54985
|
|
|
54890
|
-
// src/infrastructure/services/workspace/file-tree-scanner.ts
|
|
54891
|
-
import { exec as exec4 } from "node:child_process";
|
|
54892
|
-
import { promisify as promisify4 } from "node:util";
|
|
54893
|
-
async function scanFileTree(rootDir, options) {
|
|
54894
|
-
const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
54895
|
-
const scannedAt = Date.now();
|
|
54896
|
-
const filePaths = await getGitFiles(rootDir);
|
|
54897
|
-
const filteredPaths = filePaths.filter((p) => !isExcluded(p));
|
|
54898
|
-
const entries = buildEntries(filteredPaths, rootDir, maxEntries);
|
|
54899
|
-
return {
|
|
54900
|
-
entries,
|
|
54901
|
-
scannedAt,
|
|
54902
|
-
rootDir
|
|
54903
|
-
};
|
|
54904
|
-
}
|
|
54905
|
-
async function getGitFiles(rootDir) {
|
|
54906
|
-
const env2 = {
|
|
54907
|
-
...process.env,
|
|
54908
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
54909
|
-
GIT_PAGER: "cat",
|
|
54910
|
-
NO_COLOR: "1"
|
|
54911
|
-
};
|
|
54912
|
-
try {
|
|
54913
|
-
const tracked = await execAsync3("git ls-files", {
|
|
54914
|
-
cwd: rootDir,
|
|
54915
|
-
env: env2,
|
|
54916
|
-
maxBuffer: 10 * 1024 * 1024
|
|
54917
|
-
});
|
|
54918
|
-
const untracked = await execAsync3("git ls-files --others --exclude-standard", {
|
|
54919
|
-
cwd: rootDir,
|
|
54920
|
-
env: env2,
|
|
54921
|
-
maxBuffer: 10 * 1024 * 1024
|
|
54922
|
-
});
|
|
54923
|
-
const trackedFiles = parseLines(tracked.stdout);
|
|
54924
|
-
const untrackedFiles = parseLines(untracked.stdout);
|
|
54925
|
-
const allFiles = new Set([...trackedFiles, ...untrackedFiles]);
|
|
54926
|
-
return Array.from(allFiles);
|
|
54927
|
-
} catch {
|
|
54928
|
-
return [];
|
|
54929
|
-
}
|
|
54930
|
-
}
|
|
54931
|
-
function parseLines(output) {
|
|
54932
|
-
return output.split(`
|
|
54933
|
-
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
54934
|
-
}
|
|
54935
|
-
function isExcluded(filePath) {
|
|
54936
|
-
const segments = filePath.split("/");
|
|
54937
|
-
return segments.some((segment) => ALWAYS_EXCLUDE.has(segment));
|
|
54938
|
-
}
|
|
54939
|
-
function buildEntries(filePaths, rootDir, maxEntries) {
|
|
54940
|
-
const directories = new Set;
|
|
54941
|
-
for (const filePath of filePaths) {
|
|
54942
|
-
const parts = filePath.split("/");
|
|
54943
|
-
for (let i2 = 1;i2 < parts.length; i2++) {
|
|
54944
|
-
directories.add(parts.slice(0, i2).join("/"));
|
|
54945
|
-
}
|
|
54946
|
-
}
|
|
54947
|
-
const entries = [];
|
|
54948
|
-
const sortedDirs = Array.from(directories).sort();
|
|
54949
|
-
for (const dir of sortedDirs) {
|
|
54950
|
-
if (entries.length >= maxEntries)
|
|
54951
|
-
break;
|
|
54952
|
-
entries.push({ path: dir, type: "directory" });
|
|
54953
|
-
}
|
|
54954
|
-
const sortedFiles = filePaths.slice().sort();
|
|
54955
|
-
for (const file of sortedFiles) {
|
|
54956
|
-
if (entries.length >= maxEntries)
|
|
54957
|
-
break;
|
|
54958
|
-
entries.push({ path: file, type: "file" });
|
|
54959
|
-
}
|
|
54960
|
-
return entries;
|
|
54961
|
-
}
|
|
54962
|
-
var execAsync3, DEFAULT_MAX_ENTRIES = 1e4, ALWAYS_EXCLUDE;
|
|
54963
|
-
var init_file_tree_scanner = __esm(() => {
|
|
54964
|
-
execAsync3 = promisify4(exec4);
|
|
54965
|
-
ALWAYS_EXCLUDE = new Set([
|
|
54966
|
-
"node_modules",
|
|
54967
|
-
".git",
|
|
54968
|
-
"dist",
|
|
54969
|
-
"build",
|
|
54970
|
-
".next",
|
|
54971
|
-
"coverage",
|
|
54972
|
-
"__pycache__",
|
|
54973
|
-
".turbo"
|
|
54974
|
-
]);
|
|
54975
|
-
});
|
|
54976
|
-
|
|
54977
|
-
// src/commands/machine/daemon-start/file-tree-heartbeat.ts
|
|
54978
|
-
import { createHash as createHash4 } from "node:crypto";
|
|
54979
|
-
async function pushFileTree(ctx) {
|
|
54980
|
-
let workspaces;
|
|
54981
|
-
try {
|
|
54982
|
-
workspaces = await ctx.deps.backend.query(api.workspaces.listWorkspacesForMachine, {
|
|
54983
|
-
sessionId: ctx.sessionId,
|
|
54984
|
-
machineId: ctx.machineId
|
|
54985
|
-
});
|
|
54986
|
-
} catch (err) {
|
|
54987
|
-
console.warn(`[${formatTimestamp()}] ⚠️ Failed to query workspaces for file tree sync: ${getErrorMessage(err)}`);
|
|
54988
|
-
return;
|
|
54989
|
-
}
|
|
54990
|
-
const uniqueWorkingDirs = new Set(workspaces.map((ws) => ws.workingDir));
|
|
54991
|
-
if (uniqueWorkingDirs.size === 0)
|
|
54992
|
-
return;
|
|
54993
|
-
for (const workingDir of uniqueWorkingDirs) {
|
|
54994
|
-
try {
|
|
54995
|
-
await pushSingleWorkspaceFileTree(ctx, workingDir);
|
|
54996
|
-
} catch (err) {
|
|
54997
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File tree push failed for ${workingDir}: ${getErrorMessage(err)}`);
|
|
54998
|
-
}
|
|
54999
|
-
}
|
|
55000
|
-
}
|
|
55001
|
-
async function pushSingleWorkspaceFileTree(ctx, workingDir) {
|
|
55002
|
-
const tree = await scanFileTree(workingDir);
|
|
55003
|
-
const treeJson = JSON.stringify(tree);
|
|
55004
|
-
const stateKey = `filetree:${ctx.machineId}::${workingDir}`;
|
|
55005
|
-
const treeHash = createHash4("md5").update(treeJson).digest("hex");
|
|
55006
|
-
if (ctx.lastPushedGitState.get(stateKey) === treeHash) {
|
|
55007
|
-
return;
|
|
55008
|
-
}
|
|
55009
|
-
await ctx.deps.backend.mutation(api.workspaceFiles.syncFileTree, {
|
|
55010
|
-
sessionId: ctx.sessionId,
|
|
55011
|
-
machineId: ctx.machineId,
|
|
55012
|
-
workingDir,
|
|
55013
|
-
treeJson,
|
|
55014
|
-
treeHash,
|
|
55015
|
-
scannedAt: tree.scannedAt
|
|
55016
|
-
});
|
|
55017
|
-
ctx.lastPushedGitState.set(stateKey, treeHash);
|
|
55018
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCC1 File tree pushed: ${workingDir} (${tree.entries.length} entries)`);
|
|
55019
|
-
}
|
|
55020
|
-
var init_file_tree_heartbeat = __esm(() => {
|
|
55021
|
-
init_api3();
|
|
55022
|
-
init_file_tree_scanner();
|
|
55023
|
-
init_convex_error();
|
|
55024
|
-
});
|
|
55025
|
-
|
|
55026
54986
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
55027
54987
|
import { readFile as readFile2, readdir, stat } from "node:fs/promises";
|
|
55028
54988
|
import { join as join8, basename, resolve as resolve3 } from "node:path";
|
|
@@ -55278,7 +55238,7 @@ var init_command_discovery = __esm(() => {
|
|
|
55278
55238
|
});
|
|
55279
55239
|
|
|
55280
55240
|
// src/commands/machine/daemon-start/command-sync-heartbeat.ts
|
|
55281
|
-
import { createHash as
|
|
55241
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
55282
55242
|
async function pushCommands(ctx) {
|
|
55283
55243
|
let workspaces;
|
|
55284
55244
|
try {
|
|
@@ -55304,7 +55264,7 @@ async function pushCommands(ctx) {
|
|
|
55304
55264
|
async function pushSingleWorkspaceCommands(ctx, workingDir) {
|
|
55305
55265
|
const commands = await discoverCommands(workingDir);
|
|
55306
55266
|
const stateKey = `commands:${ctx.machineId}::${workingDir}`;
|
|
55307
|
-
const commandsHash =
|
|
55267
|
+
const commandsHash = createHash4("md5").update(JSON.stringify(commands)).digest("hex");
|
|
55308
55268
|
if (ctx.lastPushedGitState.get(stateKey) === commandsHash) {
|
|
55309
55269
|
return;
|
|
55310
55270
|
}
|
|
@@ -55486,6 +55446,153 @@ var init_file_content_subscription = __esm(() => {
|
|
|
55486
55446
|
init_convex_error();
|
|
55487
55447
|
});
|
|
55488
55448
|
|
|
55449
|
+
// src/infrastructure/services/workspace/file-tree-scanner.ts
|
|
55450
|
+
import { exec as exec4 } from "node:child_process";
|
|
55451
|
+
import { promisify as promisify4 } from "node:util";
|
|
55452
|
+
async function scanFileTree(rootDir, options) {
|
|
55453
|
+
const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
55454
|
+
const scannedAt = Date.now();
|
|
55455
|
+
const filePaths = await getGitFiles(rootDir);
|
|
55456
|
+
const filteredPaths = filePaths.filter((p) => !isExcluded(p));
|
|
55457
|
+
const entries = buildEntries(filteredPaths, rootDir, maxEntries);
|
|
55458
|
+
return {
|
|
55459
|
+
entries,
|
|
55460
|
+
scannedAt,
|
|
55461
|
+
rootDir
|
|
55462
|
+
};
|
|
55463
|
+
}
|
|
55464
|
+
async function getGitFiles(rootDir) {
|
|
55465
|
+
const env2 = {
|
|
55466
|
+
...process.env,
|
|
55467
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
55468
|
+
GIT_PAGER: "cat",
|
|
55469
|
+
NO_COLOR: "1"
|
|
55470
|
+
};
|
|
55471
|
+
try {
|
|
55472
|
+
const tracked = await execAsync3("git ls-files", {
|
|
55473
|
+
cwd: rootDir,
|
|
55474
|
+
env: env2,
|
|
55475
|
+
maxBuffer: 10 * 1024 * 1024
|
|
55476
|
+
});
|
|
55477
|
+
const untracked = await execAsync3("git ls-files --others --exclude-standard", {
|
|
55478
|
+
cwd: rootDir,
|
|
55479
|
+
env: env2,
|
|
55480
|
+
maxBuffer: 10 * 1024 * 1024
|
|
55481
|
+
});
|
|
55482
|
+
const trackedFiles = parseLines(tracked.stdout);
|
|
55483
|
+
const untrackedFiles = parseLines(untracked.stdout);
|
|
55484
|
+
const allFiles = new Set([...trackedFiles, ...untrackedFiles]);
|
|
55485
|
+
return Array.from(allFiles);
|
|
55486
|
+
} catch {
|
|
55487
|
+
return [];
|
|
55488
|
+
}
|
|
55489
|
+
}
|
|
55490
|
+
function parseLines(output) {
|
|
55491
|
+
return output.split(`
|
|
55492
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
55493
|
+
}
|
|
55494
|
+
function isExcluded(filePath) {
|
|
55495
|
+
const segments = filePath.split("/");
|
|
55496
|
+
return segments.some((segment) => ALWAYS_EXCLUDE.has(segment));
|
|
55497
|
+
}
|
|
55498
|
+
function buildEntries(filePaths, rootDir, maxEntries) {
|
|
55499
|
+
const directories = new Set;
|
|
55500
|
+
for (const filePath of filePaths) {
|
|
55501
|
+
const parts = filePath.split("/");
|
|
55502
|
+
for (let i2 = 1;i2 < parts.length; i2++) {
|
|
55503
|
+
directories.add(parts.slice(0, i2).join("/"));
|
|
55504
|
+
}
|
|
55505
|
+
}
|
|
55506
|
+
const entries = [];
|
|
55507
|
+
const sortedDirs = Array.from(directories).sort();
|
|
55508
|
+
for (const dir of sortedDirs) {
|
|
55509
|
+
if (entries.length >= maxEntries)
|
|
55510
|
+
break;
|
|
55511
|
+
entries.push({ path: dir, type: "directory" });
|
|
55512
|
+
}
|
|
55513
|
+
const sortedFiles = filePaths.slice().sort();
|
|
55514
|
+
for (const file of sortedFiles) {
|
|
55515
|
+
if (entries.length >= maxEntries)
|
|
55516
|
+
break;
|
|
55517
|
+
entries.push({ path: file, type: "file" });
|
|
55518
|
+
}
|
|
55519
|
+
return entries;
|
|
55520
|
+
}
|
|
55521
|
+
var execAsync3, DEFAULT_MAX_ENTRIES = 1e4, ALWAYS_EXCLUDE;
|
|
55522
|
+
var init_file_tree_scanner = __esm(() => {
|
|
55523
|
+
execAsync3 = promisify4(exec4);
|
|
55524
|
+
ALWAYS_EXCLUDE = new Set([
|
|
55525
|
+
"node_modules",
|
|
55526
|
+
".git",
|
|
55527
|
+
"dist",
|
|
55528
|
+
"build",
|
|
55529
|
+
".next",
|
|
55530
|
+
"coverage",
|
|
55531
|
+
"__pycache__",
|
|
55532
|
+
".turbo"
|
|
55533
|
+
]);
|
|
55534
|
+
});
|
|
55535
|
+
|
|
55536
|
+
// src/commands/machine/daemon-start/file-tree-subscription.ts
|
|
55537
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
55538
|
+
function startFileTreeSubscription(ctx, wsClient2) {
|
|
55539
|
+
let processing = false;
|
|
55540
|
+
const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.getPendingFileTreeRequests, {
|
|
55541
|
+
sessionId: ctx.sessionId,
|
|
55542
|
+
machineId: ctx.machineId
|
|
55543
|
+
}, (requests) => {
|
|
55544
|
+
if (!requests || requests.length === 0)
|
|
55545
|
+
return;
|
|
55546
|
+
if (processing)
|
|
55547
|
+
return;
|
|
55548
|
+
processing = true;
|
|
55549
|
+
fulfillFileTreeRequests(ctx, requests).catch((err) => {
|
|
55550
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File tree subscription processing failed: ${getErrorMessage(err)}`);
|
|
55551
|
+
}).finally(() => {
|
|
55552
|
+
processing = false;
|
|
55553
|
+
});
|
|
55554
|
+
}, (err) => {
|
|
55555
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File tree subscription error: ${getErrorMessage(err)}`);
|
|
55556
|
+
});
|
|
55557
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree subscription started (reactive)`);
|
|
55558
|
+
return {
|
|
55559
|
+
stop: () => {
|
|
55560
|
+
unsubscribe();
|
|
55561
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree subscription stopped`);
|
|
55562
|
+
}
|
|
55563
|
+
};
|
|
55564
|
+
}
|
|
55565
|
+
async function fulfillFileTreeRequests(ctx, requests) {
|
|
55566
|
+
for (const request of requests) {
|
|
55567
|
+
try {
|
|
55568
|
+
const tree = await scanFileTree(request.workingDir);
|
|
55569
|
+
const treeJson = JSON.stringify(tree);
|
|
55570
|
+
const treeHash = createHash5("md5").update(treeJson).digest("hex");
|
|
55571
|
+
await ctx.deps.backend.mutation(api.workspaceFiles.syncFileTree, {
|
|
55572
|
+
sessionId: ctx.sessionId,
|
|
55573
|
+
machineId: ctx.machineId,
|
|
55574
|
+
workingDir: request.workingDir,
|
|
55575
|
+
treeJson,
|
|
55576
|
+
treeHash,
|
|
55577
|
+
scannedAt: tree.scannedAt
|
|
55578
|
+
});
|
|
55579
|
+
await ctx.deps.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
|
|
55580
|
+
sessionId: ctx.sessionId,
|
|
55581
|
+
machineId: ctx.machineId,
|
|
55582
|
+
workingDir: request.workingDir
|
|
55583
|
+
});
|
|
55584
|
+
console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree fulfilled: ${request.workingDir} (${tree.entries.length} entries)`);
|
|
55585
|
+
} catch (err) {
|
|
55586
|
+
console.warn(`[${formatTimestamp()}] ⚠️ File tree fulfillment failed for ${request.workingDir}: ${getErrorMessage(err)}`);
|
|
55587
|
+
}
|
|
55588
|
+
}
|
|
55589
|
+
}
|
|
55590
|
+
var init_file_tree_subscription = __esm(() => {
|
|
55591
|
+
init_api3();
|
|
55592
|
+
init_file_tree_scanner();
|
|
55593
|
+
init_convex_error();
|
|
55594
|
+
});
|
|
55595
|
+
|
|
55489
55596
|
// src/commands/machine/daemon-start/handlers/ping.ts
|
|
55490
55597
|
function handlePing() {
|
|
55491
55598
|
console.log(` ↪ Responding: pong`);
|
|
@@ -57110,9 +57217,6 @@ async function startCommandLoop(ctx) {
|
|
|
57110
57217
|
pushGitState(ctx).catch((err) => {
|
|
57111
57218
|
console.warn(`[${formatTimestamp()}] ⚠️ Git state push failed: ${getErrorMessage(err)}`);
|
|
57112
57219
|
});
|
|
57113
|
-
pushFileTree(ctx).catch((err) => {
|
|
57114
|
-
console.warn(`[${formatTimestamp()}] ⚠️ File tree push failed: ${getErrorMessage(err)}`);
|
|
57115
|
-
});
|
|
57116
57220
|
pushCommands(ctx).catch((err) => {
|
|
57117
57221
|
console.warn(`[${formatTimestamp()}] ⚠️ Command sync failed: ${getErrorMessage(err)}`);
|
|
57118
57222
|
});
|
|
@@ -57123,8 +57227,8 @@ async function startCommandLoop(ctx) {
|
|
|
57123
57227
|
heartbeatTimer.unref();
|
|
57124
57228
|
let gitSubscriptionHandle = null;
|
|
57125
57229
|
let fileContentSubscriptionHandle = null;
|
|
57230
|
+
let fileTreeSubscriptionHandle = null;
|
|
57126
57231
|
pushGitState(ctx).catch(() => {});
|
|
57127
|
-
pushFileTree(ctx).catch(() => {});
|
|
57128
57232
|
pushCommands(ctx).catch(() => {});
|
|
57129
57233
|
const shutdown = async () => {
|
|
57130
57234
|
console.log(`
|
|
@@ -57134,6 +57238,8 @@ async function startCommandLoop(ctx) {
|
|
|
57134
57238
|
gitSubscriptionHandle.stop();
|
|
57135
57239
|
if (fileContentSubscriptionHandle)
|
|
57136
57240
|
fileContentSubscriptionHandle.stop();
|
|
57241
|
+
if (fileTreeSubscriptionHandle)
|
|
57242
|
+
fileTreeSubscriptionHandle.stop();
|
|
57137
57243
|
await onDaemonShutdown(ctx);
|
|
57138
57244
|
if (ctx.stopLocalApi) {
|
|
57139
57245
|
await ctx.stopLocalApi().catch(() => {});
|
|
@@ -57147,6 +57253,7 @@ async function startCommandLoop(ctx) {
|
|
|
57147
57253
|
const wsClient2 = await getConvexWsClient();
|
|
57148
57254
|
gitSubscriptionHandle = startGitRequestSubscription(ctx, wsClient2);
|
|
57149
57255
|
fileContentSubscriptionHandle = startFileContentSubscription(ctx, wsClient2);
|
|
57256
|
+
fileTreeSubscriptionHandle = startFileTreeSubscription(ctx, wsClient2);
|
|
57150
57257
|
console.log(`
|
|
57151
57258
|
Listening for commands...`);
|
|
57152
57259
|
console.log(`Press Ctrl+C to stop
|
|
@@ -57189,9 +57296,9 @@ var init_command_loop = __esm(() => {
|
|
|
57189
57296
|
init_on_request_stop_agent();
|
|
57190
57297
|
init_pid();
|
|
57191
57298
|
init_git_heartbeat();
|
|
57192
|
-
init_file_tree_heartbeat();
|
|
57193
57299
|
init_command_sync_heartbeat();
|
|
57194
57300
|
init_file_content_subscription();
|
|
57301
|
+
init_file_tree_subscription();
|
|
57195
57302
|
init_git_subscription();
|
|
57196
57303
|
init_command_runner();
|
|
57197
57304
|
init_init2();
|