flowviant 0.92.0 → 0.93.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/README.md +2 -2
- package/bin/cli.mjs +7 -3
- package/bin/lib/agentPlan.mjs +53 -1
- package/bin/lib/childEnv.mjs +1 -0
- package/bin/lib/config.mjs +13 -1
- package/bin/lib/prompts.mjs +9 -1
- package/bin/lib/work.mjs +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ It shows a short code. Open your project's **Workbench** in Flowviant and enter
|
|
|
38
38
|
Prefer an explicit token? Create a machine credential in the app and pass it directly:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
|
|
41
|
+
FLOWVIANT_MACHINE_TOKEN=fva_… npx flowviant@latest # FLOWVIANT_FLEET still works
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
Launch with `@latest` so each start pulls the newest published version — a bare `npx flowviant` can reuse a stale cache. A running daemon also keeps itself current: from **0.58.0** it restarts itself through `npx flowviant@latest` when a new version ships, so npx launches stay up to date the same way a global install does. (Before 0.58.0 that was only true of a global install — under npx the daemon printed a notice and stayed put, which is how machines ended up sitting several releases back.) It only ever restarts when no turn is running. `FLOWVIANT_NO_UPDATE=1` makes it nag-only; `flowviant update` updates now.
|
|
@@ -65,7 +65,7 @@ The daemon never executes anything the repository declares. An earlier version r
|
|
|
65
65
|
|
|
66
66
|
| Env | What runs |
|
|
67
67
|
| --- | --- |
|
|
68
|
-
| _(stored login)_ or `FLOWVIANT_FLEET` | **the daemon** — the project's machine, serving its sessions |
|
|
68
|
+
| _(stored login)_ or `FLOWVIANT_MACHINE_TOKEN` (`FLOWVIANT_FLEET` still read) | **the daemon** — the project's machine, serving its sessions |
|
|
69
69
|
| `FLOWVIANT_SAFE=1` | restrict the toolset instead of running unattended |
|
|
70
70
|
|
|
71
71
|
## Not freezing the box
|
package/bin/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* ONE mode, one credential:
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* FLOWVIANT_MACHINE_TOKEN=fva_… npx flowviant@latest # the machine daemon, headless
|
|
9
9
|
*
|
|
10
10
|
* `FLOWVIANT_TOKEN` (one worker, current checkout) and `FLOWVIANT_TOKENS` (a
|
|
11
11
|
* comma list, one worktree each) stood beside it until 2026-08-19. Both ran the
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
* because a daemon on another computer is invisible from here.
|
|
47
47
|
*
|
|
48
48
|
* Env:
|
|
49
|
-
*
|
|
49
|
+
* FLOWVIANT_MACHINE_TOKEN the machine credential (or use `flowviant login`);
|
|
50
|
+
* `FLOWVIANT_FLEET` is the old name and still works.
|
|
50
51
|
* FLOWVIANT_API_URL default https://api.flowviant.com/api
|
|
51
52
|
* FLOWVIANT_MCP_URL default <API_URL>/mcp
|
|
52
53
|
* FLOWVIANT_FLEET_URL default <API_URL>/fleet/agents
|
|
@@ -358,7 +359,10 @@ const interactive = canPrompt() && process.env.FLOWVIANT_REEXEC !== '1';
|
|
|
358
359
|
* asked). What was left was a person reading a list being told "no answer
|
|
359
360
|
* in 60s — nothing started". A prompt a person can see waits for the
|
|
360
361
|
* person; tty.mjs's header carries the argument. */
|
|
361
|
-
const externalToken =
|
|
362
|
+
const externalToken =
|
|
363
|
+
process.argv.includes('--fleet') ||
|
|
364
|
+
Boolean(process.env.FLOWVIANT_MACHINE_TOKEN) ||
|
|
365
|
+
Boolean(process.env.FLOWVIANT_FLEET);
|
|
362
366
|
|
|
363
367
|
/** Re-exec a plain `flowviant` after an inline login — the login command's own
|
|
364
368
|
* pattern: config.mjs read the store at IMPORT time, before the credential
|
package/bin/lib/agentPlan.mjs
CHANGED
|
@@ -157,6 +157,35 @@ export function parseProposal(text) {
|
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
/**
|
|
161
|
+
* The running account, off whichever shape the turn ended with — `{ progress }`
|
|
162
|
+
* or nothing at all.
|
|
163
|
+
*
|
|
164
|
+
* A SPREAD RATHER THAN A FIELD, so an absent account produces no key on the
|
|
165
|
+
* result and therefore no key on the settle body. That is the whole contract
|
|
166
|
+
* with the server: absence means KEEP the last account, and an empty string
|
|
167
|
+
* sent instead would be indistinguishable from an agent saying the branch now
|
|
168
|
+
* amounts to nothing.
|
|
169
|
+
*
|
|
170
|
+
* AN ABSURDITY BOUND HERE, NOT THE DISPLAY CAP (corrected 2026-09-22, in
|
|
171
|
+
* review). This sliced to the wire's own 1000 first, which quietly INVERTED the
|
|
172
|
+
* order the caller's own comment claims to keep: `envScrub` replaces EXACT
|
|
173
|
+
* values, so handing it a paragraph already cut at 1000 hands it a credential
|
|
174
|
+
* cut in half — it matches nothing and the surviving prefix ships. The scrub is
|
|
175
|
+
* the only thing standing between a model that pasted a secret into its own
|
|
176
|
+
* summary and the wire, and a cap must never run ahead of it. So this is the
|
|
177
|
+
* same absurdity bound `summary` takes one line up (8000): enough that nothing
|
|
178
|
+
* a model writes reaches the caller unbounded, far enough above the 1000 the
|
|
179
|
+
* wire cuts to that the scrub always sees whole values. `work.mjs` scrubs and
|
|
180
|
+
* THEN cuts to 1000, and the server clamps again because the wire never trusts
|
|
181
|
+
* a machine to have clamped.
|
|
182
|
+
*/
|
|
183
|
+
const MAX_PROGRESS = 8000;
|
|
184
|
+
const progressOf = (v) => {
|
|
185
|
+
const t = typeof v.progress === 'string' ? v.progress.trim() : '';
|
|
186
|
+
return t ? { progress: t.slice(0, MAX_PROGRESS) } : {};
|
|
187
|
+
};
|
|
188
|
+
|
|
160
189
|
/**
|
|
161
190
|
* READING AN AGENT'S ANSWER at the end of a turn.
|
|
162
191
|
*
|
|
@@ -170,6 +199,28 @@ export function parseProposal(text) {
|
|
|
170
199
|
* `nothing`, which sends the agent to Stuck. Optimistic status from a machine
|
|
171
200
|
* that quit is the one lie this board cannot afford, so anything ambiguous ends
|
|
172
201
|
* up here rather than being read as success.
|
|
202
|
+
*
|
|
203
|
+
* ── AND IT CARRIES THE AGENT'S RUNNING ACCOUNT OF ITSELF (2026-09-22) ─────
|
|
204
|
+
*
|
|
205
|
+
* The owner: "we should add a brief summary of what the agent has done overall
|
|
206
|
+
* at the top that updates." `progress` is one more key on the SAME object —
|
|
207
|
+
* two or three cumulative sentences about the whole branch, rewritten fresh
|
|
208
|
+
* every turn — and it is read here because this is where everything the agent
|
|
209
|
+
* SAYS is already read. Nothing derives it: this file parses, it does not
|
|
210
|
+
* summarise, and a daemon that read the turn log and wrote its own paragraph
|
|
211
|
+
* would be the second brain the product forbids.
|
|
212
|
+
*
|
|
213
|
+
* ON BOTH SHAPES, because a turn that stopped to ask has still done work — an
|
|
214
|
+
* agent that built three quarters of a feature and then needed a decision is
|
|
215
|
+
* exactly the run whose account a person wants. It is NOT read off an
|
|
216
|
+
* unparseable turn, and that is not an omission: there is no object to read it
|
|
217
|
+
* from, and a `nothing` outcome means the CLI never got as far as saying
|
|
218
|
+
* anything about itself.
|
|
219
|
+
*
|
|
220
|
+
* MISSING IS MISSING. An older prompt, a resumed conversation that never saw
|
|
221
|
+
* the key, a model that dropped it — all of them leave it absent, and the
|
|
222
|
+
* caller omits the field rather than sending an empty string, so the server
|
|
223
|
+
* keeps the last account that was true instead of blanking the head.
|
|
173
224
|
*/
|
|
174
225
|
export function parseTurnResult(text) {
|
|
175
226
|
for (const v of candidateObjects(String(text ?? ''))) {
|
|
@@ -179,12 +230,13 @@ export function parseTurnResult(text) {
|
|
|
179
230
|
// parks an agent with nothing to reply to. Treated as `nothing`, which
|
|
180
231
|
// at least says truthfully that the machine went quiet.
|
|
181
232
|
if (!question) continue;
|
|
182
|
-
return { outcome: 'question', answer: question.slice(0, 8000) };
|
|
233
|
+
return { outcome: 'question', answer: question.slice(0, 8000), ...progressOf(v) };
|
|
183
234
|
}
|
|
184
235
|
if (v.status === 'delivered') {
|
|
185
236
|
return {
|
|
186
237
|
outcome: 'delivered',
|
|
187
238
|
answer: (typeof v.summary === 'string' ? v.summary : '').slice(0, 8000),
|
|
239
|
+
...progressOf(v),
|
|
188
240
|
raised: Array.isArray(v.raised)
|
|
189
241
|
? v.raised
|
|
190
242
|
.filter((r) => r && typeof r.title === 'string' && r.title.trim())
|
package/bin/lib/childEnv.mjs
CHANGED
|
@@ -160,6 +160,7 @@ export function childEnv({ cwd, extra, deploy = false } = {}) {
|
|
|
160
160
|
* purpose: the default is what almost every caller gets, and the sample is
|
|
161
161
|
* about the default. */
|
|
162
162
|
export const DROPPED_SAMPLE = [
|
|
163
|
+
'FLOWVIANT_MACHINE_TOKEN',
|
|
163
164
|
'FLOWVIANT_FLEET',
|
|
164
165
|
'FLOWVIANT_FLEET_URL',
|
|
165
166
|
'FLOWVIANT_API_URL',
|
package/bin/lib/config.mjs
CHANGED
|
@@ -290,8 +290,20 @@ export const PROCESS_STARTED_AT = new Date(
|
|
|
290
290
|
// ambiguous store with a picker, adoptStoredCredential updates every importer
|
|
291
291
|
// before the daemon touches the network. Everything before that point (the
|
|
292
292
|
// resolution, the flags) is settled synchronously at import, as it always was.
|
|
293
|
+
// THE VARIABLE IS NAMED FOR WHAT IT IS (2026-09-21): `FLOWVIANT_MACHINE_TOKEN`.
|
|
294
|
+
// The owner met `FLOWVIANT_FLEET=… npx flowviant` in the app's headless
|
|
295
|
+
// credential panel and asked "what is flowviant fleet?" — a fair question,
|
|
296
|
+
// because a FLEET was a pool of worker lanes deleted 2026-08-19 and the word
|
|
297
|
+
// now names nothing a person can see. `FLOWVIANT_FLEET` stays as the fallback
|
|
298
|
+
// forever: a CI runner somewhere may have it in its secrets, and a rename that
|
|
299
|
+
// silently stops a headless box from authenticating is the substitution class
|
|
300
|
+
// this codebase floors everything against.
|
|
293
301
|
export let FLEET_TOKEN =
|
|
294
|
-
argFlag('--fleet') ||
|
|
302
|
+
argFlag('--fleet') ||
|
|
303
|
+
process.env.FLOWVIANT_MACHINE_TOKEN ||
|
|
304
|
+
process.env.FLOWVIANT_FLEET ||
|
|
305
|
+
CREDENTIAL.entry?.fleetToken ||
|
|
306
|
+
'';
|
|
295
307
|
|
|
296
308
|
/**
|
|
297
309
|
* WHICH PROJECT THIS DAEMON SERVES, or null when nothing on this box names one.
|
package/bin/lib/prompts.mjs
CHANGED
|
@@ -777,6 +777,7 @@ END YOUR TURN WITH ONE JSON OBJECT AND NOTHING AFTER IT, in a \`\`\`json fence:
|
|
|
777
777
|
{
|
|
778
778
|
"status": "delivered",
|
|
779
779
|
"summary": "one or two sentences on what you actually changed",
|
|
780
|
+
"progress": "two or three sentences on what you have done on this branch SO FAR, across every card",
|
|
780
781
|
"raised": [{ "title": "short title", "brief": "what is wrong and what you did" }]
|
|
781
782
|
}
|
|
782
783
|
\`\`\`
|
|
@@ -786,13 +787,20 @@ or, if you are stopping to ask:
|
|
|
786
787
|
\`\`\`json
|
|
787
788
|
{
|
|
788
789
|
"status": "blocked",
|
|
790
|
+
"progress": "two or three sentences on what you have done on this branch SO FAR, across every card",
|
|
789
791
|
"question": "the specific thing you need decided, in one or two sentences"
|
|
790
792
|
}
|
|
791
793
|
\`\`\`
|
|
792
794
|
|
|
793
795
|
"raised" is optional and only for work you did that was NOT this card. Do not
|
|
794
796
|
list the card itself there. Do not put commit shas in the summary — they are
|
|
795
|
-
read from git
|
|
797
|
+
read from git.
|
|
798
|
+
|
|
799
|
+
"progress" is REQUIRED on both shapes. It is the running account a person reads
|
|
800
|
+
at the top of this run, and it REPLACES the previous one whole — so write it
|
|
801
|
+
fresh every turn, covering everything you have done on this branch so far and
|
|
802
|
+
not only this card. Past tense, plain sentences, no commit shas and no card ids.
|
|
803
|
+
"summary" is about this one card; "progress" is about the branch.`;
|
|
796
804
|
|
|
797
805
|
/**
|
|
798
806
|
* The turn itself.
|
package/bin/lib/work.mjs
CHANGED
|
@@ -5062,6 +5062,32 @@ export function createWorkManager({
|
|
|
5062
5062
|
...(commits.length ? { commits } : {}),
|
|
5063
5063
|
...(res.raised?.length ? { raised: res.raised } : {}),
|
|
5064
5064
|
...(usage ? { usage } : {}),
|
|
5065
|
+
/**
|
|
5066
|
+
* THE AGENT'S RUNNING ACCOUNT OF THIS BRANCH (2026-09-22).
|
|
5067
|
+
*
|
|
5068
|
+
* The owner: "we should add a brief summary of what the agent has done
|
|
5069
|
+
* overall at the top that updates." A RELAY — the agent wrote it in its
|
|
5070
|
+
* own final JSON object and nothing here composes, narrows or infers
|
|
5071
|
+
* one. It rides only this settle, which is the one that follows a
|
|
5072
|
+
* PARSED result: the two `nothing` settles above it come from a turn
|
|
5073
|
+
* that declared no outcome at all, so there is no account to carry and
|
|
5074
|
+
* inventing one would be the machine speaking for the agent.
|
|
5075
|
+
*
|
|
5076
|
+
* SCRUBBED BEFORE IT IS CUT, the order that matters and the one the
|
|
5077
|
+
* check's output lane learned the expensive way: `envScrub` replaces
|
|
5078
|
+
* EXACT values, so a paragraph capped first hands the scrub a
|
|
5079
|
+
* credential already cut in half — it matches nothing and the surviving
|
|
5080
|
+
* prefix ships. `parseTurnResult` trims it and bounds it for absurdity
|
|
5081
|
+
* at 8000, DELIBERATELY above the 1000 below, so this slice is the
|
|
5082
|
+
* first one a value of any interest meets and the scrub has already
|
|
5083
|
+
* run when it does. The first cut of this feature bounded the parser at
|
|
5084
|
+
* 1000 as well, which read identically and quietly put the cap first.
|
|
5085
|
+
*
|
|
5086
|
+
* OMITTED WHEN THE TURN DID NOT WRITE ONE, never sent empty. Absence is
|
|
5087
|
+
* the server's signal to KEEP the last account that was true; an empty
|
|
5088
|
+
* string would blank the head because a model dropped a key.
|
|
5089
|
+
*/
|
|
5090
|
+
...(res.progress ? { progress: envScrub(res.progress).slice(0, 1000) } : {}),
|
|
5065
5091
|
branch,
|
|
5066
5092
|
worktree: wt,
|
|
5067
5093
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowviant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.93.0",
|
|
4
4
|
"description": "Run your own coding CLIs as build agents for Flowviant \u2014 Claude Code, Codex or Antigravity, on your own credentials. Holds your sessions, keeps a worktree per tab, and ships branches on your word.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|