flowviant 0.48.0 → 0.48.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/bin/lib/work.mjs +19 -0
- package/bin/lib/worktreeDiff.mjs +33 -2
- package/package.json +1 -1
package/bin/lib/work.mjs
CHANGED
|
@@ -259,7 +259,15 @@ export function createWorkManager({ repoRoot, baseDir, baseRef, getMcpUrl, getLe
|
|
|
259
259
|
* narrator: never awaited by a turn, every failure swallowed.
|
|
260
260
|
*/
|
|
261
261
|
const WORKTREE_SWEEP_MS = 60_000;
|
|
262
|
+
/** How often the sweep refreshes `origin/<base>` before measuring. The
|
|
263
|
+
* behind-count is the whole point of the readout — "someone pushed while you
|
|
264
|
+
* were working" — and without a fetch it would only ever count what this
|
|
265
|
+
* machine already happened to have. Rarer than the sweep because a fetch is
|
|
266
|
+
* network, and a teammate's push being visible within three minutes is the
|
|
267
|
+
* same promise the rest of the product makes. */
|
|
268
|
+
const WORKTREE_FETCH_MS = 3 * 60_000;
|
|
262
269
|
let lastWorktreeSweep = 0;
|
|
270
|
+
let lastWorktreeFetch = 0;
|
|
263
271
|
let sweepingWorktrees = false;
|
|
264
272
|
const postWorktrees = async (reports) => {
|
|
265
273
|
if (!reports.length) return;
|
|
@@ -297,6 +305,17 @@ export function createWorkManager({ repoRoot, baseDir, baseRef, getMcpUrl, getLe
|
|
|
297
305
|
lastWorktreeSweep = Date.now();
|
|
298
306
|
void (async () => {
|
|
299
307
|
try {
|
|
308
|
+
// Refresh the base before measuring, so "3 new on main" means what a
|
|
309
|
+
// person thinks it means. Throttled, best-effort, and never fatal: an
|
|
310
|
+
// offline machine reports the counts it can still compute.
|
|
311
|
+
if (Date.now() - lastWorktreeFetch >= WORKTREE_FETCH_MS) {
|
|
312
|
+
lastWorktreeFetch = Date.now();
|
|
313
|
+
try {
|
|
314
|
+
git(['fetch', 'origin', '--quiet'], repoRoot);
|
|
315
|
+
} catch {
|
|
316
|
+
/* offline, or no remote — the numbers just age */
|
|
317
|
+
}
|
|
318
|
+
}
|
|
300
319
|
const reports = [];
|
|
301
320
|
for (const id of activeIds.slice(0, 20)) {
|
|
302
321
|
const r = sessionWorktreeReport(id);
|
package/bin/lib/worktreeDiff.mjs
CHANGED
|
@@ -44,8 +44,10 @@ function countLines(buf) {
|
|
|
44
44
|
/**
|
|
45
45
|
* @param {string} wt the worktree directory
|
|
46
46
|
* @param {string} baseRef the project's base ref (e.g. `origin/main`)
|
|
47
|
-
* @returns {null | {branch:string, path:string, ahead:number,
|
|
48
|
-
*
|
|
47
|
+
* @returns {null | {branch:string, path:string, ahead:number, behind:number,
|
|
48
|
+
* baseLabel:string, baseCommits:{sha:string, subject:string, author:string}[],
|
|
49
|
+
* dirty:boolean, additions:number, deletions:number, fileCount:number,
|
|
50
|
+
* truncated:number,
|
|
49
51
|
* files:{path:string, added:number, deleted:number, binary?:boolean}[]}}
|
|
50
52
|
*/
|
|
51
53
|
export function worktreeDiff(wt, baseRef) {
|
|
@@ -121,6 +123,32 @@ export function worktreeDiff(wt, baseRef) {
|
|
|
121
123
|
} catch {
|
|
122
124
|
/* leave at 0 */
|
|
123
125
|
}
|
|
126
|
+
// WHAT LANDED WHILE YOU WERE WORKING. Not the branch's own history — the
|
|
127
|
+
// commits on BASE that this worktree doesn't have, which is the thing a
|
|
128
|
+
// person cannot see from inside their own session and the reason they end up
|
|
129
|
+
// rebasing onto a surprise. Freshness is the caller's job: these are only as
|
|
130
|
+
// current as the last fetch (reportWorktrees throttles one).
|
|
131
|
+
let behind = 0;
|
|
132
|
+
const baseCommits = [];
|
|
133
|
+
try {
|
|
134
|
+
behind = Number(git(['rev-list', '--count', `HEAD..${baseRef}`], wt)) || 0;
|
|
135
|
+
if (behind > 0) {
|
|
136
|
+
// %x1f is the unit separator — a subject can contain anything a person
|
|
137
|
+
// can type, tabs and pipes included, so the delimiter must be one that
|
|
138
|
+
// cannot appear in it.
|
|
139
|
+
const raw = git(
|
|
140
|
+
['log', '-n', '3', '--format=%h%x1f%s%x1f%an', `HEAD..${baseRef}`],
|
|
141
|
+
wt
|
|
142
|
+
);
|
|
143
|
+
for (const line of raw.split('\n')) {
|
|
144
|
+
if (!line.trim()) continue;
|
|
145
|
+
const [sha, subject, author] = line.split('\x1f');
|
|
146
|
+
if (sha) baseCommits.push({ sha, subject: subject ?? '', author: author ?? '' });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
} catch {
|
|
150
|
+
/* an unfetched or missing base — say nothing rather than "you're current" */
|
|
151
|
+
}
|
|
124
152
|
let dirty = false;
|
|
125
153
|
try {
|
|
126
154
|
dirty = git(['status', '--porcelain'], wt) !== '';
|
|
@@ -137,6 +165,9 @@ export function worktreeDiff(wt, baseRef) {
|
|
|
137
165
|
branch,
|
|
138
166
|
path: wt,
|
|
139
167
|
ahead,
|
|
168
|
+
behind,
|
|
169
|
+
baseLabel: String(baseRef).replace(/^origin\//, ''),
|
|
170
|
+
baseCommits,
|
|
140
171
|
dirty,
|
|
141
172
|
additions,
|
|
142
173
|
deletions,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowviant",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.1",
|
|
4
4
|
"description": "Run your own coding CLIs as headless build agents for Flowviant — Claude Code or Codex, on your own credentials. Claims dispatched work, opens PRs, captures review evidence, and routes questions back to you.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|