flowviant 0.8.0 → 0.8.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.
@@ -4,7 +4,7 @@ import { readFileSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
  import { homedir } from 'node:os';
6
6
 
7
- export const VERSION = '0.8.0';
7
+ export const VERSION = '0.8.1';
8
8
 
9
9
  // Credential stored by `flowviant login` (device auth) — the no-token,
10
10
  // no-env-var path. An explicit --fleet flag or FLOWVIANT_FLEET env still wins.
package/bin/lib/live.mjs CHANGED
@@ -302,14 +302,26 @@ export async function runLiveTask({ mcpUrl, token, cwd, baseRef, isAlive, resume
302
302
  let nudges = 0;
303
303
  let held = false; // asked to stop — park for direction, don't nudge
304
304
 
305
+ // Liveness heartbeat: stream_turn refreshes the lease, but a long stretch of
306
+ // silent tool work streams no text — the app would read "stalled" while the
307
+ // agent is grinding. Beat at most once a minute on ANY session activity.
308
+ let lastBeat = Date.now();
309
+ const beat = () => {
310
+ if (Date.now() - lastBeat < 60_000) return;
311
+ lastBeat = Date.now();
312
+ void mcpCall(mcpUrl, token, 'heartbeat', { runId }).catch(() => {});
313
+ };
314
+
305
315
  const flush = async () => {
306
- if (turnId && turnText.trim())
316
+ if (turnId && turnText.trim()) {
317
+ lastBeat = Date.now(); // stream_turn refreshes the lease itself
307
318
  await mcpCall(mcpUrl, token, 'stream_turn', {
308
319
  runId,
309
320
  turnId,
310
321
  text: turnText.trim(),
311
322
  createdAt: turnAt,
312
323
  }).catch(() => {});
324
+ }
313
325
  };
314
326
  const inject = (msgs) => {
315
327
  afterId = msgs[msgs.length - 1].id;
@@ -319,6 +331,7 @@ export async function runLiveTask({ mcpUrl, token, cwd, baseRef, isAlive, resume
319
331
  try {
320
332
  for await (const m of session) {
321
333
  if (!isAlive()) return { outcome: 'blocked', title, intentId };
334
+ beat(); // any session traffic = alive (throttled to 1/min)
322
335
 
323
336
  if (m.type === 'assistant') {
324
337
  if (!turnId) {
@@ -471,7 +484,16 @@ export async function runLiveWorker({
471
484
  const cfg = loadPreviewConfig(cwd);
472
485
  const kind = cfg?.ui ? 'ui' : cfg?.api ? 'api' : null;
473
486
  const entry = kind ? cfg[kind] : null;
474
- if (!entry || !intentId) return; // no preview config → captured evidence only
487
+ if (!entry || !intentId) {
488
+ // Say WHY there's no preview instead of skipping silently — this was a
489
+ // real "where's my preview?" support case.
490
+ info(
491
+ `${label} ${c.dim(
492
+ 'no live preview: add .flowviant/preview.json ({"ui":{"cmd":"npm run dev","port":5173}}) — the framework could not be inferred from package.json.'
493
+ )}`
494
+ );
495
+ return;
496
+ }
475
497
  info(`${label} ${c.dim('starting a live preview of the branch for review…')}`);
476
498
  preview = await startPreview({
477
499
  worktree: cwd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowviant",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Run your own Claude Code as headless build agents for Flowviant — 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": {