chatroom-cli 1.36.0 → 1.36.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 +453 -44
- package/dist/index.js.map +12 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -56809,7 +56809,7 @@ var init_telegram = __esm(() => {
|
|
|
56809
56809
|
});
|
|
56810
56810
|
|
|
56811
56811
|
// ../../services/backend/config/reliability.ts
|
|
56812
|
-
var DAEMON_HEARTBEAT_INTERVAL_MS = 30000, AGENT_REQUEST_DEADLINE_MS = 120000;
|
|
56812
|
+
var DAEMON_HEARTBEAT_INTERVAL_MS = 30000, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVATION_TTL_MS = 60000, OBSERVED_SAFETY_POLL_MS = 30000;
|
|
56813
56813
|
|
|
56814
56814
|
// src/events/daemon/agent/on-request-start-agent.ts
|
|
56815
56815
|
async function onRequestStartAgent(ctx, event) {
|
|
@@ -56974,6 +56974,55 @@ var init_pid = __esm(() => {
|
|
|
56974
56974
|
CHATROOM_DIR4 = join8(homedir5(), ".chatroom");
|
|
56975
56975
|
});
|
|
56976
56976
|
|
|
56977
|
+
// src/infrastructure/git/git-state-pipeline.ts
|
|
56978
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
56979
|
+
|
|
56980
|
+
class GitStatePipeline {
|
|
56981
|
+
fields;
|
|
56982
|
+
constructor(fields) {
|
|
56983
|
+
this.fields = fields;
|
|
56984
|
+
}
|
|
56985
|
+
async collect(workingDir, preCollected) {
|
|
56986
|
+
const results = new Map(preCollected);
|
|
56987
|
+
if (this.fields.length === 0)
|
|
56988
|
+
return results;
|
|
56989
|
+
const entries = await Promise.all(this.fields.filter((f) => !results.has(f.key)).map(async (field) => {
|
|
56990
|
+
try {
|
|
56991
|
+
const raw = await field.collect(workingDir);
|
|
56992
|
+
return { key: field.key, raw };
|
|
56993
|
+
} catch {
|
|
56994
|
+
return { key: field.key, raw: field.defaultValue };
|
|
56995
|
+
}
|
|
56996
|
+
}));
|
|
56997
|
+
for (const { key, raw } of entries) {
|
|
56998
|
+
results.set(key, raw);
|
|
56999
|
+
}
|
|
57000
|
+
return results;
|
|
57001
|
+
}
|
|
57002
|
+
computeHash(values, slim) {
|
|
57003
|
+
const hashInput = {};
|
|
57004
|
+
for (const field of this.fields) {
|
|
57005
|
+
if (slim && !field.includeInSlim)
|
|
57006
|
+
continue;
|
|
57007
|
+
const raw = values.get(field.key) ?? field.defaultValue;
|
|
57008
|
+
hashInput[field.key] = field.toHashable(raw);
|
|
57009
|
+
}
|
|
57010
|
+
return createHash3("md5").update(JSON.stringify(hashInput)).digest("hex");
|
|
57011
|
+
}
|
|
57012
|
+
toMutationArgs(values, slim) {
|
|
57013
|
+
const args = {};
|
|
57014
|
+
for (const field of this.fields) {
|
|
57015
|
+
if (slim && !field.includeInSlim)
|
|
57016
|
+
continue;
|
|
57017
|
+
const raw = values.get(field.key) ?? field.defaultValue;
|
|
57018
|
+
Object.assign(args, field.toMutationPartial(raw));
|
|
57019
|
+
}
|
|
57020
|
+
args.pipelineMode = slim ? "slim" : "full";
|
|
57021
|
+
return args;
|
|
57022
|
+
}
|
|
57023
|
+
}
|
|
57024
|
+
var init_git_state_pipeline = () => {};
|
|
57025
|
+
|
|
56977
57026
|
// src/commands/machine/daemon-start/utils.ts
|
|
56978
57027
|
function formatTimestamp() {
|
|
56979
57028
|
return new Date().toISOString().replace("T", " ").substring(0, 19);
|
|
@@ -57613,6 +57662,28 @@ async function processMoreCommits(ctx, req) {
|
|
|
57613
57662
|
});
|
|
57614
57663
|
console.log(`[${formatTimestamp()}] \uD83D\uDCDC More commits appended: ${req.workingDir} (+${commits.length} commits, offset=${offset})`);
|
|
57615
57664
|
}
|
|
57665
|
+
async function processAllPullRequests(ctx, req) {
|
|
57666
|
+
const pullRequests = await getAllPRs(req.workingDir);
|
|
57667
|
+
await ctx.deps.backend.mutation(api.workspaces.upsertAllPullRequests, {
|
|
57668
|
+
sessionId: ctx.sessionId,
|
|
57669
|
+
machineId: ctx.machineId,
|
|
57670
|
+
workingDir: req.workingDir,
|
|
57671
|
+
pullRequests
|
|
57672
|
+
});
|
|
57673
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCCB All pull requests pushed: ${req.workingDir} (${pullRequests.length} PRs)`);
|
|
57674
|
+
}
|
|
57675
|
+
async function processRecentCommits(ctx, req) {
|
|
57676
|
+
const commits = await getRecentCommits(req.workingDir, COMMITS_PER_PAGE, 0);
|
|
57677
|
+
const hasMoreCommits = commits.length >= COMMITS_PER_PAGE;
|
|
57678
|
+
await ctx.deps.backend.mutation(api.workspaces.upsertRecentCommits, {
|
|
57679
|
+
sessionId: ctx.sessionId,
|
|
57680
|
+
machineId: ctx.machineId,
|
|
57681
|
+
workingDir: req.workingDir,
|
|
57682
|
+
commits,
|
|
57683
|
+
hasMoreCommits
|
|
57684
|
+
});
|
|
57685
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDCDC Recent commits pushed: ${req.workingDir} (${commits.length} commits)`);
|
|
57686
|
+
}
|
|
57616
57687
|
async function processRequests(ctx, requests, processedRequestIds, dedupTtlMs) {
|
|
57617
57688
|
const evictBefore = Date.now() - dedupTtlMs;
|
|
57618
57689
|
for (const [id, ts] of processedRequestIds) {
|
|
@@ -57649,6 +57720,12 @@ async function processRequests(ctx, requests, processedRequestIds, dedupTtlMs) {
|
|
|
57649
57720
|
case "pr_commits":
|
|
57650
57721
|
await processPRCommits(ctx, req);
|
|
57651
57722
|
break;
|
|
57723
|
+
case "all_pull_requests":
|
|
57724
|
+
await processAllPullRequests(ctx, req);
|
|
57725
|
+
break;
|
|
57726
|
+
case "recent_commits":
|
|
57727
|
+
await processRecentCommits(ctx, req);
|
|
57728
|
+
break;
|
|
57652
57729
|
}
|
|
57653
57730
|
await ctx.deps.backend.mutation(api.workspaces.updateRequestStatus, {
|
|
57654
57731
|
sessionId: ctx.sessionId,
|
|
@@ -57673,7 +57750,26 @@ var init_git_subscription = __esm(() => {
|
|
|
57673
57750
|
});
|
|
57674
57751
|
|
|
57675
57752
|
// src/commands/machine/daemon-start/git-heartbeat.ts
|
|
57676
|
-
|
|
57753
|
+
function makeBranchDependentFields(branch) {
|
|
57754
|
+
return [
|
|
57755
|
+
{
|
|
57756
|
+
key: "openPullRequests",
|
|
57757
|
+
includeInSlim: true,
|
|
57758
|
+
collect: (wd) => getOpenPRsForBranch(wd, branch),
|
|
57759
|
+
toHashable: (raw) => raw.map((pr) => pr.prNumber),
|
|
57760
|
+
toMutationPartial: (raw) => ({ openPullRequests: raw }),
|
|
57761
|
+
defaultValue: []
|
|
57762
|
+
},
|
|
57763
|
+
{
|
|
57764
|
+
key: "headCommitStatus",
|
|
57765
|
+
includeInSlim: true,
|
|
57766
|
+
collect: (wd) => getCommitStatusChecks(wd, branch),
|
|
57767
|
+
toHashable: (raw) => raw,
|
|
57768
|
+
toMutationPartial: (raw) => ({ headCommitStatus: raw }),
|
|
57769
|
+
defaultValue: null
|
|
57770
|
+
}
|
|
57771
|
+
];
|
|
57772
|
+
}
|
|
57677
57773
|
async function pushGitState(ctx) {
|
|
57678
57774
|
let workspaces;
|
|
57679
57775
|
try {
|
|
@@ -57700,8 +57796,8 @@ async function pushSingleWorkspaceGitState(ctx, workingDir) {
|
|
|
57700
57796
|
const stateKey = makeGitStateKey(ctx.machineId, workingDir);
|
|
57701
57797
|
const isRepo = await isGitRepo(workingDir);
|
|
57702
57798
|
if (!isRepo) {
|
|
57703
|
-
const
|
|
57704
|
-
if (ctx.lastPushedGitState.get(stateKey) ===
|
|
57799
|
+
const stateHash = "not_found";
|
|
57800
|
+
if (ctx.lastPushedGitState.get(stateKey) === stateHash)
|
|
57705
57801
|
return;
|
|
57706
57802
|
await ctx.deps.backend.mutation(api.workspaces.upsertWorkspaceGitState, {
|
|
57707
57803
|
sessionId: ctx.sessionId,
|
|
@@ -57709,20 +57805,13 @@ async function pushSingleWorkspaceGitState(ctx, workingDir) {
|
|
|
57709
57805
|
workingDir,
|
|
57710
57806
|
status: "not_found"
|
|
57711
57807
|
});
|
|
57712
|
-
ctx.lastPushedGitState.set(stateKey,
|
|
57808
|
+
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
57713
57809
|
return;
|
|
57714
57810
|
}
|
|
57715
|
-
const
|
|
57716
|
-
getBranch(workingDir),
|
|
57717
|
-
isDirty(workingDir),
|
|
57718
|
-
getDiffStat(workingDir),
|
|
57719
|
-
getRecentCommits(workingDir, COMMITS_PER_PAGE),
|
|
57720
|
-
getCommitsAhead(workingDir)
|
|
57721
|
-
]);
|
|
57722
|
-
const remotes = await getRemotes(workingDir);
|
|
57811
|
+
const branchResult = await getBranch(workingDir);
|
|
57723
57812
|
if (branchResult.status === "error") {
|
|
57724
|
-
const
|
|
57725
|
-
if (ctx.lastPushedGitState.get(stateKey) ===
|
|
57813
|
+
const stateHash = `error:${branchResult.message}`;
|
|
57814
|
+
if (ctx.lastPushedGitState.get(stateKey) === stateHash)
|
|
57726
57815
|
return;
|
|
57727
57816
|
await ctx.deps.backend.mutation(api.workspaces.upsertWorkspaceGitState, {
|
|
57728
57817
|
sessionId: ctx.sessionId,
|
|
@@ -57731,21 +57820,21 @@ async function pushSingleWorkspaceGitState(ctx, workingDir) {
|
|
|
57731
57820
|
status: "error",
|
|
57732
57821
|
errorMessage: branchResult.message
|
|
57733
57822
|
});
|
|
57734
|
-
ctx.lastPushedGitState.set(stateKey,
|
|
57823
|
+
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
57735
57824
|
return;
|
|
57736
57825
|
}
|
|
57737
57826
|
if (branchResult.status === "not_found") {
|
|
57738
57827
|
return;
|
|
57739
57828
|
}
|
|
57740
|
-
const openPRs = await getOpenPRsForBranch(workingDir, branchResult.branch);
|
|
57741
|
-
const allPRs = await getAllPRs(workingDir);
|
|
57742
|
-
const headCommitStatus = await getCommitStatusChecks(workingDir, branchResult.branch);
|
|
57743
57829
|
const branch = branchResult.branch;
|
|
57744
|
-
const
|
|
57745
|
-
const
|
|
57830
|
+
const allFields = [branchField, ...GIT_STATE_FIELDS, ...makeBranchDependentFields(branch)];
|
|
57831
|
+
const pipeline2 = new GitStatePipeline(allFields);
|
|
57832
|
+
const preCollected = new Map([["branch", branchResult]]);
|
|
57833
|
+
const values = await pipeline2.collect(workingDir, preCollected);
|
|
57834
|
+
const commits = values.get("commits");
|
|
57746
57835
|
const hasMoreCommits = commits.length >= COMMITS_PER_PAGE;
|
|
57747
|
-
const
|
|
57748
|
-
if (ctx.lastPushedGitState.get(stateKey) ===
|
|
57836
|
+
const hash = pipeline2.computeHash(values, false);
|
|
57837
|
+
if (ctx.lastPushedGitState.get(stateKey) === hash) {
|
|
57749
57838
|
return;
|
|
57750
57839
|
}
|
|
57751
57840
|
await ctx.deps.backend.mutation(api.workspaces.upsertWorkspaceGitState, {
|
|
@@ -57753,23 +57842,73 @@ async function pushSingleWorkspaceGitState(ctx, workingDir) {
|
|
|
57753
57842
|
machineId: ctx.machineId,
|
|
57754
57843
|
workingDir,
|
|
57755
57844
|
status: "available",
|
|
57756
|
-
|
|
57757
|
-
isDirty: isDirty2,
|
|
57758
|
-
diffStat,
|
|
57845
|
+
...pipeline2.toMutationArgs(values, false),
|
|
57759
57846
|
recentCommits: commits,
|
|
57760
|
-
hasMoreCommits
|
|
57761
|
-
openPullRequests: openPRs,
|
|
57762
|
-
allPullRequests: allPRs,
|
|
57763
|
-
remotes,
|
|
57764
|
-
commitsAhead,
|
|
57765
|
-
headCommitStatus
|
|
57847
|
+
hasMoreCommits
|
|
57766
57848
|
});
|
|
57767
|
-
ctx.lastPushedGitState.set(stateKey,
|
|
57768
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD00 Git state pushed: ${workingDir} (${branch}${
|
|
57849
|
+
ctx.lastPushedGitState.set(stateKey, hash);
|
|
57850
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD00 Git state pushed: ${workingDir} (${branch}${values.get("isDirty") ? ", dirty" : ", clean"})`);
|
|
57769
57851
|
prefetchMissingCommitDetails(ctx, workingDir, commits).catch((err) => {
|
|
57770
57852
|
console.warn(`[${formatTimestamp()}] ⚠️ Commit pre-fetch failed for ${workingDir}: ${getErrorMessage(err)}`);
|
|
57771
57853
|
});
|
|
57772
57854
|
}
|
|
57855
|
+
async function pushSingleWorkspaceGitSummaryForObserved(ctx, workingDir, reason = "safety-poll") {
|
|
57856
|
+
const stateKey = makeGitStateKey(ctx.machineId, workingDir);
|
|
57857
|
+
const isRepo = await isGitRepo(workingDir);
|
|
57858
|
+
if (!isRepo) {
|
|
57859
|
+
const stateHash = "not_found";
|
|
57860
|
+
if (reason !== "refresh" && ctx.lastPushedGitState.get(stateKey) === stateHash)
|
|
57861
|
+
return;
|
|
57862
|
+
await ctx.deps.backend.mutation(api.workspaces.upsertWorkspaceGitState, {
|
|
57863
|
+
sessionId: ctx.sessionId,
|
|
57864
|
+
machineId: ctx.machineId,
|
|
57865
|
+
workingDir,
|
|
57866
|
+
status: "not_found"
|
|
57867
|
+
});
|
|
57868
|
+
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
57869
|
+
return;
|
|
57870
|
+
}
|
|
57871
|
+
const branchResult = await getBranch(workingDir);
|
|
57872
|
+
if (branchResult.status === "error") {
|
|
57873
|
+
const stateHash = `error:${branchResult.message}`;
|
|
57874
|
+
if (reason !== "refresh" && ctx.lastPushedGitState.get(stateKey) === stateHash)
|
|
57875
|
+
return;
|
|
57876
|
+
await ctx.deps.backend.mutation(api.workspaces.upsertWorkspaceGitState, {
|
|
57877
|
+
sessionId: ctx.sessionId,
|
|
57878
|
+
machineId: ctx.machineId,
|
|
57879
|
+
workingDir,
|
|
57880
|
+
status: "error",
|
|
57881
|
+
errorMessage: branchResult.message
|
|
57882
|
+
});
|
|
57883
|
+
ctx.lastPushedGitState.set(stateKey, stateHash);
|
|
57884
|
+
return;
|
|
57885
|
+
}
|
|
57886
|
+
if (branchResult.status === "not_found") {
|
|
57887
|
+
return;
|
|
57888
|
+
}
|
|
57889
|
+
const branch = branchResult.branch;
|
|
57890
|
+
const slimFields = [
|
|
57891
|
+
branchField,
|
|
57892
|
+
...GIT_STATE_FIELDS.filter((f) => f.includeInSlim),
|
|
57893
|
+
...makeBranchDependentFields(branch)
|
|
57894
|
+
];
|
|
57895
|
+
const pipeline2 = new GitStatePipeline(slimFields);
|
|
57896
|
+
const preCollected = new Map([["branch", branchResult]]);
|
|
57897
|
+
const values = await pipeline2.collect(workingDir, preCollected);
|
|
57898
|
+
const hash = pipeline2.computeHash(values, true);
|
|
57899
|
+
if (reason !== "refresh" && ctx.lastPushedGitState.get(stateKey) === hash) {
|
|
57900
|
+
return;
|
|
57901
|
+
}
|
|
57902
|
+
await ctx.deps.backend.mutation(api.workspaces.upsertWorkspaceGitState, {
|
|
57903
|
+
sessionId: ctx.sessionId,
|
|
57904
|
+
machineId: ctx.machineId,
|
|
57905
|
+
workingDir,
|
|
57906
|
+
status: "available",
|
|
57907
|
+
...pipeline2.toMutationArgs(values, true)
|
|
57908
|
+
});
|
|
57909
|
+
ctx.lastPushedGitState.set(stateKey, hash);
|
|
57910
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed git summary pushed: ${workingDir} (${branch}${values.get("isDirty") ? ", dirty" : ", clean"})${reason === "refresh" ? " [refresh]" : ""}`);
|
|
57911
|
+
}
|
|
57773
57912
|
async function prefetchMissingCommitDetails(ctx, workingDir, commits) {
|
|
57774
57913
|
if (commits.length === 0)
|
|
57775
57914
|
return;
|
|
@@ -57840,11 +57979,87 @@ async function prefetchSingleCommit(ctx, workingDir, sha, commits) {
|
|
|
57840
57979
|
});
|
|
57841
57980
|
console.log(`[${formatTimestamp()}] ✅ Pre-fetched: ${sha.slice(0, 7)} in ${workingDir}`);
|
|
57842
57981
|
}
|
|
57982
|
+
var branchField, GIT_STATE_FIELDS;
|
|
57843
57983
|
var init_git_heartbeat = __esm(() => {
|
|
57984
|
+
init_git_state_pipeline();
|
|
57844
57985
|
init_git_subscription();
|
|
57845
57986
|
init_api3();
|
|
57846
57987
|
init_git_reader();
|
|
57847
57988
|
init_convex_error();
|
|
57989
|
+
branchField = {
|
|
57990
|
+
key: "branch",
|
|
57991
|
+
includeInSlim: true,
|
|
57992
|
+
collect: () => {
|
|
57993
|
+
throw new Error("branch must be pre-collected");
|
|
57994
|
+
},
|
|
57995
|
+
toHashable: (raw) => {
|
|
57996
|
+
const r = raw;
|
|
57997
|
+
return r.status === "available" ? r.branch : "unknown";
|
|
57998
|
+
},
|
|
57999
|
+
toMutationPartial: (raw) => {
|
|
58000
|
+
const r = raw;
|
|
58001
|
+
return r.status === "available" ? { branch: r.branch } : {};
|
|
58002
|
+
},
|
|
58003
|
+
defaultValue: { status: "not_found" }
|
|
58004
|
+
};
|
|
58005
|
+
GIT_STATE_FIELDS = [
|
|
58006
|
+
{
|
|
58007
|
+
key: "isDirty",
|
|
58008
|
+
includeInSlim: true,
|
|
58009
|
+
collect: (wd) => isDirty(wd),
|
|
58010
|
+
toHashable: (raw) => raw,
|
|
58011
|
+
toMutationPartial: (raw) => ({ isDirty: raw }),
|
|
58012
|
+
defaultValue: false
|
|
58013
|
+
},
|
|
58014
|
+
{
|
|
58015
|
+
key: "diffStat",
|
|
58016
|
+
includeInSlim: false,
|
|
58017
|
+
collect: (wd) => getDiffStat(wd),
|
|
58018
|
+
toHashable: (raw) => {
|
|
58019
|
+
const r = raw;
|
|
58020
|
+
return r.status === "available" ? r.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 };
|
|
58021
|
+
},
|
|
58022
|
+
toMutationPartial: (raw) => {
|
|
58023
|
+
const r = raw;
|
|
58024
|
+
return {
|
|
58025
|
+
diffStat: r.status === "available" ? r.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 }
|
|
58026
|
+
};
|
|
58027
|
+
},
|
|
58028
|
+
defaultValue: { status: "not_found" }
|
|
58029
|
+
},
|
|
58030
|
+
{
|
|
58031
|
+
key: "commits",
|
|
58032
|
+
includeInSlim: false,
|
|
58033
|
+
collect: (wd) => getRecentCommits(wd, COMMITS_PER_PAGE),
|
|
58034
|
+
toHashable: (raw) => raw.map((c) => c.sha),
|
|
58035
|
+
toMutationPartial: () => ({}),
|
|
58036
|
+
defaultValue: []
|
|
58037
|
+
},
|
|
58038
|
+
{
|
|
58039
|
+
key: "commitsAhead",
|
|
58040
|
+
includeInSlim: false,
|
|
58041
|
+
collect: (wd) => getCommitsAhead(wd),
|
|
58042
|
+
toHashable: (raw) => raw,
|
|
58043
|
+
toMutationPartial: (raw) => ({ commitsAhead: raw }),
|
|
58044
|
+
defaultValue: 0
|
|
58045
|
+
},
|
|
58046
|
+
{
|
|
58047
|
+
key: "remotes",
|
|
58048
|
+
includeInSlim: false,
|
|
58049
|
+
collect: (wd) => getRemotes(wd),
|
|
58050
|
+
toHashable: (raw) => raw.map((r) => `${r.name}:${r.url}`),
|
|
58051
|
+
toMutationPartial: (raw) => ({ remotes: raw }),
|
|
58052
|
+
defaultValue: []
|
|
58053
|
+
},
|
|
58054
|
+
{
|
|
58055
|
+
key: "allPullRequests",
|
|
58056
|
+
includeInSlim: false,
|
|
58057
|
+
collect: (wd) => getAllPRs(wd),
|
|
58058
|
+
toHashable: (raw) => raw.map((pr) => `${pr.prNumber}:${pr.state}`),
|
|
58059
|
+
toMutationPartial: (raw) => ({ allPullRequests: raw }),
|
|
58060
|
+
defaultValue: []
|
|
58061
|
+
}
|
|
58062
|
+
];
|
|
57848
58063
|
});
|
|
57849
58064
|
|
|
57850
58065
|
// src/infrastructure/services/workspace/workspace-resolver.ts
|
|
@@ -58485,6 +58700,176 @@ var init_file_tree_subscription = __esm(() => {
|
|
|
58485
58700
|
init_convex_error();
|
|
58486
58701
|
});
|
|
58487
58702
|
|
|
58703
|
+
// src/commands/machine/daemon-start/observed-sync.ts
|
|
58704
|
+
function startObservedSyncSubscription(ctx, wsClient2) {
|
|
58705
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Starting observed-sync subscription (reactive)`);
|
|
58706
|
+
const observedWorkingDirs = new Map;
|
|
58707
|
+
const chatroomRefreshState = new Map;
|
|
58708
|
+
const skippedPushCount = new Map;
|
|
58709
|
+
const pendingRefresh = new Map;
|
|
58710
|
+
let stopped = false;
|
|
58711
|
+
let reconcileInFlight = false;
|
|
58712
|
+
const unsubscribe = wsClient2.onUpdate(api.machines.getObservedChatroomsForMachine, {
|
|
58713
|
+
sessionId: ctx.sessionId,
|
|
58714
|
+
machineId: ctx.machineId
|
|
58715
|
+
}, (observed) => {
|
|
58716
|
+
if (stopped)
|
|
58717
|
+
return;
|
|
58718
|
+
handleObservedChange(observed ?? []);
|
|
58719
|
+
}, (err) => {
|
|
58720
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Observed-sync subscription error: ${getErrorMessage(err)}`);
|
|
58721
|
+
});
|
|
58722
|
+
const reconcileIntervalMs = Math.max(OBSERVATION_TTL_MS / 2, OBSERVED_SAFETY_POLL_MS);
|
|
58723
|
+
const reconcileTimer = setInterval(() => {
|
|
58724
|
+
if (stopped || reconcileInFlight)
|
|
58725
|
+
return;
|
|
58726
|
+
reconcileInFlight = true;
|
|
58727
|
+
ctx.deps.backend.query(api.machines.getObservedChatroomsForMachine, {
|
|
58728
|
+
sessionId: ctx.sessionId,
|
|
58729
|
+
machineId: ctx.machineId
|
|
58730
|
+
}).then((observed) => {
|
|
58731
|
+
if (!stopped)
|
|
58732
|
+
handleObservedChange(observed ?? []);
|
|
58733
|
+
}).catch((err) => {
|
|
58734
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Observed-sync reconcile query failed: ${getErrorMessage(err)}`);
|
|
58735
|
+
}).finally(() => {
|
|
58736
|
+
reconcileInFlight = false;
|
|
58737
|
+
});
|
|
58738
|
+
}, reconcileIntervalMs);
|
|
58739
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed-sync subscription started`);
|
|
58740
|
+
return {
|
|
58741
|
+
stop: () => {
|
|
58742
|
+
stopped = true;
|
|
58743
|
+
unsubscribe();
|
|
58744
|
+
clearInterval(reconcileTimer);
|
|
58745
|
+
for (const [wd, state] of observedWorkingDirs) {
|
|
58746
|
+
clearInterval(state.intervalHandle);
|
|
58747
|
+
const skips = skippedPushCount.get(wd) ?? 0;
|
|
58748
|
+
if (skips > 0) {
|
|
58749
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Stopped observing ${wd} (skipped ${skips} overlapping pushes)`);
|
|
58750
|
+
} else {
|
|
58751
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Stopped observing ${wd}`);
|
|
58752
|
+
}
|
|
58753
|
+
}
|
|
58754
|
+
observedWorkingDirs.clear();
|
|
58755
|
+
skippedPushCount.clear();
|
|
58756
|
+
pendingRefresh.clear();
|
|
58757
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed-sync subscription stopped`);
|
|
58758
|
+
}
|
|
58759
|
+
};
|
|
58760
|
+
function handleObservedChange(observed) {
|
|
58761
|
+
const newWorkingDirs = new Set;
|
|
58762
|
+
const refreshedWorkingDirs = new Set;
|
|
58763
|
+
for (const chatroom of observed) {
|
|
58764
|
+
const chatroomId = chatroom.chatroomId;
|
|
58765
|
+
const currentRefresh = chatroom.lastRefreshedAt;
|
|
58766
|
+
const previous = chatroomRefreshState.get(chatroomId);
|
|
58767
|
+
const wasRefreshed = currentRefresh !== null && currentRefresh !== undefined && (previous === undefined || (previous.lastRefreshedAt ?? 0) < currentRefresh);
|
|
58768
|
+
if (wasRefreshed) {
|
|
58769
|
+
chatroomRefreshState.set(chatroomId, { lastRefreshedAt: currentRefresh });
|
|
58770
|
+
for (const wd of chatroom.workingDirs) {
|
|
58771
|
+
refreshedWorkingDirs.add(wd);
|
|
58772
|
+
}
|
|
58773
|
+
}
|
|
58774
|
+
for (const wd of chatroom.workingDirs) {
|
|
58775
|
+
newWorkingDirs.add(wd);
|
|
58776
|
+
}
|
|
58777
|
+
}
|
|
58778
|
+
for (const [chatroomId] of chatroomRefreshState) {
|
|
58779
|
+
const stillObserved = observed.some((c) => c.chatroomId === chatroomId);
|
|
58780
|
+
if (!stillObserved) {
|
|
58781
|
+
chatroomRefreshState.delete(chatroomId);
|
|
58782
|
+
}
|
|
58783
|
+
}
|
|
58784
|
+
const currentWorkingDirs = new Set(observedWorkingDirs.keys());
|
|
58785
|
+
let addedCount = 0;
|
|
58786
|
+
let removedCount = 0;
|
|
58787
|
+
for (const wd of currentWorkingDirs) {
|
|
58788
|
+
if (!newWorkingDirs.has(wd)) {
|
|
58789
|
+
const state = observedWorkingDirs.get(wd);
|
|
58790
|
+
if (state) {
|
|
58791
|
+
clearInterval(state.intervalHandle);
|
|
58792
|
+
observedWorkingDirs.delete(wd);
|
|
58793
|
+
const skips = skippedPushCount.get(wd) ?? 0;
|
|
58794
|
+
if (skips > 0) {
|
|
58795
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Stopped observing ${wd} (skipped ${skips} overlapping pushes)`);
|
|
58796
|
+
} else {
|
|
58797
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Stopped observing ${wd}`);
|
|
58798
|
+
}
|
|
58799
|
+
skippedPushCount.delete(wd);
|
|
58800
|
+
pendingRefresh.delete(wd);
|
|
58801
|
+
removedCount++;
|
|
58802
|
+
}
|
|
58803
|
+
}
|
|
58804
|
+
}
|
|
58805
|
+
for (const wd of newWorkingDirs) {
|
|
58806
|
+
if (!observedWorkingDirs.has(wd)) {
|
|
58807
|
+
observedWorkingDirs.set(wd, {
|
|
58808
|
+
intervalHandle: setInterval(() => {
|
|
58809
|
+
schedulePushForWorkingDir(wd, "safety-poll");
|
|
58810
|
+
}, OBSERVED_SAFETY_POLL_MS),
|
|
58811
|
+
pushInFlight: false
|
|
58812
|
+
});
|
|
58813
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Started observing ${wd}`);
|
|
58814
|
+
schedulePushForWorkingDir(wd, "safety-poll");
|
|
58815
|
+
addedCount++;
|
|
58816
|
+
}
|
|
58817
|
+
}
|
|
58818
|
+
if (addedCount > 0 || removedCount > 0) {
|
|
58819
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observing ${observedWorkingDirs.size} working dir(s)`);
|
|
58820
|
+
}
|
|
58821
|
+
for (const wd of refreshedWorkingDirs) {
|
|
58822
|
+
if (observedWorkingDirs.has(wd)) {
|
|
58823
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Refresh triggered for ${wd}`);
|
|
58824
|
+
schedulePushForWorkingDir(wd, "refresh");
|
|
58825
|
+
}
|
|
58826
|
+
}
|
|
58827
|
+
}
|
|
58828
|
+
function schedulePushForWorkingDir(workingDir, reason = "safety-poll") {
|
|
58829
|
+
if (stopped)
|
|
58830
|
+
return;
|
|
58831
|
+
const state = observedWorkingDirs.get(workingDir);
|
|
58832
|
+
if (!state)
|
|
58833
|
+
return;
|
|
58834
|
+
if (state.pushInFlight) {
|
|
58835
|
+
if (reason === "refresh") {
|
|
58836
|
+
pendingRefresh.set(workingDir, true);
|
|
58837
|
+
}
|
|
58838
|
+
const current = skippedPushCount.get(workingDir) ?? 0;
|
|
58839
|
+
skippedPushCount.set(workingDir, current + 1);
|
|
58840
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Skipping observed push for ${workingDir} (${reason}, in flight)`);
|
|
58841
|
+
return;
|
|
58842
|
+
}
|
|
58843
|
+
state.pushInFlight = true;
|
|
58844
|
+
pushForWorkingDir(workingDir, reason).catch((err) => {
|
|
58845
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Push failed for ${workingDir}: ${getErrorMessage(err)}`);
|
|
58846
|
+
}).finally(() => {
|
|
58847
|
+
const s = observedWorkingDirs.get(workingDir);
|
|
58848
|
+
if (s) {
|
|
58849
|
+
s.pushInFlight = false;
|
|
58850
|
+
if (pendingRefresh.get(workingDir)) {
|
|
58851
|
+
pendingRefresh.delete(workingDir);
|
|
58852
|
+
schedulePushForWorkingDir(workingDir, "refresh");
|
|
58853
|
+
}
|
|
58854
|
+
}
|
|
58855
|
+
});
|
|
58856
|
+
}
|
|
58857
|
+
async function pushForWorkingDir(workingDir, reason = "safety-poll") {
|
|
58858
|
+
await pushSingleWorkspaceGitSummaryForObserved(ctx, workingDir, reason).catch((err) => {
|
|
58859
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Observed git summary push failed for ${workingDir}: ${getErrorMessage(err)}`);
|
|
58860
|
+
});
|
|
58861
|
+
await pushSingleWorkspaceCommands(ctx, workingDir).catch((err) => {
|
|
58862
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Command sync failed for ${workingDir}: ${getErrorMessage(err)}`);
|
|
58863
|
+
});
|
|
58864
|
+
}
|
|
58865
|
+
}
|
|
58866
|
+
var init_observed_sync = __esm(() => {
|
|
58867
|
+
init_api3();
|
|
58868
|
+
init_git_heartbeat();
|
|
58869
|
+
init_command_sync_heartbeat();
|
|
58870
|
+
init_convex_error();
|
|
58871
|
+
});
|
|
58872
|
+
|
|
58488
58873
|
// src/commands/machine/daemon-start/handlers/ping.ts
|
|
58489
58874
|
function handlePing() {
|
|
58490
58875
|
console.log(` ↪ Responding: pong`);
|
|
@@ -59727,6 +60112,15 @@ var init_agent_process_manager = __esm(() => {
|
|
|
59727
60112
|
init_api3();
|
|
59728
60113
|
});
|
|
59729
60114
|
|
|
60115
|
+
// ../../services/backend/config/featureFlags.ts
|
|
60116
|
+
var featureFlags;
|
|
60117
|
+
var init_featureFlags = __esm(() => {
|
|
60118
|
+
featureFlags = {
|
|
60119
|
+
observedSyncEnabled: false,
|
|
60120
|
+
disableLogin: false
|
|
60121
|
+
};
|
|
60122
|
+
});
|
|
60123
|
+
|
|
59730
60124
|
// src/commands/machine/daemon-start/init.ts
|
|
59731
60125
|
import { stat as stat2 } from "node:fs/promises";
|
|
59732
60126
|
async function discoverModels(agentServices) {
|
|
@@ -59949,7 +60343,8 @@ async function initDaemon() {
|
|
|
59949
60343
|
events,
|
|
59950
60344
|
agentServices,
|
|
59951
60345
|
lastPushedGitState: new Map,
|
|
59952
|
-
lastPushedModels: availableModels
|
|
60346
|
+
lastPushedModels: availableModels,
|
|
60347
|
+
observedSyncEnabled: featureFlags.observedSyncEnabled ?? false
|
|
59953
60348
|
};
|
|
59954
60349
|
registerEventListeners(ctx);
|
|
59955
60350
|
logStartup(ctx, availableModels);
|
|
@@ -59991,6 +60386,7 @@ var init_init2 = __esm(() => {
|
|
|
59991
60386
|
init_convex_error();
|
|
59992
60387
|
init_version();
|
|
59993
60388
|
init_pid();
|
|
60389
|
+
init_featureFlags();
|
|
59994
60390
|
AUTH_WAIT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
59995
60391
|
});
|
|
59996
60392
|
|
|
@@ -60334,12 +60730,14 @@ async function startCommandLoop(ctx) {
|
|
|
60334
60730
|
}).then(() => {
|
|
60335
60731
|
heartbeatCount++;
|
|
60336
60732
|
console.log(`[${formatTimestamp()}] \uD83D\uDC93 Daemon heartbeat #${heartbeatCount} OK`);
|
|
60337
|
-
|
|
60338
|
-
|
|
60339
|
-
|
|
60340
|
-
|
|
60341
|
-
|
|
60342
|
-
|
|
60733
|
+
if (!ctx.observedSyncEnabled) {
|
|
60734
|
+
pushGitState(ctx).catch((err) => {
|
|
60735
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Git state push failed: ${getErrorMessage(err)}`);
|
|
60736
|
+
});
|
|
60737
|
+
pushCommands(ctx).catch((err) => {
|
|
60738
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Command sync failed: ${getErrorMessage(err)}`);
|
|
60739
|
+
});
|
|
60740
|
+
}
|
|
60343
60741
|
}).catch((err) => {
|
|
60344
60742
|
console.warn(`[${formatTimestamp()}] ⚠️ Daemon heartbeat failed: ${getErrorMessage(err)}`);
|
|
60345
60743
|
});
|
|
@@ -60348,8 +60746,13 @@ async function startCommandLoop(ctx) {
|
|
|
60348
60746
|
let gitSubscriptionHandle = null;
|
|
60349
60747
|
let fileContentSubscriptionHandle = null;
|
|
60350
60748
|
let fileTreeSubscriptionHandle = null;
|
|
60351
|
-
|
|
60352
|
-
|
|
60749
|
+
let observedSyncSubscriptionHandle = null;
|
|
60750
|
+
if (ctx.observedSyncEnabled) {
|
|
60751
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Observed-sync enabled, skipping immediate push`);
|
|
60752
|
+
} else {
|
|
60753
|
+
pushGitState(ctx).catch(() => {});
|
|
60754
|
+
pushCommands(ctx).catch(() => {});
|
|
60755
|
+
}
|
|
60353
60756
|
const shutdown = async () => {
|
|
60354
60757
|
console.log(`
|
|
60355
60758
|
[${formatTimestamp()}] Shutting down...`);
|
|
@@ -60360,6 +60763,8 @@ async function startCommandLoop(ctx) {
|
|
|
60360
60763
|
fileContentSubscriptionHandle.stop();
|
|
60361
60764
|
if (fileTreeSubscriptionHandle)
|
|
60362
60765
|
fileTreeSubscriptionHandle.stop();
|
|
60766
|
+
if (observedSyncSubscriptionHandle)
|
|
60767
|
+
observedSyncSubscriptionHandle.stop();
|
|
60363
60768
|
await onDaemonShutdown(ctx);
|
|
60364
60769
|
if (ctx.stopLocalApi) {
|
|
60365
60770
|
await ctx.stopLocalApi().catch(() => {});
|
|
@@ -60374,6 +60779,9 @@ async function startCommandLoop(ctx) {
|
|
|
60374
60779
|
gitSubscriptionHandle = startGitRequestSubscription(ctx, wsClient2);
|
|
60375
60780
|
fileContentSubscriptionHandle = startFileContentSubscription(ctx, wsClient2);
|
|
60376
60781
|
fileTreeSubscriptionHandle = startFileTreeSubscription(ctx, wsClient2);
|
|
60782
|
+
if (ctx.observedSyncEnabled) {
|
|
60783
|
+
observedSyncSubscriptionHandle = startObservedSyncSubscription(ctx, wsClient2);
|
|
60784
|
+
}
|
|
60377
60785
|
console.log(`
|
|
60378
60786
|
Listening for commands...`);
|
|
60379
60787
|
console.log(`Press Ctrl+C to stop
|
|
@@ -60420,6 +60828,7 @@ var init_command_loop = __esm(() => {
|
|
|
60420
60828
|
init_file_content_subscription();
|
|
60421
60829
|
init_file_tree_subscription();
|
|
60422
60830
|
init_git_subscription();
|
|
60831
|
+
init_observed_sync();
|
|
60423
60832
|
init_command_runner();
|
|
60424
60833
|
init_init2();
|
|
60425
60834
|
init_api3();
|
|
@@ -61525,5 +61934,5 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
61525
61934
|
});
|
|
61526
61935
|
program2.parse();
|
|
61527
61936
|
|
|
61528
|
-
//# debugId=
|
|
61937
|
+
//# debugId=C6BB51F249BBA12864756E2164756E21
|
|
61529
61938
|
//# sourceMappingURL=index.js.map
|