workday-daemon 0.7.2 → 0.8.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/collectors/git-client.d.ts +27 -1
- package/dist/collectors/git-client.js +94 -0
- package/dist/collectors/git-client.js.map +1 -1
- package/dist/collectors/git-tracker.d.ts +2 -2
- package/dist/collectors/git-tracker.js +14 -3
- package/dist/collectors/git-tracker.js.map +1 -1
- package/dist/collectors/ledger-collector.d.ts +13 -0
- package/dist/collectors/ledger-collector.js +73 -0
- package/dist/collectors/ledger-collector.js.map +1 -0
- package/dist/core/commit-ledger.d.ts +46 -0
- package/dist/core/commit-ledger.js +173 -0
- package/dist/core/commit-ledger.js.map +1 -0
- package/dist/core/daily-log.d.ts +6 -0
- package/dist/core/daily-log.js +13 -3
- package/dist/core/daily-log.js.map +1 -1
- package/dist/core/session-tracker.d.ts +18 -3
- package/dist/core/session-tracker.js +95 -27
- package/dist/core/session-tracker.js.map +1 -1
- package/dist/core/types.d.ts +65 -0
- package/dist/core/types.js.map +1 -1
- package/dist/daemon.js +2 -1
- package/dist/daemon.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RawGitOutput } from '../core/types.js';
|
|
1
|
+
import type { RawGitOutput, CommitMeta } from '../core/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Low-level git command executor.
|
|
4
4
|
* Runs batched git calls and returns raw output split by sections.
|
|
@@ -32,5 +32,31 @@ export declare class GitClient {
|
|
|
32
32
|
* typical for shallow clones or repos that never had origin/HEAD set.
|
|
33
33
|
*/
|
|
34
34
|
detectDefaultBranchName(repoPath: string): Promise<string | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Branch reflog entries, newest first: [{sha (new value of the ref),
|
|
37
|
+
* ts (when the move happened), message}]. Every branch-tip move —
|
|
38
|
+
* commit, amend, rebase finish, reset, merge — writes exactly one entry,
|
|
39
|
+
* so consecutive entries form the complete old→new transition journal.
|
|
40
|
+
* Empty array when the branch has no reflog (core.logAllRefUpdates off).
|
|
41
|
+
*/
|
|
42
|
+
getBranchReflog(repoPath: string, branch: string, count: number): Promise<Array<{
|
|
43
|
+
sha: string;
|
|
44
|
+
ts: number;
|
|
45
|
+
message: string;
|
|
46
|
+
}>>;
|
|
47
|
+
/**
|
|
48
|
+
* Batched commit metadata. Works for unreachable SHAs too (squashed-away
|
|
49
|
+
* commits stay in the object db until gc — reflog entries protect them),
|
|
50
|
+
* which is exactly what transition replay needs. SHAs whose objects are
|
|
51
|
+
* gone are silently omitted.
|
|
52
|
+
*/
|
|
53
|
+
getCommitsMeta(repoPath: string, shas: readonly string[]): Promise<CommitMeta[]>;
|
|
54
|
+
/**
|
|
55
|
+
* `git rev-list include ^exclude ...` — SHAs reachable from `include` but
|
|
56
|
+
* none of `excludes`, parent-first (oldest first). Empty on any git error.
|
|
57
|
+
*/
|
|
58
|
+
revListShas(repoPath: string, include: string, excludes: readonly string[]): Promise<string[]>;
|
|
59
|
+
/** `git merge-base --is-ancestor sha ref` — true when sha is reachable from ref. */
|
|
60
|
+
isAncestor(repoPath: string, sha: string, ref: string): Promise<boolean>;
|
|
35
61
|
private static parseSections;
|
|
36
62
|
}
|
|
@@ -116,6 +116,100 @@ export class GitClient {
|
|
|
116
116
|
return null;
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Branch reflog entries, newest first: [{sha (new value of the ref),
|
|
121
|
+
* ts (when the move happened), message}]. Every branch-tip move —
|
|
122
|
+
* commit, amend, rebase finish, reset, merge — writes exactly one entry,
|
|
123
|
+
* so consecutive entries form the complete old→new transition journal.
|
|
124
|
+
* Empty array when the branch has no reflog (core.logAllRefUpdates off).
|
|
125
|
+
*/
|
|
126
|
+
async getBranchReflog(repoPath, branch, count) {
|
|
127
|
+
try {
|
|
128
|
+
const { stdout } = await execAsync(`git -C "${repoPath}" reflog show "${branch}" -${count} --format="%H|%gd|%gs" --date=unix`, { maxBuffer: GIT_MAX_BUFFER_BYTES, windowsHide: true });
|
|
129
|
+
const entries = [];
|
|
130
|
+
for (const line of stdout.split('\n')) {
|
|
131
|
+
const match = line.match(/^([0-9a-f]{40})\|.*@\{(\d+)\}\|(.*)$/);
|
|
132
|
+
if (!match)
|
|
133
|
+
continue;
|
|
134
|
+
entries.push({ sha: match[1], ts: parseInt(match[2], 10), message: match[3] });
|
|
135
|
+
}
|
|
136
|
+
return entries;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Batched commit metadata. Works for unreachable SHAs too (squashed-away
|
|
144
|
+
* commits stay in the object db until gc — reflog entries protect them),
|
|
145
|
+
* which is exactly what transition replay needs. SHAs whose objects are
|
|
146
|
+
* gone are silently omitted.
|
|
147
|
+
*/
|
|
148
|
+
async getCommitsMeta(repoPath, shas) {
|
|
149
|
+
if (shas.length === 0)
|
|
150
|
+
return [];
|
|
151
|
+
const metas = [];
|
|
152
|
+
// Chunk to keep the command line comfortably short.
|
|
153
|
+
for (let i = 0; i < shas.length; i += 50) {
|
|
154
|
+
const chunk = shas.slice(i, i + 50);
|
|
155
|
+
let stdout;
|
|
156
|
+
try {
|
|
157
|
+
({ stdout } = await execAsync(`git -C "${repoPath}" show -s --format="%H|%T|%P|%ae|%at|%ct" ${chunk.join(' ')}`, { maxBuffer: GIT_MAX_BUFFER_BYTES, windowsHide: true }));
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// One bad SHA fails the whole batch — retry individually, skip the dead.
|
|
161
|
+
stdout = '';
|
|
162
|
+
for (const sha of chunk) {
|
|
163
|
+
try {
|
|
164
|
+
const single = await execAsync(`git -C "${repoPath}" show -s --format="%H|%T|%P|%ae|%at|%ct" ${sha}`, { maxBuffer: GIT_MAX_BUFFER_BYTES, windowsHide: true });
|
|
165
|
+
stdout += single.stdout + '\n';
|
|
166
|
+
}
|
|
167
|
+
catch { /* object gone — skip */ }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const line of stdout.split('\n')) {
|
|
171
|
+
const parts = line.trim().split('|');
|
|
172
|
+
if (parts.length !== 6 || !/^[0-9a-f]{40}$/.test(parts[0]))
|
|
173
|
+
continue;
|
|
174
|
+
metas.push({
|
|
175
|
+
sha: parts[0],
|
|
176
|
+
tree: parts[1],
|
|
177
|
+
parentCount: parts[2] === '' ? 0 : parts[2].split(' ').length,
|
|
178
|
+
authorEmail: parts[3],
|
|
179
|
+
authorTs: parseInt(parts[4], 10),
|
|
180
|
+
committerTs: parseInt(parts[5], 10),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return metas;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* `git rev-list include ^exclude ...` — SHAs reachable from `include` but
|
|
188
|
+
* none of `excludes`, parent-first (oldest first). Empty on any git error.
|
|
189
|
+
*/
|
|
190
|
+
async revListShas(repoPath, include, excludes) {
|
|
191
|
+
const excludeArgs = excludes.map(e => `"^${e}"`).join(' ');
|
|
192
|
+
try {
|
|
193
|
+
const { stdout } = await execAsync(`git -C "${repoPath}" rev-list --reverse ${include} ${excludeArgs}`, { maxBuffer: GIT_MAX_BUFFER_BYTES, windowsHide: true });
|
|
194
|
+
return stdout.split('\n').map(s => s.trim()).filter(s => /^[0-9a-f]{40}$/.test(s));
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/** `git merge-base --is-ancestor sha ref` — true when sha is reachable from ref. */
|
|
201
|
+
async isAncestor(repoPath, sha, ref) {
|
|
202
|
+
try {
|
|
203
|
+
await execAsync(`git -C "${repoPath}" merge-base --is-ancestor ${sha} ${ref}`, {
|
|
204
|
+
maxBuffer: GIT_MAX_BUFFER_BYTES,
|
|
205
|
+
windowsHide: true,
|
|
206
|
+
});
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
119
213
|
static parseSections(raw, withBase) {
|
|
120
214
|
const normalized = raw.replace(/\r\n/g, '\n');
|
|
121
215
|
// Windows echo may add trailing space: "---WORKDAY-SEP--- \n"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-client.js","sourceRoot":"","sources":["../../src/collectors/git-client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"git-client.js","sourceRoot":"","sources":["../../src/collectors/git-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppConfig, Secrets, PollResult, ReflogEntry, RepoTracker } from '../core/types.js';
|
|
1
|
+
import type { AppConfig, Secrets, PollResult, ReflogEntry, RepoTracker, LedgerQuery } from '../core/types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Main git activity tracker.
|
|
4
4
|
* Orchestrates GitClient, ReflogParser, SnapshotParser.
|
|
@@ -23,7 +23,7 @@ export declare class GitTracker {
|
|
|
23
23
|
* that base; otherwise the snapshot is null and SessionTracker is
|
|
24
24
|
* expected to capture currentHead as the new baseSha.
|
|
25
25
|
*/
|
|
26
|
-
pollAll(baseShas?: ReadonlyMap<string, string | null>): Promise<PollResult[]>;
|
|
26
|
+
pollAll(baseShas?: ReadonlyMap<string, string | null>, ledgerQueries?: ReadonlyMap<string, LedgerQuery | null>): Promise<PollResult[]>;
|
|
27
27
|
/** Get current state for a repo */
|
|
28
28
|
getRepoState(repoPath: string): RepoTracker | undefined;
|
|
29
29
|
/**
|
|
@@ -5,6 +5,7 @@ import { GitClient } from './git-client.js';
|
|
|
5
5
|
import { ReflogParser } from './reflog-parser.js';
|
|
6
6
|
import { SnapshotParser } from './snapshot-parser.js'; // static methods only
|
|
7
7
|
import { buildChurnFiles } from './churn-scanner.js';
|
|
8
|
+
import { collectLedgerUpdate } from './ledger-collector.js';
|
|
8
9
|
/**
|
|
9
10
|
* Final fallback list when no config and no `origin/HEAD` are available.
|
|
10
11
|
* Tried in order; the first ref that actually exists wins.
|
|
@@ -42,12 +43,13 @@ export class GitTracker {
|
|
|
42
43
|
* that base; otherwise the snapshot is null and SessionTracker is
|
|
43
44
|
* expected to capture currentHead as the new baseSha.
|
|
44
45
|
*/
|
|
45
|
-
async pollAll(baseShas) {
|
|
46
|
+
async pollAll(baseShas, ledgerQueries) {
|
|
46
47
|
const results = [];
|
|
47
48
|
for (const repoPath of this.config.repos) {
|
|
48
49
|
try {
|
|
49
50
|
const baseSha = baseShas?.get(repoPath) ?? null;
|
|
50
|
-
const
|
|
51
|
+
const ledgerQuery = ledgerQueries?.get(repoPath) ?? null;
|
|
52
|
+
const result = await this.pollRepo(repoPath, baseSha, ledgerQuery);
|
|
51
53
|
if (result !== null) {
|
|
52
54
|
results.push(result);
|
|
53
55
|
}
|
|
@@ -85,7 +87,7 @@ export class GitTracker {
|
|
|
85
87
|
* Poll a single repo.
|
|
86
88
|
* Returns null if branch is not developer's (skip this repo for now).
|
|
87
89
|
*/
|
|
88
|
-
async pollRepo(repoPath, baseSha) {
|
|
90
|
+
async pollRepo(repoPath, baseSha, ledgerQuery) {
|
|
89
91
|
const now = Date.now();
|
|
90
92
|
const defaultBranchRef = await this.resolveDefaultBranchRef(repoPath);
|
|
91
93
|
// Evidence base: fresh merge-base with the default branch (rebase-stable
|
|
@@ -145,6 +147,14 @@ export class GitTracker {
|
|
|
145
147
|
};
|
|
146
148
|
evidenceBasis = mergeBaseSha !== null ? 'merge_base' : 'base_sha';
|
|
147
149
|
}
|
|
150
|
+
// Commit ledger: replay branch-reflog transitions (exact per-operation
|
|
151
|
+
// accounting) or seed a fresh ledger. Only on developer branches with a
|
|
152
|
+
// resolved default branch + merge-base — everything else falls back to
|
|
153
|
+
// the positive-jump commit counter.
|
|
154
|
+
let ledgerUpdate = null;
|
|
155
|
+
if (task !== null && defaultBranchRef !== null && mergeBaseSha !== null) {
|
|
156
|
+
ledgerUpdate = await collectLedgerUpdate(this.gitClient, repoPath, raw.branch, mergeBaseSha, defaultBranchRef, ledgerQuery);
|
|
157
|
+
}
|
|
148
158
|
return {
|
|
149
159
|
repoPath,
|
|
150
160
|
branch: raw.branch,
|
|
@@ -156,6 +166,7 @@ export class GitTracker {
|
|
|
156
166
|
evidenceSnapshot,
|
|
157
167
|
evidenceBasis,
|
|
158
168
|
mergeBaseSha,
|
|
169
|
+
ledgerUpdate,
|
|
159
170
|
};
|
|
160
171
|
}
|
|
161
172
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-tracker.js","sourceRoot":"","sources":["../../src/collectors/git-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"git-tracker.js","sourceRoot":"","sources":["../../src/collectors/git-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { LedgerQuery, LedgerUpdate } from '../core/types.js';
|
|
2
|
+
import { GitClient } from './git-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the per-tick LedgerUpdate for a repo: seeds a fresh ledger when no
|
|
5
|
+
* session context exists yet, otherwise turns branch-reflog entries since
|
|
6
|
+
* the stored pointer into old→new transitions with full commit metadata.
|
|
7
|
+
*
|
|
8
|
+
* Everything is computed relative to the default branch: commits reachable
|
|
9
|
+
* from it are never "added" (upstream work entering via merge/rebase) and
|
|
10
|
+
* never "removed" (own work merged upstream survives squashes of the local
|
|
11
|
+
* branch).
|
|
12
|
+
*/
|
|
13
|
+
export declare function collectLedgerUpdate(gitClient: GitClient, repoPath: string, branch: string, mergeBaseSha: string, defaultBranchRef: string, query: LedgerQuery | null): Promise<LedgerUpdate | null>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reflog entries fetched per tick. Far above any realistic number of branch
|
|
3
|
+
* operations between two polls (or across a same-day daemon restart) — when
|
|
4
|
+
* the stored pointer still falls outside this window, the collector degrades
|
|
5
|
+
* to a resync instead of replaying.
|
|
6
|
+
*/
|
|
7
|
+
const REFLOG_WINDOW = 200;
|
|
8
|
+
/**
|
|
9
|
+
* Builds the per-tick LedgerUpdate for a repo: seeds a fresh ledger when no
|
|
10
|
+
* session context exists yet, otherwise turns branch-reflog entries since
|
|
11
|
+
* the stored pointer into old→new transitions with full commit metadata.
|
|
12
|
+
*
|
|
13
|
+
* Everything is computed relative to the default branch: commits reachable
|
|
14
|
+
* from it are never "added" (upstream work entering via merge/rebase) and
|
|
15
|
+
* never "removed" (own work merged upstream survives squashes of the local
|
|
16
|
+
* branch).
|
|
17
|
+
*/
|
|
18
|
+
export async function collectLedgerUpdate(gitClient, repoPath, branch, mergeBaseSha, defaultBranchRef, query) {
|
|
19
|
+
const reflog = await gitClient.getBranchReflog(repoPath, branch, REFLOG_WINDOW);
|
|
20
|
+
if (reflog.length === 0) {
|
|
21
|
+
// No branch reflog (core.logAllRefUpdates off) — ledger can't work here.
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const currentPointer = { sha: reflog[0].sha, ts: reflog[0].ts };
|
|
25
|
+
if (query === null || query.branch !== branch || query.pointer === null) {
|
|
26
|
+
return buildSeed(gitClient, repoPath, mergeBaseSha, currentPointer);
|
|
27
|
+
}
|
|
28
|
+
// Newest occurrence of the stored pointer. Entries above it are unprocessed.
|
|
29
|
+
const pointerIndex = reflog.findIndex(e => e.sha === query.pointer.sha && e.ts === query.pointer.ts);
|
|
30
|
+
if (pointerIndex === -1) {
|
|
31
|
+
// Pointer fell out of the window (long downtime / reflog expired) —
|
|
32
|
+
// rebuild flags from the current branch state instead of replaying.
|
|
33
|
+
return buildResync(gitClient, repoPath, mergeBaseSha, defaultBranchRef, query, currentPointer);
|
|
34
|
+
}
|
|
35
|
+
const transitions = [];
|
|
36
|
+
let oldSha = query.pointer.sha;
|
|
37
|
+
for (let i = pointerIndex - 1; i >= 0; i--) {
|
|
38
|
+
const entry = reflog[i];
|
|
39
|
+
if (entry.sha !== oldSha) {
|
|
40
|
+
const removedShas = await gitClient.revListShas(repoPath, oldSha, [entry.sha, defaultBranchRef]);
|
|
41
|
+
const addedShas = await gitClient.revListShas(repoPath, entry.sha, [oldSha, defaultBranchRef]);
|
|
42
|
+
const added = await gitClient.getCommitsMeta(repoPath, addedShas);
|
|
43
|
+
transitions.push({ ts: entry.ts, removedShas, added });
|
|
44
|
+
}
|
|
45
|
+
oldSha = entry.sha;
|
|
46
|
+
}
|
|
47
|
+
return { kind: 'transitions', transitions, pointer: currentPointer };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Fresh ledger: all commits currently on the branch (vs merge-base). The
|
|
51
|
+
* SessionTracker marks them pre-session at apply time — a new session always
|
|
52
|
+
* starts counting from zero.
|
|
53
|
+
*/
|
|
54
|
+
async function buildSeed(gitClient, repoPath, mergeBaseSha, pointer) {
|
|
55
|
+
const shas = await gitClient.revListShas(repoPath, 'HEAD', [mergeBaseSha]);
|
|
56
|
+
const commits = await gitClient.getCommitsMeta(repoPath, shas);
|
|
57
|
+
return { kind: 'seed', commits, pointer };
|
|
58
|
+
}
|
|
59
|
+
async function buildResync(gitClient, repoPath, mergeBaseSha, defaultBranchRef, query, pointer) {
|
|
60
|
+
const liveShas = await gitClient.revListShas(repoPath, 'HEAD', [mergeBaseSha]);
|
|
61
|
+
const liveSet = new Set(liveShas);
|
|
62
|
+
const mergedShas = [];
|
|
63
|
+
for (const sha of query.knownShas) {
|
|
64
|
+
if (!liveSet.has(sha) && await gitClient.isAncestor(repoPath, sha, defaultBranchRef)) {
|
|
65
|
+
mergedShas.push(sha);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const known = new Set(query.knownShas);
|
|
69
|
+
const unknownShas = liveShas.filter(sha => !known.has(sha));
|
|
70
|
+
const unknownCommits = await gitClient.getCommitsMeta(repoPath, unknownShas);
|
|
71
|
+
return { kind: 'resync', liveShas, mergedShas, unknownCommits, pointer };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=ledger-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-collector.js","sourceRoot":"","sources":["../../src/collectors/ledger-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CommitLedgerState, CommitMeta, LedgerUpdate } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Commit ledger — exact accounting of "how many commits did this session
|
|
4
|
+
* actually produce", robust to any git operation happening between polls.
|
|
5
|
+
*
|
|
6
|
+
* The 30-second poll can never reconstruct events from counter samples:
|
|
7
|
+
* commit + squash inside one tick shows a net jump of 0 or +1. So instead
|
|
8
|
+
* of counting, the ledger tracks commit *identities* and replays the branch
|
|
9
|
+
* reflog — a complete, persistent journal of every branch-tip move — one
|
|
10
|
+
* transition at a time. Each transition is small and unambiguous.
|
|
11
|
+
*
|
|
12
|
+
* The counter is strictly session-scoped: a fresh session starts at zero,
|
|
13
|
+
* seeded with everything already on the branch as pre-session, and nothing
|
|
14
|
+
* done outside a session (daemon down, session closed) is ever counted.
|
|
15
|
+
*
|
|
16
|
+
* Rewrite matching cascade for a commit that appears in a transition:
|
|
17
|
+
* 0. Known SHA → resurrect (reset back to an old tip).
|
|
18
|
+
* 1. Tree match → squash: the new commit's tree equals the tree
|
|
19
|
+
* of a commit removed earlier; it absorbs the whole chain removed in
|
|
20
|
+
* that same transition and inherits sessionCreated as OR over the
|
|
21
|
+
* chain. This is why squashing a session commit INTO a pre-session
|
|
22
|
+
* commit keeps the counter (the session's work survived, inside a
|
|
23
|
+
* rewritten commit), while squashing two session commits drops 2 → 1.
|
|
24
|
+
* 2. (authorEmail, authorTs) match → rebase pick / amend / reword: git
|
|
25
|
+
* preserves the author timestamp through these, so the rewritten
|
|
26
|
+
* commit inherits the original's membership. Rebasing pre-session
|
|
27
|
+
* commits does NOT count them (committer ts is fresh but the author
|
|
28
|
+
* identity says "old").
|
|
29
|
+
* 3. No match → genuinely new commit; counts when its
|
|
30
|
+
* committer timestamp falls after the session started (`isSessionTs`).
|
|
31
|
+
*
|
|
32
|
+
* Commits merged into the default branch never appear as "removed" (the
|
|
33
|
+
* collector excludes ^defaultRef), so merged work stays counted — it is
|
|
34
|
+
* the most real work of all.
|
|
35
|
+
*/
|
|
36
|
+
/** Number of live commits created within this session. */
|
|
37
|
+
export declare function countSessionCommits(state: CommitLedgerState): number;
|
|
38
|
+
/**
|
|
39
|
+
* Apply one poll's ledger update. `countsAsSession(meta)` decides whether an
|
|
40
|
+
* unmatched commit was created by this session — typically: committer
|
|
41
|
+
* timestamp after the session opened (minus a small slack, so the commit
|
|
42
|
+
* that itself triggered the session counts) and not already accounted for
|
|
43
|
+
* by an earlier session's ledger.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyLedgerUpdate(state: CommitLedgerState, update: LedgerUpdate, countsAsSession: (meta: CommitMeta) => boolean): void;
|
|
46
|
+
export declare function createEmptyLedger(): CommitLedgerState;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commit ledger — exact accounting of "how many commits did this session
|
|
3
|
+
* actually produce", robust to any git operation happening between polls.
|
|
4
|
+
*
|
|
5
|
+
* The 30-second poll can never reconstruct events from counter samples:
|
|
6
|
+
* commit + squash inside one tick shows a net jump of 0 or +1. So instead
|
|
7
|
+
* of counting, the ledger tracks commit *identities* and replays the branch
|
|
8
|
+
* reflog — a complete, persistent journal of every branch-tip move — one
|
|
9
|
+
* transition at a time. Each transition is small and unambiguous.
|
|
10
|
+
*
|
|
11
|
+
* The counter is strictly session-scoped: a fresh session starts at zero,
|
|
12
|
+
* seeded with everything already on the branch as pre-session, and nothing
|
|
13
|
+
* done outside a session (daemon down, session closed) is ever counted.
|
|
14
|
+
*
|
|
15
|
+
* Rewrite matching cascade for a commit that appears in a transition:
|
|
16
|
+
* 0. Known SHA → resurrect (reset back to an old tip).
|
|
17
|
+
* 1. Tree match → squash: the new commit's tree equals the tree
|
|
18
|
+
* of a commit removed earlier; it absorbs the whole chain removed in
|
|
19
|
+
* that same transition and inherits sessionCreated as OR over the
|
|
20
|
+
* chain. This is why squashing a session commit INTO a pre-session
|
|
21
|
+
* commit keeps the counter (the session's work survived, inside a
|
|
22
|
+
* rewritten commit), while squashing two session commits drops 2 → 1.
|
|
23
|
+
* 2. (authorEmail, authorTs) match → rebase pick / amend / reword: git
|
|
24
|
+
* preserves the author timestamp through these, so the rewritten
|
|
25
|
+
* commit inherits the original's membership. Rebasing pre-session
|
|
26
|
+
* commits does NOT count them (committer ts is fresh but the author
|
|
27
|
+
* identity says "old").
|
|
28
|
+
* 3. No match → genuinely new commit; counts when its
|
|
29
|
+
* committer timestamp falls after the session started (`isSessionTs`).
|
|
30
|
+
*
|
|
31
|
+
* Commits merged into the default branch never appear as "removed" (the
|
|
32
|
+
* collector excludes ^defaultRef), so merged work stays counted — it is
|
|
33
|
+
* the most real work of all.
|
|
34
|
+
*/
|
|
35
|
+
/** Number of live commits created within this session. */
|
|
36
|
+
export function countSessionCommits(state) {
|
|
37
|
+
let count = 0;
|
|
38
|
+
for (const commit of state.commits) {
|
|
39
|
+
if (commit.live && commit.sessionCreated)
|
|
40
|
+
count++;
|
|
41
|
+
}
|
|
42
|
+
return count;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Apply one poll's ledger update. `countsAsSession(meta)` decides whether an
|
|
46
|
+
* unmatched commit was created by this session — typically: committer
|
|
47
|
+
* timestamp after the session opened (minus a small slack, so the commit
|
|
48
|
+
* that itself triggered the session counts) and not already accounted for
|
|
49
|
+
* by an earlier session's ledger.
|
|
50
|
+
*/
|
|
51
|
+
export function applyLedgerUpdate(state, update, countsAsSession) {
|
|
52
|
+
switch (update.kind) {
|
|
53
|
+
case 'seed':
|
|
54
|
+
seedLedger(state, update.commits, countsAsSession);
|
|
55
|
+
break;
|
|
56
|
+
case 'transitions':
|
|
57
|
+
for (const transition of update.transitions) {
|
|
58
|
+
applyTransition(state, transition, countsAsSession);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 'resync':
|
|
62
|
+
applyResync(state, update.liveShas, update.mergedShas, update.unknownCommits, countsAsSession);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
state.pointer = update.pointer;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Seed a fresh ledger from the commits currently on the branch. Everything
|
|
69
|
+
* already there is pre-session (counter starts at zero) — except commits
|
|
70
|
+
* landing within the slack window right before the session opened, i.e. the
|
|
71
|
+
* commit that itself triggered the session.
|
|
72
|
+
*/
|
|
73
|
+
function seedLedger(state, commits, countsAsSession) {
|
|
74
|
+
for (const meta of commits) {
|
|
75
|
+
if (findCommit(state, meta.sha))
|
|
76
|
+
continue;
|
|
77
|
+
state.commits.push(newLedgerCommit(meta, meta.parentCount < 2 && countsAsSession(meta)));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function applyTransition(state, transition, countsAsSession) {
|
|
81
|
+
const seq = ++state.seq;
|
|
82
|
+
// 1. Commits that left the branch (and are not on the default branch).
|
|
83
|
+
for (const sha of transition.removedShas) {
|
|
84
|
+
const entry = findCommit(state, sha);
|
|
85
|
+
if (entry && entry.live) {
|
|
86
|
+
entry.live = false;
|
|
87
|
+
entry.removedAtSeq = seq;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 2. Commits that entered the branch, parent-first.
|
|
91
|
+
for (const meta of transition.added) {
|
|
92
|
+
const known = findCommit(state, meta.sha);
|
|
93
|
+
if (known) {
|
|
94
|
+
// Resurrect: reset back onto a previously-seen tip.
|
|
95
|
+
known.live = true;
|
|
96
|
+
known.removedAtSeq = null;
|
|
97
|
+
known.absorbedBy = null;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (meta.parentCount >= 2) {
|
|
101
|
+
// Merge commits are recorded but never counted as created work.
|
|
102
|
+
state.commits.push(newLedgerCommit(meta, false));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const pool = matchPool(state);
|
|
106
|
+
// Cascade 1: tree match → squash of the chain removed in one transition.
|
|
107
|
+
const treeMatch = pool.find(c => c.tree === meta.tree);
|
|
108
|
+
if (treeMatch) {
|
|
109
|
+
const chain = pool.filter(c => c.removedAtSeq === treeMatch.removedAtSeq);
|
|
110
|
+
const inherited = chain.some(c => c.sessionCreated);
|
|
111
|
+
for (const absorbed of chain)
|
|
112
|
+
absorbed.absorbedBy = meta.sha;
|
|
113
|
+
state.commits.push(newLedgerCommit(meta, inherited));
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
// Cascade 2: author identity match → rebase pick / amend / reword.
|
|
117
|
+
const authorMatch = pool.find(c => c.authorEmail === meta.authorEmail && c.authorTs === meta.authorTs);
|
|
118
|
+
if (authorMatch) {
|
|
119
|
+
authorMatch.absorbedBy = meta.sha;
|
|
120
|
+
state.commits.push(newLedgerCommit(meta, authorMatch.sessionCreated));
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
// Cascade 3: genuinely new commit. The countsAsSession test keeps
|
|
124
|
+
// commits resurrected from outside the session (e.g. reset --hard onto
|
|
125
|
+
// a tip built while the daemon was down) out of the counter.
|
|
126
|
+
state.commits.push(newLedgerCommit(meta, countsAsSession(meta)));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Pointer fell out of the reflog window — rebuild flags from current state
|
|
131
|
+
* instead of replaying. Known commits: live when still on the branch OR
|
|
132
|
+
* merged into the default branch. Unknown commits on the branch are adopted
|
|
133
|
+
* with the committer-timestamp session test (no lineage available).
|
|
134
|
+
*/
|
|
135
|
+
function applyResync(state, liveShas, mergedShas, unknownCommits, countsAsSession) {
|
|
136
|
+
const live = new Set(liveShas);
|
|
137
|
+
const merged = new Set(mergedShas);
|
|
138
|
+
for (const commit of state.commits) {
|
|
139
|
+
if (live.has(commit.sha)) {
|
|
140
|
+
commit.live = true;
|
|
141
|
+
commit.removedAtSeq = null;
|
|
142
|
+
commit.absorbedBy = null;
|
|
143
|
+
}
|
|
144
|
+
else if (!merged.has(commit.sha)) {
|
|
145
|
+
commit.live = false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
seedLedger(state, unknownCommits, countsAsSession);
|
|
149
|
+
}
|
|
150
|
+
/** Gone-but-unabsorbed commits — the pool rewrite matching runs against. */
|
|
151
|
+
function matchPool(state) {
|
|
152
|
+
return state.commits.filter(c => !c.live && c.absorbedBy === null);
|
|
153
|
+
}
|
|
154
|
+
function findCommit(state, sha) {
|
|
155
|
+
return state.commits.find(c => c.sha === sha);
|
|
156
|
+
}
|
|
157
|
+
function newLedgerCommit(meta, sessionCreated) {
|
|
158
|
+
return {
|
|
159
|
+
sha: meta.sha,
|
|
160
|
+
tree: meta.tree,
|
|
161
|
+
authorEmail: meta.authorEmail,
|
|
162
|
+
authorTs: meta.authorTs,
|
|
163
|
+
committerTs: meta.committerTs,
|
|
164
|
+
sessionCreated,
|
|
165
|
+
live: true,
|
|
166
|
+
removedAtSeq: null,
|
|
167
|
+
absorbedBy: null,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
export function createEmptyLedger() {
|
|
171
|
+
return { commits: [], pointer: null, seq: 0 };
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=commit-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit-ledger.js","sourceRoot":"","sources":["../../src/core/commit-ledger.ts"],"names":[],"mappings":"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"}
|
package/dist/core/daily-log.d.ts
CHANGED
|
@@ -48,6 +48,12 @@ export declare function computeDayStart(log: DailyLog, config: AppConfig): numbe
|
|
|
48
48
|
* this returns null when nothing meaningful is set yet, so the client can
|
|
49
49
|
* hide the indicator until the user either marks it manually or the first
|
|
50
50
|
* session reaches ACTIVE.
|
|
51
|
+
*
|
|
52
|
+
* The fallback is the EARLIEST `activatedAt` across all sessions (first
|
|
53
|
+
* CONFIRMED work), NOT `sessions[0]`. Array order follows repo discovery,
|
|
54
|
+
* so the first entry may be a session that activated much later — anchoring
|
|
55
|
+
* to it would push the indicator past the real start. This matches the
|
|
56
|
+
* upper-bound logic in `setDayManualStart`.
|
|
51
57
|
*/
|
|
52
58
|
export declare function resolveUiDayStart(log: DailyLog): string | null;
|
|
53
59
|
/** Compute day end timestamp (next day boundary) */
|