flowviant 0.28.0 → 0.28.2
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/claude.mjs +51 -14
- package/bin/lib/deploy.mjs +20 -5
- package/bin/lib/fleet.mjs +6 -1
- package/package.json +2 -2
package/bin/lib/claude.mjs
CHANGED
|
@@ -130,25 +130,62 @@ Ground EVERY claim in files you actually read (Read, Grep, Glob, ls, git in the
|
|
|
130
130
|
repo) — never guess.
|
|
131
131
|
|
|
132
132
|
THE HUMAN DOCS — docs/ inside the vault. After the vault pages are current,
|
|
133
|
-
COMPILE
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- docs/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
COMPILE professional developer documentation FROM them (distill your own vault
|
|
134
|
+
pages; spot-check a cited file only when something looks off — don't re-read the
|
|
135
|
+
whole repo). These are what a new engineer onboards from and a working engineer
|
|
136
|
+
keeps open: hold them to the standard of Stripe / Google / Microsoft developer
|
|
137
|
+
docs — comprehensive, precisely structured, richly cross-linked. Detailed and
|
|
138
|
+
thorough beats short: a reader should be able to work in a subsystem after
|
|
139
|
+
reading its chapter.
|
|
140
|
+
|
|
141
|
+
Fixed spine (numeric prefix = reading order):
|
|
142
|
+
- docs/00-start-here.md — the landing page + MASTER TABLE OF CONTENTS: what the
|
|
143
|
+
product is (2-3 sentences); how to run it locally (prerequisites, install,
|
|
144
|
+
required env, dev server, tests); then a linked table of contents of EVERY
|
|
145
|
+
chapter, each with a one-line description; then 2-3 role-based reading paths
|
|
146
|
+
(e.g. "New to the backend: read 01, then 12, then 14").
|
|
147
|
+
- docs/01-architecture.md — the system at a glance: a Mermaid diagram (a fenced
|
|
148
|
+
code block whose language is mermaid) of the major components and how they
|
|
149
|
+
connect, a component-responsibility table, the primary request/data flows, and
|
|
150
|
+
a link into the chapter for each component.
|
|
151
|
+
- docs/1N-<chapter>.md — ONE chapter per major subsystem (10, 11, 12 …), your
|
|
152
|
+
choice of chapters, derived from the vault's hub pages. Cover every significant
|
|
153
|
+
subsystem.
|
|
154
|
+
- docs/90-decisions.md — notable design decisions, each as context, decision,
|
|
155
|
+
why, and consequences.
|
|
156
|
+
- docs/91-glossary.md — the project's terms of art, alphabetized, each linking to
|
|
157
|
+
the chapter or vault page that defines it.
|
|
158
|
+
|
|
159
|
+
EVERY chapter follows this exact anatomy, in order:
|
|
160
|
+
1. YAML frontmatter listing the real repo files the chapter draws on.
|
|
161
|
+
2. A "# Title" heading.
|
|
162
|
+
3. One or two sentences: what the chapter covers and who should read it.
|
|
163
|
+
4. A "## Contents" section — an in-page table of contents: a bulleted list
|
|
164
|
+
linking each of the chapter's own "## " sections by anchor. An anchor is the
|
|
165
|
+
heading text lowercased, spaces turned to hyphens, punctuation removed — so
|
|
166
|
+
a section "## How dispatch works" is linked "- [How dispatch works](#how-dispatch-works)".
|
|
167
|
+
5. The body sections ("## " / "### "), including as relevant: an overview and
|
|
168
|
+
where the subsystem sits in the system; how it works walked step by step
|
|
169
|
+
with REAL code excerpts (fenced and language-tagged) and file citations; a
|
|
170
|
+
Mermaid diagram for any non-trivial flow or sequence; and REFERENCE TABLES
|
|
171
|
+
for the concrete surface — HTTP endpoints (method, path, auth, purpose), key
|
|
172
|
+
functions/types, env/config keys, DB tables/columns — as markdown tables.
|
|
173
|
+
6. A "## Gotchas" section: the traps, edge cases, invariants, and non-obvious
|
|
174
|
+
constraints.
|
|
175
|
+
7. A "## See also" section: [[wikilinks]] to the deeper vault pages, plus
|
|
176
|
+
relative links to sibling chapters (e.g. "[Architecture](01-architecture.md)").
|
|
177
|
+
|
|
178
|
+
Cross-link liberally: [[wikilinks]] point to vault pages; relative "NN-name.md"
|
|
179
|
+
links point to sibling chapters; both are clickable in the reader. Keep every
|
|
180
|
+
claim grounded in code you actually read.
|
|
146
181
|
|
|
147
182
|
Full-sweep protocol:
|
|
148
183
|
1. If the vault already has pages, read index.md + log.md FIRST — update and
|
|
149
184
|
extend rather than rewrite; delete vault pages whose code no longer exists.
|
|
150
185
|
2. Explore the repo broadly, then write/refresh pages area by area.
|
|
151
|
-
3. Compile/refresh the docs/ chapters from the finished vault pages
|
|
186
|
+
3. Compile/refresh the docs/ chapters from the finished vault pages, following
|
|
187
|
+
the docs spine + per-chapter anatomy above (Contents TOC, reference tables,
|
|
188
|
+
Mermaid diagrams, Gotchas, See also).
|
|
152
189
|
4. Refresh index.md, append a log.md entry, then output exactly WIKI_DONE on
|
|
153
190
|
its own line and stop.
|
|
154
191
|
|
package/bin/lib/deploy.mjs
CHANGED
|
@@ -60,14 +60,19 @@ export async function reportDeployConfig(repoRoot) {
|
|
|
60
60
|
const targets = readDeployConfig(repoRoot);
|
|
61
61
|
const json = JSON.stringify(targets);
|
|
62
62
|
if (json === lastConfigJson) return;
|
|
63
|
-
//
|
|
63
|
+
// Scrub command strings before the server sees them — a command line can embed
|
|
64
|
+
// an internal host or a synced secret. Only redacted metadata leaves the box.
|
|
65
|
+
const scrubCmds = (o) =>
|
|
66
|
+
o && typeof o === 'object'
|
|
67
|
+
? Object.fromEntries(Object.entries(o).map(([k, v]) => [k, scrub(String(v ?? ''))]))
|
|
68
|
+
: o;
|
|
64
69
|
const meta = targets.map((t) => ({
|
|
65
70
|
id: t.id,
|
|
66
71
|
label: t.label,
|
|
67
72
|
provider: t.provider || 'cloudflare',
|
|
68
|
-
command: t.command,
|
|
69
|
-
build: t.build,
|
|
70
|
-
commands: t.commands,
|
|
73
|
+
command: scrub(String(t.command ?? '')),
|
|
74
|
+
build: t.build ? scrub(String(t.build)) : t.build,
|
|
75
|
+
commands: scrubCmds(t.commands),
|
|
71
76
|
healthcheck: t.healthcheck,
|
|
72
77
|
healthStatus: t.healthStatus,
|
|
73
78
|
pushSecrets: t.pushSecrets,
|
|
@@ -100,6 +105,11 @@ function run(command, { cwd, env, input }) {
|
|
|
100
105
|
/* already gone */
|
|
101
106
|
}
|
|
102
107
|
}, 30 * 60_000);
|
|
108
|
+
// A broken pipe (child exits before draining stdin — e.g. a fast-failing
|
|
109
|
+
// `wrangler secret put`) surfaces as an ASYNC 'error' on the stdin stream,
|
|
110
|
+
// which the try/catch below can't catch. Without a listener it's an uncaught
|
|
111
|
+
// exception that kills the whole daemon. Swallow it.
|
|
112
|
+
child.stdin.on('error', () => {});
|
|
103
113
|
if (input != null) {
|
|
104
114
|
try {
|
|
105
115
|
child.stdin.write(input);
|
|
@@ -129,7 +139,7 @@ async function verifyHealth(url, status) {
|
|
|
129
139
|
for (let i = 0; i < 4; i++) {
|
|
130
140
|
try {
|
|
131
141
|
const res = await fetch(url, { signal: AbortSignal.timeout(10_000), redirect: 'manual' });
|
|
132
|
-
if (res.status === status) return true;
|
|
142
|
+
if (res.status === Number(status)) return true; // coerce — a string "200" in deploy.json must still match
|
|
133
143
|
} catch {
|
|
134
144
|
/* not up yet */
|
|
135
145
|
}
|
|
@@ -148,6 +158,10 @@ const claiming = new Set(); // in-flight guard (single-flight per daemon process
|
|
|
148
158
|
export function processDeployJobs(jobs, ctx) {
|
|
149
159
|
if (!Array.isArray(jobs) || !jobs.length) return;
|
|
150
160
|
for (const job of jobs) {
|
|
161
|
+
// Defend against a malformed roster element — `job.id` on a null would throw
|
|
162
|
+
// synchronously here (outside the per-job try below) and wedge the whole
|
|
163
|
+
// reconcile loop, since this runs unguarded from the fleet tick.
|
|
164
|
+
if (!job || typeof job.id !== 'string') continue;
|
|
151
165
|
if (claiming.has(job.id)) continue;
|
|
152
166
|
claiming.add(job.id);
|
|
153
167
|
void (async () => {
|
|
@@ -185,6 +199,7 @@ export function processDeployJobs(jobs, ctx) {
|
|
|
185
199
|
|
|
186
200
|
async function runDeploy(job, target, ctx) {
|
|
187
201
|
const env = { ...process.env, ...deployCreds() }; // inject infra creds; never a file
|
|
202
|
+
delete env.FLEET_TOKEN; // the deploy command has no business reading it; keep it out of a command that might echo its env
|
|
188
203
|
const logs = [];
|
|
189
204
|
// Rollback is a single wrangler command; deploy is build → secrets → deploy.
|
|
190
205
|
if (job.kind === 'rollback') {
|
package/bin/lib/fleet.mjs
CHANGED
|
@@ -295,6 +295,7 @@ export async function runFleetDaemon() {
|
|
|
295
295
|
};
|
|
296
296
|
const processMergeJobs = (jobs) => {
|
|
297
297
|
for (const job of jobs ?? []) {
|
|
298
|
+
if (!job || typeof job.id !== 'string') continue; // a null element would wedge the loop
|
|
298
299
|
if (merging.has(job.id)) continue;
|
|
299
300
|
merging.add(job.id);
|
|
300
301
|
(async () => {
|
|
@@ -374,6 +375,7 @@ export async function runFleetDaemon() {
|
|
|
374
375
|
const cleaning = new Set();
|
|
375
376
|
const processCleanupJobs = (jobs) => {
|
|
376
377
|
for (const job of jobs ?? []) {
|
|
378
|
+
if (!job || typeof job.id !== 'string') continue; // a null element would wedge the loop
|
|
377
379
|
if (cleaning.has(job.id)) continue;
|
|
378
380
|
cleaning.add(job.id);
|
|
379
381
|
(async () => {
|
|
@@ -889,7 +891,10 @@ export async function runFleetDaemon() {
|
|
|
889
891
|
// turn) until we report reground-done; the bare drain flushes anything
|
|
890
892
|
// whose earlier mint failed.
|
|
891
893
|
enqueueSweep(roster.codeMapJob);
|
|
892
|
-
for (const j of roster.regroundJobs ?? [])
|
|
894
|
+
for (const j of roster.regroundJobs ?? []) {
|
|
895
|
+
if (!j || typeof j.intentId !== 'string') continue; // a null element would throw + wedge the loop
|
|
896
|
+
enqueueReground(j.intentId, j.prUrl, j.title);
|
|
897
|
+
}
|
|
893
898
|
void drainWiki();
|
|
894
899
|
|
|
895
900
|
// Env sync tick: register/bootstrap/wrap/rotate/sync as the roster block
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowviant",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.2",
|
|
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": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"homepage": "https://flowviant.com",
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
33
|
-
"url": "https://github.com/flowviant/cli.git"
|
|
33
|
+
"url": "git+https://github.com/flowviant/cli.git"
|
|
34
34
|
},
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"bugs": {
|