@adhdev/daemon-core 0.9.82-rc.8 → 0.9.82-rc.9
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/git/git-commands.d.ts +1 -0
- package/dist/git/git-status.d.ts +5 -0
- package/dist/git/git-types.d.ts +10 -0
- package/dist/index.js +72 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +72 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/commands/router.ts +1 -1
- package/src/git/git-commands.ts +3 -3
- package/src/git/git-status.ts +97 -6
- package/src/git/git-summary.ts +3 -0
- package/src/git/git-types.ts +11 -0
|
@@ -42,6 +42,7 @@ export interface GitPushResult extends GitRepoIdentity {
|
|
|
42
42
|
export interface GitCommandServices {
|
|
43
43
|
getStatus?: (params: {
|
|
44
44
|
workspace: string;
|
|
45
|
+
refreshUpstream?: boolean;
|
|
45
46
|
}) => Promise<GitRepoStatus> | GitRepoStatus;
|
|
46
47
|
getDiffSummary?: (params: {
|
|
47
48
|
workspace: string;
|
package/dist/git/git-status.d.ts
CHANGED
|
@@ -5,6 +5,11 @@ export interface GitStatusOptions {
|
|
|
5
5
|
includeSubmodules?: boolean;
|
|
6
6
|
/** Optional filter to exclude specific submodule paths from status */
|
|
7
7
|
submoduleIgnorePaths?: string[];
|
|
8
|
+
/**
|
|
9
|
+
* When true, refresh the tracked remote before trusting ahead/behind.
|
|
10
|
+
* Callers should opt into this only for convergence-critical surfaces.
|
|
11
|
+
*/
|
|
12
|
+
refreshUpstream?: boolean;
|
|
8
13
|
}
|
|
9
14
|
export declare function getGitRepoStatus(workspace: string, options?: GitStatusOptions): Promise<GitRepoStatus>;
|
|
10
15
|
interface ParsedPorcelainStatus {
|
package/dist/git/git-types.d.ts
CHANGED
|
@@ -27,11 +27,18 @@ export interface GitSubmoduleStatus {
|
|
|
27
27
|
/** Error message if submodule status could not be read */
|
|
28
28
|
error?: string;
|
|
29
29
|
}
|
|
30
|
+
export type GitUpstreamFreshness = 'fresh' | 'unchecked' | 'stale' | 'no_upstream' | 'unavailable';
|
|
30
31
|
export interface GitRepoStatus extends GitRepoIdentity {
|
|
31
32
|
branch: string | null;
|
|
32
33
|
headCommit: string | null;
|
|
33
34
|
headMessage: string | null;
|
|
34
35
|
upstream: string | null;
|
|
36
|
+
/** Whether ahead/behind was verified against a freshly fetched upstream ref. */
|
|
37
|
+
upstreamStatus: GitUpstreamFreshness;
|
|
38
|
+
/** Timestamp for the fetch that refreshed upstream refs when upstreamStatus === 'fresh'. */
|
|
39
|
+
upstreamFetchedAt?: number;
|
|
40
|
+
/** Error from the last refresh attempt when upstreamStatus === 'stale'. */
|
|
41
|
+
upstreamFetchError?: string;
|
|
35
42
|
ahead: number;
|
|
36
43
|
behind: number;
|
|
37
44
|
staged: number;
|
|
@@ -105,6 +112,9 @@ export interface GitCompactSummary {
|
|
|
105
112
|
isGitRepo: boolean;
|
|
106
113
|
repoRoot: string | null;
|
|
107
114
|
branch: string | null;
|
|
115
|
+
upstreamStatus: GitUpstreamFreshness;
|
|
116
|
+
upstreamFetchedAt?: number;
|
|
117
|
+
upstreamFetchError?: string;
|
|
108
118
|
dirty: boolean;
|
|
109
119
|
changedFiles: number;
|
|
110
120
|
ahead: number;
|
package/dist/index.js
CHANGED
|
@@ -5913,8 +5913,14 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5913
5913
|
const includeSubmodules = options.includeSubmodules !== false;
|
|
5914
5914
|
try {
|
|
5915
5915
|
const repo = await resolveGitRepository(workspace, options);
|
|
5916
|
-
|
|
5917
|
-
|
|
5916
|
+
let parsed = await readPorcelainStatus(repo, options);
|
|
5917
|
+
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
5918
|
+
if (options.refreshUpstream) {
|
|
5919
|
+
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
5920
|
+
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
5921
|
+
parsed = await readPorcelainStatus(repo, options);
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5918
5924
|
const head = await readHead(repo, options);
|
|
5919
5925
|
const stashCount = await readStashCount(repo, options);
|
|
5920
5926
|
let submodules;
|
|
@@ -5929,6 +5935,9 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5929
5935
|
headCommit: head.commit,
|
|
5930
5936
|
headMessage: head.message,
|
|
5931
5937
|
upstream: parsed.upstream,
|
|
5938
|
+
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
5939
|
+
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
5940
|
+
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
5932
5941
|
ahead: parsed.ahead,
|
|
5933
5942
|
behind: parsed.behind,
|
|
5934
5943
|
staged: parsed.staged,
|
|
@@ -5953,6 +5962,60 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5953
5962
|
);
|
|
5954
5963
|
}
|
|
5955
5964
|
}
|
|
5965
|
+
async function readPorcelainStatus(repo, options) {
|
|
5966
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
5967
|
+
return parsePorcelainV2Status(statusOutput.stdout);
|
|
5968
|
+
}
|
|
5969
|
+
function getInitialUpstreamProbe(parsed) {
|
|
5970
|
+
return {
|
|
5971
|
+
upstreamStatus: parsed.upstream ? "unchecked" : "no_upstream"
|
|
5972
|
+
};
|
|
5973
|
+
}
|
|
5974
|
+
async function refreshTrackedUpstream(repo, parsed, options) {
|
|
5975
|
+
if (!parsed.upstream || !parsed.branch) {
|
|
5976
|
+
return { upstreamStatus: "no_upstream" };
|
|
5977
|
+
}
|
|
5978
|
+
const remoteName = await readBranchRemote(repo, parsed.branch, options) ?? inferRemoteName(parsed.upstream);
|
|
5979
|
+
if (!remoteName) {
|
|
5980
|
+
return {
|
|
5981
|
+
upstreamStatus: "stale",
|
|
5982
|
+
upstreamFetchError: `Unable to resolve remote for upstream '${parsed.upstream}'`
|
|
5983
|
+
};
|
|
5984
|
+
}
|
|
5985
|
+
try {
|
|
5986
|
+
await runGit(repo, ["fetch", "--quiet", "--prune", "--no-tags", remoteName], options);
|
|
5987
|
+
return {
|
|
5988
|
+
upstreamStatus: "fresh",
|
|
5989
|
+
upstreamFetchedAt: Date.now()
|
|
5990
|
+
};
|
|
5991
|
+
} catch (error) {
|
|
5992
|
+
return {
|
|
5993
|
+
upstreamStatus: "stale",
|
|
5994
|
+
upstreamFetchError: formatGitError(error)
|
|
5995
|
+
};
|
|
5996
|
+
}
|
|
5997
|
+
}
|
|
5998
|
+
async function readBranchRemote(repo, branch, options) {
|
|
5999
|
+
try {
|
|
6000
|
+
const result = await runGit(repo, ["config", "--get", `branch.${branch}.remote`], options);
|
|
6001
|
+
return result.stdout.trim() || null;
|
|
6002
|
+
} catch {
|
|
6003
|
+
return null;
|
|
6004
|
+
}
|
|
6005
|
+
}
|
|
6006
|
+
function inferRemoteName(upstream) {
|
|
6007
|
+
const [remoteName] = upstream.split("/");
|
|
6008
|
+
return remoteName?.trim() || null;
|
|
6009
|
+
}
|
|
6010
|
+
function formatGitError(error) {
|
|
6011
|
+
if (error instanceof GitCommandError) {
|
|
6012
|
+
return error.stderr || error.message;
|
|
6013
|
+
}
|
|
6014
|
+
if (error instanceof Error) {
|
|
6015
|
+
return error.message;
|
|
6016
|
+
}
|
|
6017
|
+
return String(error);
|
|
6018
|
+
}
|
|
5956
6019
|
function parsePorcelainV2Status(output) {
|
|
5957
6020
|
const parsed = {
|
|
5958
6021
|
branch: null,
|
|
@@ -6047,6 +6110,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
6047
6110
|
headCommit: null,
|
|
6048
6111
|
headMessage: null,
|
|
6049
6112
|
upstream: null,
|
|
6113
|
+
upstreamStatus: "unavailable",
|
|
6050
6114
|
ahead: 0,
|
|
6051
6115
|
behind: 0,
|
|
6052
6116
|
staged: 0,
|
|
@@ -6327,6 +6391,9 @@ function createGitCompactSummary(status, diffSummary) {
|
|
|
6327
6391
|
isGitRepo: status.isGitRepo,
|
|
6328
6392
|
repoRoot: status.repoRoot,
|
|
6329
6393
|
branch: status.branch,
|
|
6394
|
+
upstreamStatus: status.upstreamStatus,
|
|
6395
|
+
upstreamFetchedAt: status.upstreamFetchedAt,
|
|
6396
|
+
upstreamFetchError: status.upstreamFetchError,
|
|
6330
6397
|
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
6331
6398
|
changedFiles,
|
|
6332
6399
|
ahead: status.ahead,
|
|
@@ -6671,7 +6738,7 @@ var defaultSnapshotStore = createGitSnapshotStore({
|
|
|
6671
6738
|
});
|
|
6672
6739
|
function createDefaultGitCommandServices() {
|
|
6673
6740
|
return {
|
|
6674
|
-
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
6741
|
+
getStatus: ({ workspace, refreshUpstream }) => getGitRepoStatus(workspace, { refreshUpstream }),
|
|
6675
6742
|
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
6676
6743
|
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
6677
6744
|
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
@@ -6757,7 +6824,7 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
|
|
|
6757
6824
|
switch (command) {
|
|
6758
6825
|
case "git_status": {
|
|
6759
6826
|
if (!services.getStatus) return serviceNotImplemented(command);
|
|
6760
|
-
const status = await runService(() => services.getStatus({ workspace }));
|
|
6827
|
+
const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
|
|
6761
6828
|
return "success" in status ? status : { success: true, status };
|
|
6762
6829
|
}
|
|
6763
6830
|
case "git_diff_summary": {
|
|
@@ -26365,7 +26432,7 @@ ${block}`);
|
|
|
26365
26432
|
continue;
|
|
26366
26433
|
}
|
|
26367
26434
|
try {
|
|
26368
|
-
const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4 });
|
|
26435
|
+
const gitStatus = await getGitRepoStatus(node.workspace, { timeoutMs: 1e4, refreshUpstream: true });
|
|
26369
26436
|
status.git = gitStatus;
|
|
26370
26437
|
if (gitStatus.isGitRepo) {
|
|
26371
26438
|
status.health = deriveMeshNodeHealthFromGit(gitStatus);
|