opencode-plugin-flow 4.3.9 → 5.0.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/CHANGELOG.md +84 -0
- package/README.md +59 -48
- package/dist/application/errors.d.ts +5 -0
- package/dist/{runtime/api.d.ts → application/flow-service.d.ts} +89 -57
- package/dist/application/ports/session-repository.d.ts +11 -0
- package/dist/{runtime → application}/schema.d.ts +291 -371
- package/dist/cli.js +283 -2773
- package/dist/cli.js.map +7 -6
- package/dist/config-shared.d.ts +30 -16
- package/dist/config.d.ts +1 -1
- package/dist/distribution/legacy-cleanup.d.ts +25 -0
- package/dist/domain/feature-id.d.ts +3 -0
- package/dist/domain/limits.d.ts +1 -0
- package/dist/domain/orchestration-policy.d.ts +27 -0
- package/dist/domain/session.d.ts +181 -0
- package/dist/domain/transitions.d.ts +80 -0
- package/dist/guidance/catalog.d.ts +18 -0
- package/dist/guidance/ids.d.ts +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2676 -1929
- package/dist/index.js.map +24 -16
- package/dist/infrastructure/fs/session-repository.d.ts +2 -0
- package/dist/infrastructure/fs/workspace-flow-service.d.ts +9 -0
- package/dist/{runtime → infrastructure/fs}/workspace.d.ts +10 -14
- package/dist/infrastructure/system/transition-environment.d.ts +2 -0
- package/dist/platform/opencode/config.d.ts +2 -0
- package/dist/{adapters → platform}/opencode/plugin.d.ts +1 -1
- package/dist/{adapters → platform}/opencode/sdk.d.ts +0 -1
- package/dist/platform/opencode/tools.d.ts +6 -0
- package/dist/prompt-baseline-fixtures.d.ts +19 -0
- package/dist/prompt-model-evaluation.d.ts +88 -0
- package/dist/prompt-quality.d.ts +73 -0
- package/dist/prompt-surfaces.d.ts +28 -0
- package/dist/version.d.ts +1 -0
- package/package.json +19 -12
- package/dist/adapters/opencode/config.d.ts +0 -3
- package/dist/adapters/opencode/tools.d.ts +0 -322
- package/dist/distribution/flow-skill-definitions.d.ts +0 -9
- package/dist/distribution/sync.d.ts +0 -69
- package/dist/runtime/time.d.ts +0 -2
- package/dist/runtime/transitions.d.ts +0 -230
- /package/dist/{runtime/json/strict-object.d.ts → infrastructure/fs/strict-json-object.d.ts} +0 -0
- /package/dist/{adapters → platform}/opencode/logging.d.ts +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,2772 +1,347 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/distribution/
|
|
3
|
+
// src/distribution/legacy-cleanup.ts
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Status meanings:
|
|
27
|
-
|
|
28
|
-
- \`success\`: the assigned scope was covered, or any skipped items are explicitly
|
|
29
|
-
immaterial to the assigned question.
|
|
30
|
-
- \`partial\`: useful evidence was gathered, but material assigned scope remains
|
|
31
|
-
unchecked or unresolved.
|
|
32
|
-
- \`blocked\`: the worker cannot answer the assigned question without missing
|
|
33
|
-
access, input, dependencies, or manager clarification.
|
|
34
|
-
|
|
35
|
-
## Evidence, review, validation, or audit worker report
|
|
36
|
-
|
|
37
|
-
Use this for \`flow-evidence-worker\`, \`flow-reviewer\`,
|
|
38
|
-
\`flow-validation-worker\`, and \`flow-audit-worker\`.
|
|
39
|
-
|
|
40
|
-
\`\`\`markdown
|
|
41
|
-
## Status
|
|
42
|
-
success | partial | blocked
|
|
43
|
-
|
|
44
|
-
## Scope
|
|
45
|
-
<owned slice: path set, module, command, risk lens, route, data range, or question set>
|
|
46
|
-
|
|
47
|
-
## Pass metadata
|
|
48
|
-
- Pass id: <stable pass id from the manifest>
|
|
49
|
-
- Manifest row id: <row id from the manifest>
|
|
50
|
-
- Depends on: <upstream row ids or "none">
|
|
51
|
-
- Write scope: <none | manager-serial | exact-path | isolated-worktree | mixed>
|
|
52
|
-
|
|
53
|
-
## Coverage
|
|
54
|
-
- Expected: <files, ranges, questions, commands, or findings assigned>
|
|
55
|
-
- Checked: <actual coverage, for example "12/12 files" or "command not run">
|
|
56
|
-
- Not checked: <items skipped with reason, or "none">
|
|
57
|
-
|
|
58
|
-
## Findings or facts
|
|
59
|
-
- [high|med|low] <claim>; evidence: <file:line | command summary | screenshot path | URL | metric>; corroboration: <N sources or "single source">
|
|
60
|
-
- [high|med|low] <claim>; evidence: <...>; corroboration: <...>
|
|
61
|
-
|
|
62
|
-
## Sources
|
|
63
|
-
- <paths read, commands run, docs fetched, data ranges covered, screenshots inspected>
|
|
64
|
-
|
|
65
|
-
## Confidence and verification
|
|
66
|
-
- Verified: <claims directly re-run, recounted, traced, or cross-checked>
|
|
67
|
-
- Single-source: <claims with exactly one supporting source>
|
|
68
|
-
- Inferred: <claims derived from surrounding evidence rather than directly observed>
|
|
69
|
-
- Unsettled: <claims, sources, or citations that could not be resolved>
|
|
70
|
-
- Falsifier or missing input: <what would overturn or materially change the result>
|
|
71
|
-
|
|
72
|
-
## Open questions / gaps
|
|
73
|
-
- <ambiguity, missing source, contradiction, skipped item, or out-of-scope dependency>
|
|
74
|
-
|
|
75
|
-
## Manager follow-ups
|
|
76
|
-
- <concrete next tasks, verifier claims, validation commands, or Flow plan targets>
|
|
77
|
-
\`\`\`
|
|
78
|
-
|
|
79
|
-
Validation workers must include exact command names and raw outcome summaries
|
|
80
|
-
for commands they actually ran. Audit workers must include guards checked for
|
|
81
|
-
any blocking-severity candidate. Review workers must separate blocking findings
|
|
82
|
-
from advisory notes. In the shared \`Findings or facts\` section, review workers
|
|
83
|
-
should prefix review items with \`blocking:\` or \`advisory:\` before the claim.
|
|
84
|
-
|
|
85
|
-
Example evidence quality:
|
|
86
|
-
|
|
87
|
-
- Good fact: \`[high] public Flow command prompts include bundled instructions;
|
|
88
|
-
evidence: src/config-shared.ts:135; corroboration: single source\`.
|
|
89
|
-
- Weak fact: \`[high] prompts look self-contained; evidence: read the config\`.
|
|
90
|
-
- Good validation: \`bun test tests/distribution-and-surface.test.ts\`, status
|
|
91
|
-
passed, summary \`surface tests passed and covered bundled command prompts\`.
|
|
92
|
-
- Weak validation: \`tests pass\`, with no command, status, or raw outcome.
|
|
93
|
-
|
|
94
|
-
## Verifier worker report
|
|
95
|
-
|
|
96
|
-
Use this for \`flow-verifier-worker\`. Give it atomic claims and the cited sources
|
|
97
|
-
or commands. Do not include the generator's reasoning unless that reasoning is
|
|
98
|
-
the thing being verified, and do not say which worker produced the claim.
|
|
99
|
-
|
|
100
|
-
\`\`\`markdown
|
|
101
|
-
## Status
|
|
102
|
-
success | partial | blocked
|
|
103
|
-
|
|
104
|
-
## Scope
|
|
105
|
-
<claim ids, sources or commands checked, and the acceptance question>
|
|
106
|
-
|
|
107
|
-
## Pass metadata
|
|
108
|
-
- Pass id: <stable pass id from the manifest>
|
|
109
|
-
- Manifest row id: <row id from the manifest>
|
|
110
|
-
- Depends on: <upstream row ids or "none">
|
|
111
|
-
|
|
112
|
-
## Verdict per claim
|
|
113
|
-
- <claim id>: verdict=<supported | partly-supported | unsupported | source-not-found>
|
|
114
|
-
- claim: <claim text>
|
|
115
|
-
- evidence: <supporting snippet, path plus line, measured value, command result, or "none">
|
|
116
|
-
- source resolution: <URL, path, or command plus whether it resolved>
|
|
117
|
-
- confidence level: high | med | low
|
|
118
|
-
- recommended action: <keep, narrow, rewrite, or remove>
|
|
119
|
-
|
|
120
|
-
## Overall
|
|
121
|
-
<accept | revise | reject> because <brief reason>
|
|
122
|
-
|
|
123
|
-
## Gaps
|
|
124
|
-
- <unavailable source, ambiguous claim wording, missing oracle, or check not run>
|
|
125
|
-
|
|
126
|
-
## Manager follow-ups
|
|
127
|
-
- <narrow recheck, plan adjustment, review finding, or none>
|
|
128
|
-
\`\`\`
|
|
129
|
-
|
|
130
|
-
## Candidate implementation worker report
|
|
131
|
-
|
|
132
|
-
Use this only with explicit user authorization, in an isolated worktree or an
|
|
133
|
-
exact non-overlapping path-owned slice assigned by the manager.
|
|
134
|
-
|
|
135
|
-
\`\`\`markdown
|
|
136
|
-
## Status
|
|
137
|
-
success | partial | blocked
|
|
138
|
-
|
|
139
|
-
## Scope
|
|
140
|
-
<isolated worktree or exact path-owned slice>
|
|
141
|
-
|
|
142
|
-
## Pass metadata
|
|
143
|
-
- Pass id: <stable pass id from the manifest>
|
|
144
|
-
- Manifest row id: <row id from the manifest>
|
|
145
|
-
- Depends on: <upstream row ids or "none">
|
|
146
|
-
- Write scope: <exact-path | isolated-worktree>
|
|
147
|
-
|
|
148
|
-
## Changed or proposed patch
|
|
149
|
-
- <path>: <what changed and why>
|
|
150
|
-
|
|
151
|
-
## Coverage
|
|
152
|
-
- Assigned: <owned files/modules>
|
|
153
|
-
- Touched: <files changed or proposed>
|
|
154
|
-
- Skipped: <anything assigned but not changed and why, or "none">
|
|
155
|
-
|
|
156
|
-
## Verification
|
|
157
|
-
live-verified | test-verified | type-check-only | not-verified
|
|
158
|
-
- <command, observed outcome, pass/fail counts, or manual check>
|
|
159
|
-
|
|
160
|
-
## Confidence and risk
|
|
161
|
-
- Checked directly: <behavior, files, or commands verified by the worker>
|
|
162
|
-
- Still open: <tests, review paths, or integration points the manager must cover>
|
|
163
|
-
- Risk: low | medium | high -- <why>
|
|
164
|
-
|
|
165
|
-
## Merge notes
|
|
166
|
-
- <conflicts, nearby user changes, assumptions, or deviations>
|
|
167
|
-
|
|
168
|
-
## Manager follow-ups
|
|
169
|
-
- <merge, reject, rerun check, verifier pass, or replan task>
|
|
170
|
-
\`\`\`
|
|
171
|
-
|
|
172
|
-
The manager must inspect and validate any candidate patch before recording Flow
|
|
173
|
-
completion.
|
|
174
|
-
|
|
175
|
-
## Manager pass accounting record
|
|
176
|
-
|
|
177
|
-
The manager, not the worker, may carry compact records into
|
|
178
|
-
\`flow_feature_complete.orchestrationPasses\`. Use one record per material pass or
|
|
179
|
-
implementation decision; keep handoffs and long artifacts outside \`.flow/**\`.
|
|
180
|
-
The candidate accounting rules — which \`candidateEligibility\`,
|
|
181
|
-
\`candidateDecision\`, and \`decision\` combinations validate, and what counts as
|
|
182
|
-
candidate execution evidence — live in
|
|
183
|
-
[parallel-orchestration.md](parallel-orchestration.md) under "Implementation
|
|
184
|
-
pass decision"; note \`decision: "parallel"\` is not valid on
|
|
185
|
-
\`implementation-decision\` records.
|
|
186
|
-
|
|
187
|
-
\`\`\`json
|
|
188
|
-
{
|
|
189
|
-
"id": "stable-pass-id",
|
|
190
|
-
"kind": "discovery | audit | review | validation | verification | candidate | implementation-decision",
|
|
191
|
-
"decision": "serial | parallel | candidate-exact-path | candidate-worktree | tournament | skipped",
|
|
192
|
-
"decisionReason": "why this pass shape was chosen",
|
|
193
|
-
"candidateEligibility": "eligible | not_eligible | unknown",
|
|
194
|
-
"candidateDecision": "used | skipped | serial_required",
|
|
195
|
-
"decisionFactors": [
|
|
196
|
-
"shared_state",
|
|
197
|
-
"overlapping_files",
|
|
198
|
-
"small_slice",
|
|
199
|
-
"needs_manager_judgment",
|
|
200
|
-
"independent_surface",
|
|
201
|
-
"validation_available"
|
|
202
|
-
],
|
|
203
|
-
"modes": ["evidence"],
|
|
204
|
-
"workerCount": 1,
|
|
205
|
-
"candidateWorkerCount": 0,
|
|
206
|
-
"verifierWorkerCount": 0,
|
|
207
|
-
"sliceIds": ["manifest-row-id"],
|
|
208
|
-
"dependsOn": [],
|
|
209
|
-
"writeScope": "none | manager-serial | exact-path | isolated-worktree | mixed",
|
|
210
|
-
"handoffRefs": ["/tmp/flow-handoff.md"],
|
|
211
|
-
"verificationStatus": "not-needed | pending | passed | failed | mixed | downgraded",
|
|
212
|
-
"outcome": "accepted | modified | rejected | partial | not-covered | superseded",
|
|
213
|
-
"synthesisRef": "/tmp/flow-synthesis.md"
|
|
214
|
-
}
|
|
215
|
-
\`\`\`
|
|
216
|
-
`;
|
|
217
|
-
|
|
218
|
-
// skills/flow/references/parallel-orchestration.md
|
|
219
|
-
var parallel_orchestration_default = `# Parallel orchestration
|
|
220
|
-
|
|
221
|
-
Use fan-out when Flow work is broad enough that independent workers can gather
|
|
222
|
-
evidence faster than one linear pass. The manager still owns the Flow session:
|
|
223
|
-
only the manager calls state-changing Flow tools, approves plans, completes
|
|
224
|
-
features, records reviews, or closes sessions.
|
|
225
|
-
|
|
226
|
-
Every parallel pass runs the same loop:
|
|
227
|
-
|
|
228
|
-
**orient → slice → manifest → fan out → account → verify → synthesize →
|
|
229
|
-
extend or stop.**
|
|
230
|
-
|
|
231
|
-
This file is the whole playbook; read it once and run the pass. Two companions
|
|
232
|
-
stay separate:
|
|
233
|
-
|
|
234
|
-
- \`handoff-format.md\` holds the worker response templates. The manager pastes
|
|
235
|
-
the matching template verbatim into every worker prompt.
|
|
236
|
-
- \`parallel-pass-example.md\` walks one concrete end-to-end pass (synced with
|
|
237
|
-
the \`flow\` skill; not bundled into commands).
|
|
238
|
-
|
|
239
|
-
## Choose a pass
|
|
240
|
-
|
|
241
|
-
| Situation | Flow pass | Output the manager may synthesize |
|
|
242
|
-
| --- | --- | --- |
|
|
243
|
-
| Repo shape is unclear before planning | Discovery pass | Requirements, decisions, targets, validation entries, or a review-first feature |
|
|
244
|
-
| A broad finding set needs refutation | Audit pass | Surviving findings with guards checked and gaps named |
|
|
245
|
-
| Changed files or risk lenses are too broad for one review pass | Review pass | One feature review packet or \`finalReview\` payload owned by the manager |
|
|
246
|
-
| Test strategy or route coverage is unclear | Validation pass | Candidate commands or authorized raw command evidence |
|
|
247
|
-
| A claim is single-source, surprising, high-stakes, or payload-bound | Verification pass | Per-claim keep, narrow, rewrite, or remove decisions |
|
|
248
|
-
| Multiple implementation paths are plausible | Candidate pass | Candidate patches inspected and validated by the manager before use |
|
|
249
|
-
|
|
250
|
-
Pass notes:
|
|
251
|
-
|
|
252
|
-
- **Discovery**: workers read specific modules, routes, docs, commands, or risk
|
|
253
|
-
lenses; only evidenced claims become plan fields.
|
|
254
|
-
- **Audit**: workers actively look for guards, lifecycle resets, deployment
|
|
255
|
-
constraints, and counterexamples before reporting a finding. A finding
|
|
256
|
-
without refutation work stays advisory or becomes a follow-up question.
|
|
257
|
-
- **Review**: workers separate blocking findings from advisory notes; the
|
|
258
|
-
manager resolves conflicts and returns one review payload.
|
|
259
|
-
- **Validation**: workers run only manager-authorized commands and report the
|
|
260
|
-
exact command, status, and raw outcome summary.
|
|
261
|
-
- **Verification**: verifiers judge atomic claims against cited sources or
|
|
262
|
-
commands; do not ask a verifier to redesign the work or review the whole
|
|
263
|
-
feature.
|
|
264
|
-
- **Candidate**: only with explicit user authorization plus isolated worktrees
|
|
265
|
-
or exact non-overlapping path ownership. Patches stay proposals until the
|
|
266
|
-
manager inspects, merges or rejects, and validates.
|
|
267
|
-
|
|
268
|
-
## Implementation pass decision
|
|
269
|
-
|
|
270
|
-
Before implementing a broad, risky, or multi-target feature, record one manager
|
|
271
|
-
decision. This is required even when the answer is "stay serial"; the point is
|
|
272
|
-
to make the skipped parallelism visible instead of relying on memory.
|
|
273
|
-
|
|
274
|
-
First classify candidate eligibility:
|
|
275
|
-
|
|
276
|
-
- \`eligible\`: at least one slice is independent enough for a candidate worker.
|
|
277
|
-
- \`not_eligible\`: worker isolation would not make the implementation safer or
|
|
278
|
-
cheaper because the slice shares state, files, tests, or one mental model.
|
|
279
|
-
- \`unknown\`: orientation did not produce enough evidence to classify; use this
|
|
280
|
-
only for non-decision pass rows or legacy low-signal records, not for
|
|
281
|
-
\`implementation-decision\` records and not as a substitute for judgment.
|
|
282
|
-
|
|
283
|
-
Then record the candidate decision:
|
|
284
|
-
|
|
285
|
-
- \`used\`: candidate workers were used or a candidate pass carried the work.
|
|
286
|
-
- \`skipped\`: candidates were eligible, but the manager chose serial anyway.
|
|
287
|
-
This is the underused-parallelism signal counted by Flow status; use it only
|
|
288
|
-
on \`kind: "implementation-decision"\` records.
|
|
289
|
-
- \`serial_required\`: candidates were not eligible, so serial work was the
|
|
290
|
-
correct implementation shape. Use it only on \`kind: "implementation-decision"\`
|
|
291
|
-
records.
|
|
292
|
-
|
|
293
|
-
Use one of these decisions:
|
|
294
|
-
|
|
295
|
-
- \`serial\`: the manager implements directly because slices overlap, the next
|
|
296
|
-
edit depends on one shared contract, or prompt/merge overhead would exceed the
|
|
297
|
-
value. Pair unsafe or not-useful worker cases with
|
|
298
|
-
\`candidateEligibility: "not_eligible"\` and
|
|
299
|
-
\`candidateDecision: "serial_required"\`.
|
|
300
|
-
- \`candidate-exact-path\`: one or more candidate workers may edit exact
|
|
301
|
-
non-overlapping paths or modules named by the manager.
|
|
302
|
-
- \`candidate-worktree\`: one or more candidate workers may edit in isolated
|
|
303
|
-
worktrees, then the manager inspects and merges or rejects.
|
|
304
|
-
- \`tournament\`: several isolated candidate implementations compete for the same
|
|
305
|
-
outcome; the manager filters by tests, review, and source inspection before
|
|
306
|
-
accepting one.
|
|
307
|
-
- Candidate-shaped decisions (\`candidate-exact-path\`, \`candidate-worktree\`,
|
|
308
|
-
\`tournament\`) require candidate execution evidence on the same record:
|
|
309
|
-
\`kind: "candidate"\`, \`modes\` includes \`candidate-implementation\`, or
|
|
310
|
-
\`candidateWorkerCount > 0\`. The same evidence rule applies to
|
|
311
|
-
\`candidateDecision: "used"\`. Non-decision candidate rows (for example
|
|
312
|
-
\`kind: "candidate"\`) may omit \`decision\`; \`implementation-decision\` rows must
|
|
313
|
-
always set one, and when \`candidateDecision\` is \`"used"\` that decision must
|
|
314
|
-
be candidate-shaped — never \`serial\`, \`parallel\`, or \`skipped\`.
|
|
315
|
-
- \`parallel\` describes multi-worker read or audit passes (discovery, audit,
|
|
316
|
-
review); it is not a valid \`implementation-decision\` value. Implementation
|
|
317
|
-
decisions use \`serial\`, \`skipped\`, or a candidate-shaped decision.
|
|
318
|
-
- \`skipped\`: candidate workers were eligible but the manager chose serial
|
|
319
|
-
anyway; pair this with \`candidateEligibility: "eligible"\` and
|
|
320
|
-
\`candidateDecision: "skipped"\`. Do not use \`skipped\` for shared fixtures,
|
|
321
|
-
shared API contracts, unclear ownership, or other unsafe worker cases; use
|
|
322
|
-
\`serial\` plus \`serial_required\` for those.
|
|
323
|
-
|
|
324
|
-
Use structured \`decisionFactors\` alongside prose \`decisionReason\`:
|
|
325
|
-
\`shared_state\`, \`overlapping_files\`, \`small_slice\`,
|
|
326
|
-
\`needs_manager_judgment\`, \`independent_surface\`, and
|
|
327
|
-
\`validation_available\`. Serial-required records usually cite
|
|
328
|
-
\`shared_state\`, \`overlapping_files\`, or \`needs_manager_judgment\`; eligible
|
|
329
|
-
records usually cite \`independent_surface\` and \`validation_available\`, with
|
|
330
|
-
\`small_slice\` explaining an eligible-but-skipped choice.
|
|
331
|
-
|
|
332
|
-
### Worker decision rubric
|
|
333
|
-
|
|
334
|
-
Default to considering candidate workers when:
|
|
335
|
-
|
|
336
|
-
- the plan has three or more features.
|
|
337
|
-
- features touch separate surfaces such as frontend, core, docs, release
|
|
338
|
-
scripts, tests, or bindings.
|
|
339
|
-
- validation can run per slice.
|
|
340
|
-
- the work is mostly additive or localized.
|
|
341
|
-
- the final manager can review, apply, adapt, or reject the result safely.
|
|
342
|
-
|
|
343
|
-
Prefer serial when:
|
|
344
|
-
|
|
345
|
-
- one tight invariant crosses shared files.
|
|
346
|
-
- migrations, persistence, storage, or lifecycle semantics require one mental
|
|
347
|
-
model.
|
|
348
|
-
- tests require iterative local debugging in one checkout.
|
|
349
|
-
- multiple slices would edit the same files or fixtures.
|
|
350
|
-
- the slice is so small that prompt, handoff, merge, and verification overhead
|
|
351
|
-
costs more than direct work.
|
|
352
|
-
|
|
353
|
-
Record the decision in the pass manifest with a stable pass id,
|
|
354
|
-
\`candidateEligibility\`, \`candidateDecision\`, \`decisionFactors\`,
|
|
355
|
-
\`decisionReason\`, \`writeScope\`, expected verification, and where any handoff or
|
|
356
|
-
synthesis artifact will live. If the feature completes, include the compact
|
|
357
|
-
record in the \`orchestrationPasses\` array of the \`flow_feature_complete\`
|
|
358
|
-
payload. The runtime stores only compact accounting; full worker handoffs stay
|
|
359
|
-
in manager-owned scratch files or the conversation.
|
|
360
|
-
|
|
361
|
-
## When to stay serial
|
|
362
|
-
|
|
363
|
-
- One file, command, or design question determines the next step.
|
|
364
|
-
- Slices would share the same contracts, fixtures, or edit targets.
|
|
365
|
-
- The manager can inspect the full scope faster than writing and checking
|
|
366
|
-
worker prompts.
|
|
367
|
-
- The result would still need the same manual synthesis with no time saved.
|
|
368
|
-
|
|
369
|
-
Do not fan out to keep agents busy. Every worker should reduce a named
|
|
370
|
-
planning, validation, review, audit, or implementation uncertainty. A normal
|
|
371
|
-
first pass is two to five workers with independent slices; use more only when
|
|
372
|
-
the manifest stays countable and non-overlapping.
|
|
373
|
-
|
|
374
|
-
## Modes
|
|
375
|
-
|
|
376
|
-
When fanning out Flow work, select the matching hidden Flow agent by name. These
|
|
377
|
-
workers are injected by the plugin config; invoke the named worker when it is
|
|
378
|
-
available. Do not use generic subagents for Flow slices because Flow workers
|
|
379
|
-
carry the permission boundaries for each mode.
|
|
380
|
-
|
|
381
|
-
| Mode | Use agent | Worker output | Write access | Flow tools |
|
|
382
|
-
| --- | --- | --- | --- | --- |
|
|
383
|
-
| \`evidence\` | \`flow-evidence-worker\` | Coverage, facts, files inspected, confidence, gaps, suggested plan targets | No | \`flow_status\` only if needed |
|
|
384
|
-
| \`review\` | \`flow-reviewer\` | Coverage, candidate findings or review slice summary, confidence, gaps | No | \`flow_status\` only if needed |
|
|
385
|
-
| \`validation\` | \`flow-validation-worker\` | Command options or manager-authorized raw output, coverage, confidence, gaps | No code edits; commands only when explicitly allowed | \`flow_status\` only if needed |
|
|
386
|
-
| \`audit\` | \`flow-audit-worker\` | Refuted or surviving finding candidates, guards checked, confidence, gaps | No | \`flow_status\` only if needed |
|
|
387
|
-
| \`verifier\` | \`flow-verifier-worker\` | Per-claim verdicts against cited evidence or commands | No | \`flow_status\` only if needed |
|
|
388
|
-
| \`candidate-implementation\` | \`flow-candidate-worker\` | Candidate patch summary from an isolated worktree or exact path-owned slice | Only with explicit user authorization plus isolation or exact non-overlapping path ownership | No state-changing Flow tools |
|
|
389
|
-
|
|
390
|
-
Use worker-specific model routing where the installation can support it:
|
|
391
|
-
\`OPENCODE_FLOW_READONLY_WORKER_MODEL\` for evidence, validation, and audit
|
|
392
|
-
workers; \`OPENCODE_FLOW_REVIEW_WORKER_MODEL\` for reviewer and verifier workers;
|
|
393
|
-
\`OPENCODE_FLOW_CANDIDATE_WORKER_MODEL\` for candidate implementation workers; and
|
|
394
|
-
\`OPENCODE_FLOW_WORKER_MODEL\` as a fallback for all hidden Flow workers. Model IDs
|
|
395
|
-
are OpenCode installation-specific (\`provider/model\`), so leave these unset when
|
|
396
|
-
the configured provider is unknown. Spend stronger models where being wrong is
|
|
397
|
-
expensive; read-heavy discovery slices tolerate the cheapest configured option,
|
|
398
|
-
while verifier and review slices deserve the strongest.
|
|
399
|
-
|
|
400
|
-
## Permission contract
|
|
401
|
-
|
|
402
|
-
The plugin injects these hidden workers with the following permission values.
|
|
403
|
-
\`Flow state tools\` means the \`flow_*\` rule, while \`Flow status\` documents the
|
|
404
|
-
explicit \`flow_status\` exception.
|
|
405
|
-
|
|
406
|
-
| Worker | Edit | Bash | Task | Skill | Flow state tools | Flow status |
|
|
407
|
-
| --- | --- | --- | --- | --- | --- | --- |
|
|
408
|
-
| \`flow-reviewer\` | deny | deny | deny | deny | deny | allow |
|
|
409
|
-
| \`flow-evidence-worker\` | deny | deny | deny | deny | deny | allow |
|
|
410
|
-
| \`flow-validation-worker\` | deny | ask | deny | deny | deny | allow |
|
|
411
|
-
| \`flow-audit-worker\` | deny | ask | deny | deny | deny | allow |
|
|
412
|
-
| \`flow-candidate-worker\` | ask | ask | deny | deny | deny | allow |
|
|
413
|
-
| \`flow-verifier-worker\` | deny | ask | deny | deny | deny | allow |
|
|
414
|
-
|
|
415
|
-
Do not fan out parallel \`flow_plan_save\`, \`flow_plan_approve\`,
|
|
416
|
-
\`flow_run_start\`, \`flow_feature_complete\`, \`flow_feature_reset\`, or
|
|
417
|
-
\`flow_session_close\` calls. Runtime locking protects files, but Flow accepts only
|
|
418
|
-
one active feature result at a time.
|
|
419
|
-
|
|
420
|
-
Workers may read files, inspect docs, run authorized read-only commands, and
|
|
421
|
-
summarize evidence. Candidate implementation workers may edit only when the
|
|
422
|
-
manager assigned an isolated worktree or exact path ownership that does not
|
|
423
|
-
overlap sibling workers or manager edits. Workers must not edit \`.flow/**\`,
|
|
424
|
-
must not call state-changing Flow tools, and must not approve work, close
|
|
425
|
-
sessions, record Flow validation, or claim validation they did not run. A
|
|
426
|
-
worker may report raw validation output it actually ran; the manager decides
|
|
427
|
-
whether it is strong enough to record.
|
|
428
|
-
|
|
429
|
-
## Stage 1 — Orient (serial)
|
|
430
|
-
|
|
431
|
-
Call \`flow_status\` if a Flow session may already exist. Read enough files,
|
|
432
|
-
schemas, docs, tests, commands, or artifacts to identify real slices. Keep the
|
|
433
|
-
immediate blocker local: do not delegate the question that determines whether
|
|
434
|
-
fan-out is even valid.
|
|
435
|
-
|
|
436
|
-
Treat orientation as uncertainty reduction. Resolve environment uncertainty by
|
|
437
|
-
inspecting the repo, running cheap commands, or assigning evidence workers; ask
|
|
438
|
-
the user only when the remaining specification uncertainty would make a wrong
|
|
439
|
-
slice expensive to undo. Do not split a vague goal into workers until the
|
|
440
|
-
candidate slices have concrete targets, dependencies, and verification signals.
|
|
441
|
-
|
|
442
|
-
## Stage 2 — Slice
|
|
443
|
-
|
|
444
|
-
Split along whichever axis keeps slices independent: modules or path sets,
|
|
445
|
-
route or endpoint groups, risk lenses, command surfaces, data ranges, or claim
|
|
446
|
-
sets. Each slice needs a one-line scope, expected coverage, and a defined
|
|
447
|
-
output the manager can check.
|
|
448
|
-
|
|
449
|
-
For implementation slices, also name dependencies and write ownership before
|
|
450
|
-
spawning. A real dependency edge means the later slice waits for a verified
|
|
451
|
-
handoff or manager synthesis from the earlier slice; a shared file, fixture,
|
|
452
|
-
schema, or public contract usually means the work should stay serial unless an
|
|
453
|
-
isolated worktree is used. The manifest owns those edges through \`dependsOn\`
|
|
454
|
-
and \`writeScope\`.
|
|
455
|
-
|
|
456
|
-
## Stage 3 — Manifest (the pre-fan-out coverage gate)
|
|
457
|
-
|
|
458
|
-
Before spawning, write a pass manifest: one row per slice, plus a totals check.
|
|
459
|
-
Give the pass a stable id so later handoffs, verifier claims, and completion
|
|
460
|
-
payloads can refer to the same work without replaying chat.
|
|
461
|
-
|
|
462
|
-
| Row id | Slice scope | Expected coverage | Mode | Depends on | Write scope | Verification tier | Handoff ref | Verification status | Synthesis ref |
|
|
463
|
-
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
464
|
-
| \`runtime-read\` | \`src/core/**\` plus its tests | 14 files | \`evidence\` | none | none | accept locally | pending | pending | pending |
|
|
465
|
-
| \`release-read\` | release contract: CI workflows, \`package.json\`, changelog | 6 files | \`evidence\` | none | none | verify once | pending | pending | pending |
|
|
466
|
-
|
|
467
|
-
\`writeScope\` values in runtime accounting are \`none\`, \`manager-serial\`,
|
|
468
|
-
\`exact-path\`, \`isolated-worktree\`, or \`mixed\`. Use \`manager-serial\` for a
|
|
469
|
-
recorded serial implementation decision, \`exact-path\` for disjoint candidate
|
|
470
|
-
edits in one checkout, and \`isolated-worktree\` for candidate work that must be
|
|
471
|
-
merged back by the manager.
|
|
472
|
-
|
|
473
|
-
- Count the total work items when countable: files, modules, routes, commands,
|
|
474
|
-
rows, findings, screenshots, or claims. Confirm slice counts add back to the
|
|
475
|
-
total, with no overlaps, gaps, empty slices, or ambiguous shared contracts.
|
|
476
|
-
- If the scope cannot be counted, state the completeness rule instead, such as
|
|
477
|
-
"all changed files plus callers" or "all public commands plus release docs."
|
|
478
|
-
- Assign each slice's verification tier now (see Stage 6). Deciding where a
|
|
479
|
-
wrong claim is expensive belongs before handoffs arrive, not after.
|
|
480
|
-
- Record dependency edges now. A row may be spawned only after every \`depends on\`
|
|
481
|
-
row it names has returned a verified handoff or a manager synthesis that
|
|
482
|
-
explicitly settles the dependency.
|
|
483
|
-
- Fix the slice map centrally before spawning if the gate does not reconcile.
|
|
484
|
-
|
|
485
|
-
The manifest is also the accounting contract for the pass: N rows spawned means
|
|
486
|
-
N handoffs collected and checked in Stage 5 before anything is synthesized.
|
|
487
|
-
|
|
488
|
-
For implementation decisions, add a manifest row even when no worker is spawned:
|
|
489
|
-
\`kind=implementation-decision\`, \`decision=serial\` or \`decision=skipped\`,
|
|
490
|
-
\`candidateEligibility\`, \`candidateDecision\`, \`decisionFactors\`,
|
|
491
|
-
\`workerCount=0\`, \`writeScope=manager-serial\`, and a concrete \`decisionReason\`.
|
|
492
|
-
Use \`decision=serial\` with \`candidateDecision=serial_required\` for ineligible
|
|
493
|
-
worker cases; reserve \`decision=skipped\` for eligible candidate work that the
|
|
494
|
-
manager chose not to delegate. When an implementation-decision row uses
|
|
495
|
-
\`candidateDecision=used\`, it must also record actual candidate execution
|
|
496
|
-
evidence: either \`modes=candidate-implementation\`, or \`candidateWorkerCount > 0\`
|
|
497
|
-
with \`workerCount\` raised to cover it — a \`workerCount=0\` row cannot carry a
|
|
498
|
-
positive \`candidateWorkerCount\`. Neither subtype count may exceed the total:
|
|
499
|
-
\`candidateWorkerCount <= workerCount\` and \`verifierWorkerCount <= workerCount\`
|
|
500
|
-
(a single worker may fill both roles).
|
|
501
|
-
This is how Flow distinguishes deliberate serial work from forgotten candidate
|
|
502
|
-
or verifier passes.
|
|
503
|
-
|
|
504
|
-
Write the manifest where it survives the pass: the conversation is enough for a
|
|
505
|
-
single bounded pass, but when a follow-up pass or a session resume is
|
|
506
|
-
plausible, persist it with the synthesis (Stage 7) so the accounting can be
|
|
507
|
-
reconstructed.
|
|
508
|
-
|
|
509
|
-
## Stage 4 — Fan out
|
|
510
|
-
|
|
511
|
-
Every worker prompt includes:
|
|
512
|
-
|
|
513
|
-
\`\`\`text
|
|
514
|
-
Overall goal, context only: <goal>
|
|
515
|
-
Mode: evidence | review | validation | audit | verifier | candidate-implementation
|
|
516
|
-
Pass id and manifest row id: <stable ids from the manifest>
|
|
517
|
-
Your exact slice: <paths, modules, command, claim ids, risk lens, or worktree>
|
|
518
|
-
Expected coverage: <count, paths, range, or complete question set>
|
|
519
|
-
Dependencies and write scope: <verified dependencies, if any; none | manager-serial | exact-path | isolated-worktree>
|
|
520
|
-
Do: <bounded actions>
|
|
521
|
-
Do not: call state-changing Flow tools, edit .flow/**, own sibling slices, or make the final Flow verdict.
|
|
522
|
-
Return only the Flow handoff in this exact shape:
|
|
523
|
-
<matching handoff template copied verbatim from handoff-format.md>
|
|
524
|
-
\`\`\`
|
|
525
|
-
|
|
526
|
-
Hidden workers cannot load skills or read \`handoff-format.md\` themselves. The
|
|
527
|
-
manager copies the matching handoff template into every worker prompt; a bare
|
|
528
|
-
filename reference is not enough. Workers also cannot read the conversation, so
|
|
529
|
-
prompts cite file paths — including any synthesis file from an earlier pass —
|
|
530
|
-
instead of restating chat history.
|
|
531
|
-
|
|
532
|
-
For research or current-doc slices, require source checks for versioned or
|
|
533
|
-
time-sensitive facts. For implementation candidates, remind workers that other
|
|
534
|
-
work may be active and that they must not revert unrelated changes.
|
|
535
|
-
|
|
536
|
-
Continue non-overlapping manager work while workers run.
|
|
537
|
-
|
|
538
|
-
## Stage 5 — Account
|
|
539
|
-
|
|
540
|
-
Check every manifest row off against a returned handoff before synthesis. A
|
|
541
|
-
worker that never returns, errors out, returns empty or unstructured output, or
|
|
542
|
-
reports \`partial\` or \`blocked\` is a hole in the pass, and synthesizing around it
|
|
543
|
-
silently drops a slice.
|
|
544
|
-
|
|
545
|
-
For each row, fill in:
|
|
546
|
-
|
|
547
|
-
- \`handoffRefs\`: worker ids, handoff file paths, command output artifacts, or
|
|
548
|
-
review packet location that the manager can re-open.
|
|
549
|
-
- \`verificationStatus\`: \`not-needed\`, \`pending\`, \`passed\`, \`failed\`, \`mixed\`,
|
|
550
|
-
or \`downgraded\`.
|
|
551
|
-
- \`outcome\`: \`accepted\`, \`modified\`, \`rejected\`, \`partial\`, \`not-covered\`, or
|
|
552
|
-
\`superseded\`.
|
|
553
|
-
- \`synthesisRef\`: the manager-owned synthesis file or plan field that carries
|
|
554
|
-
the accepted result forward.
|
|
555
|
-
|
|
556
|
-
Rows with no worker, such as serial or skipped implementation decisions, still
|
|
557
|
-
need a row id, decision, reason, and outcome. They are not handoffs, but they
|
|
558
|
-
are accounting.
|
|
559
|
-
|
|
560
|
-
Worker failure ladder:
|
|
561
|
-
|
|
562
|
-
1. Re-spawn once with a narrower slice and a note about what the first attempt
|
|
563
|
-
returned.
|
|
564
|
-
2. If it fails again, cover the slice directly in the manager session.
|
|
565
|
-
3. If it stays blocked, carry the slice into the synthesis explicitly as
|
|
566
|
-
not-covered. Never present results as if coverage were complete.
|
|
567
|
-
|
|
568
|
-
## Stage 6 — Verify
|
|
569
|
-
|
|
570
|
-
\`Status: success\` only says the worker believes its slice is done. Accept a
|
|
571
|
-
handoff only after a cheap manager-side pass:
|
|
572
|
-
|
|
573
|
-
- \`Status\` is present and terminal: \`success\`, \`partial\`, or \`blocked\`; empty or
|
|
574
|
-
unstructured output fails this check.
|
|
575
|
-
- Coverage matches the assigned slice, or skips are explicit.
|
|
576
|
-
- Important claims have concrete evidence and confidence tags.
|
|
577
|
-
- Cited paths, commands, screenshots, URLs, or metrics resolve.
|
|
578
|
-
- The evidence supports the claim, not just the topic.
|
|
579
|
-
- Findings stay inside the worker's slice.
|
|
580
|
-
- Headline counts can be recounted or traced.
|
|
581
|
-
- Dependency claims cite the verified upstream handoff, synthesis, or source
|
|
582
|
-
artifact they depend on.
|
|
583
|
-
- Candidate implementation claims identify whether they came from exact path
|
|
584
|
-
ownership or an isolated worktree, and whether the manager inspected the
|
|
585
|
-
resulting patch. Record the manager result as \`accepted\`, \`modified\`, or
|
|
586
|
-
\`rejected\` where that is the most precise candidate outcome.
|
|
587
|
-
- Contradictions between workers are either resolved or explicitly marked as
|
|
588
|
-
contested.
|
|
589
|
-
|
|
590
|
-
Demote, drop, re-task, or verify claims that fail this pass.
|
|
591
|
-
|
|
592
|
-
### Verification tiers
|
|
593
|
-
|
|
594
|
-
One taxonomy decides how much verification a claim gets: the manifest assigns
|
|
595
|
-
a default tier per slice, and this stage applies it per claim. Use the cheapest
|
|
596
|
-
check that matches the risk:
|
|
597
|
-
|
|
598
|
-
- **Accept locally**: low-risk claims with direct evidence that the manager can
|
|
599
|
-
cheaply inspect or recount.
|
|
600
|
-
- **Verify once** with \`flow-verifier-worker\`: single-source, surprising,
|
|
601
|
-
inferred, low-confidence, citation-heavy, contested, or Flow-payload-bound
|
|
602
|
-
claims, including any count, benchmark, command result, or pass/fail claim a
|
|
603
|
-
Flow payload will rely on.
|
|
604
|
-
- **Verify strongly**: blocking or release-sensitive claims and claims that
|
|
605
|
-
affect user data, security, persistence, permissions, public API behavior,
|
|
606
|
-
release behavior, or data loss. Use independent verifier checks, manager-run
|
|
607
|
-
commands, or direct artifact inspection strong enough to settle the claim.
|
|
608
|
-
- **Do not accept**: claims without concrete evidence, claims outside the
|
|
609
|
-
assigned slice, claims contradicted by inspected artifacts, or claims where
|
|
610
|
-
the cited evidence supports only the topic rather than the assertion.
|
|
611
|
-
|
|
612
|
-
Verifier prompts use stable claim ids, one atomic assertion per id, the cited
|
|
613
|
-
source or command for each id, and the exact acceptance question. Do not
|
|
614
|
-
include the generator's reasoning unless that reasoning is the thing being
|
|
615
|
-
verified, do not say which worker produced the claim, and do not ask a
|
|
616
|
-
verifier to redesign the work or review the whole feature.
|
|
617
|
-
|
|
618
|
-
## Stage 7 — Synthesize
|
|
619
|
-
|
|
620
|
-
Apply the manager synthesis barrier before presenting or recording anything:
|
|
621
|
-
|
|
622
|
-
- Preserve confidence: verified, single-sourced, inferred, and unresolved claims
|
|
623
|
-
stay distinct when it matters.
|
|
624
|
-
- When workers disagree, inspect the cited artifact or rerun the cited command
|
|
625
|
-
instead of arbitrating from summaries. Do not average conflicting claims.
|
|
626
|
-
- Run the strongest practical local check for the deliverable.
|
|
627
|
-
- For broad implementation sessions, use one verifier worker after manager
|
|
628
|
-
synthesis when the risk is medium or high. Ask it whether every planned
|
|
629
|
-
feature landed, worker validation claims are supported, final code matches
|
|
630
|
-
the audit finding, generated bindings/docs/version metadata stayed
|
|
631
|
-
consistent, and changed files have plausible test coverage.
|
|
632
|
-
- Re-read critical files or docs that will be cited in the final decision.
|
|
633
|
-
- Move only distilled, evidence-backed claims forward; raw handoffs remain
|
|
634
|
-
candidate evidence, not a plan, review, completion payload, or final answer.
|
|
635
|
-
- Record gaps honestly instead of converting missing evidence into success
|
|
636
|
-
language.
|
|
637
|
-
|
|
638
|
-
Where accepted evidence goes:
|
|
639
|
-
|
|
640
|
-
- Planning evidence becomes \`requirements\`, \`decisions\`, feature \`targets\`,
|
|
641
|
-
feature \`validation\`, or plan notes — only when the source and scope are
|
|
642
|
-
clear. Unverified broad findings become a review-first feature, not a fix
|
|
643
|
-
plan.
|
|
644
|
-
- Validation evidence may become \`validationRun\` only when the worker was
|
|
645
|
-
explicitly authorized to run the command and reported the exact command,
|
|
646
|
-
status, and raw outcome summary.
|
|
647
|
-
- Review evidence informs \`featureReviewDepth\` plus \`featureReview\`, or \`finalReview\`, but the manager
|
|
648
|
-
owns the pass/fail verdict and must resolve blockers, contradictions, and
|
|
649
|
-
coverage gaps before returning the payload.
|
|
650
|
-
- Audit evidence becomes findings only after refutation; blocking findings need
|
|
651
|
-
guards checked, deployment context, and evidence that the current code
|
|
652
|
-
exhibits the behavior.
|
|
653
|
-
- Candidate patches are not Flow evidence until the manager inspects, merges or
|
|
654
|
-
rejects them, and validates the main Flow-managed workspace.
|
|
655
|
-
|
|
656
|
-
When completing a feature, include compact pass accounting in
|
|
657
|
-
\`flow_feature_complete.orchestrationPasses\` for any pass or implementation
|
|
658
|
-
decision that materially affected the feature:
|
|
659
|
-
|
|
660
|
-
\`\`\`json
|
|
661
|
-
{
|
|
662
|
-
"id": "feature-id-implementation-decision",
|
|
663
|
-
"kind": "implementation-decision",
|
|
664
|
-
"decision": "serial",
|
|
665
|
-
"decisionReason": "Shared schema and tests made exact path ownership unsafe.",
|
|
666
|
-
"candidateEligibility": "not_eligible",
|
|
667
|
-
"candidateDecision": "serial_required",
|
|
668
|
-
"decisionFactors": ["shared_state", "overlapping_files"],
|
|
669
|
-
"modes": [],
|
|
670
|
-
"workerCount": 0,
|
|
671
|
-
"candidateWorkerCount": 0,
|
|
672
|
-
"verifierWorkerCount": 0,
|
|
673
|
-
"sliceIds": ["manager-implementation"],
|
|
674
|
-
"dependsOn": [],
|
|
675
|
-
"writeScope": "manager-serial",
|
|
676
|
-
"handoffRefs": [],
|
|
677
|
-
"verificationStatus": "not-needed",
|
|
678
|
-
"outcome": "accepted",
|
|
679
|
-
"synthesisRef": "/tmp/flow-pass-synthesis.md"
|
|
680
|
-
}
|
|
681
|
-
\`\`\`
|
|
682
|
-
|
|
683
|
-
For candidate and verifier passes, use \`kind: "candidate"\` or
|
|
684
|
-
\`kind: "verification"\`, list the worker modes used, worker counts, slice ids,
|
|
685
|
-
handoff refs, dependency ids, verification status, and whether the manager
|
|
686
|
-
accepted, rejected, downgraded, or superseded the pass. The runtime aggregates
|
|
687
|
-
these compact records into \`session.budget.orchestration\` and stores them on
|
|
688
|
-
the feature history entry. Do not store full handoffs, long logs, or scratch
|
|
689
|
-
tables in \`.flow/session.json\`.
|
|
690
|
-
|
|
691
|
-
Status accounting distinguishes three cases: \`candidateDecision: "used"\` means
|
|
692
|
-
candidate execution evidence was recorded, \`candidateDecision:
|
|
693
|
-
"serial_required"\` means workers were not safe or useful, and
|
|
694
|
-
\`candidateEligibility: "eligible"\` plus \`candidateDecision: "skipped"\`
|
|
695
|
-
increments \`skippedCandidateDecisionCount\`. These candidate decision counters
|
|
696
|
-
come from \`kind: "implementation-decision"\` records; \`skipped\` and
|
|
697
|
-
\`serial_required\` are not valid on discovery, audit, review, validation,
|
|
698
|
-
verification, or candidate pass rows. \`candidatePassCount\`
|
|
699
|
-
counts actual candidate pass or worker evidence (\`kind: "candidate"\`,
|
|
700
|
-
\`modes\` includes \`candidate-implementation\`, or \`candidateWorkerCount > 0\`) —
|
|
701
|
-
a candidate-shaped decision label without that evidence is rejected, so decision
|
|
702
|
-
labels alone never count. \`verifierPassCount\` similarly counts
|
|
703
|
-
actual verifier pass or worker evidence (\`kind: "verification"\`, \`modes\`
|
|
704
|
-
includes \`verifier\`, or \`verifierWorkerCount > 0\`).
|
|
705
|
-
|
|
706
|
-
Persist the manifest and the synthesis when another pass may follow or the
|
|
707
|
-
session is long enough to be compacted or resumed: write the distilled result —
|
|
708
|
-
the accounted manifest, accepted claims with evidence and confidence, dropped
|
|
709
|
-
claims with one-line reasons, and open gaps — into plan prose fields or a
|
|
710
|
-
manager-owned scratch file outside both \`.flow/**\` and the repository worktree,
|
|
711
|
-
such as a file in the OS temporary directory. The runtime owns the \`.flow/**\`
|
|
712
|
-
layout, and scratch files left in the worktree end up staged or reviewed as if
|
|
713
|
-
they were project changes. Follow-up worker prompts cite that path; files are
|
|
714
|
-
the only shared memory between passes.
|
|
715
|
-
|
|
716
|
-
## Stage 8 — Extend or stop
|
|
717
|
-
|
|
718
|
-
Stop after a pass when:
|
|
719
|
-
|
|
720
|
-
- the manifest's coverage rule is satisfied and every row is accounted for.
|
|
721
|
-
- accepted claims are evidenced, scoped, and confidence-labeled.
|
|
722
|
-
- material single-source, contested, high-stakes, or payload-bound claims have
|
|
723
|
-
been verified or downgraded.
|
|
724
|
-
- every dependency edge named in the manifest has either a verified upstream
|
|
725
|
-
result or an explicit not-covered outcome.
|
|
726
|
-
- implementation pass decisions are recorded, including skipped candidate
|
|
727
|
-
workers, candidate eligibility, candidate decision, structured factors, and
|
|
728
|
-
the reason eligible workers were skipped.
|
|
729
|
-
- remaining gaps are explicit and do not block the Flow artifact being produced.
|
|
730
|
-
|
|
731
|
-
Start a bounded follow-up pass only when:
|
|
732
|
-
|
|
733
|
-
- the original slice map missed material scope.
|
|
734
|
-
- workers disagree on a claim that affects the Flow decision.
|
|
735
|
-
- a high-stakes or payload-bound claim needs verification.
|
|
736
|
-
- a dependency has just become verified and now unlocks a dependent slice.
|
|
737
|
-
- a candidate patch was rejected and an isolated alternative is still cheaper
|
|
738
|
-
than serial repair.
|
|
739
|
-
- a first pass exposes a narrower implementation or validation slice worth
|
|
740
|
-
isolating.
|
|
741
|
-
|
|
742
|
-
Run at most one routine follow-up pass. Extra passes need an explicit manager
|
|
743
|
-
reason, such as a high-stakes verifier check or a newly discovered bounded
|
|
744
|
-
slice. Do not recurse by default: if a worker says it needs another worker, the
|
|
745
|
-
manager decides whether that is a follow-up pass and writes the next bounded
|
|
746
|
-
prompt, starting again from the manifest.
|
|
747
|
-
|
|
748
|
-
## Worker count defaults
|
|
749
|
-
|
|
750
|
-
Use caps, not a fixed feature limit:
|
|
751
|
-
|
|
752
|
-
- small implementation: zero or one worker.
|
|
753
|
-
- medium independent implementation: two workers.
|
|
754
|
-
- broad audit: three to five workers.
|
|
755
|
-
- broad implementation: two to four candidate workers, only for
|
|
756
|
-
non-overlapping slices.
|
|
757
|
-
- final verifier: one worker when risk is medium or high.
|
|
758
|
-
|
|
759
|
-
The target is not "more workers." The target is explicit accounting: Flow must
|
|
760
|
-
justify not using workers when the work was eligible.
|
|
761
|
-
`;
|
|
762
|
-
|
|
763
|
-
// skills/flow/references/parallel-pass-example.md
|
|
764
|
-
var parallel_pass_example_default = `# Parallel pass example
|
|
765
|
-
|
|
766
|
-
Use this example after \`parallel-orchestration.md\` when a broad Flow task needs a
|
|
767
|
-
concrete pass shape. The project below is illustrative; derive your own slices
|
|
768
|
-
from the actual repo during serial orientation.
|
|
769
|
-
|
|
770
|
-
Goal: review whether a web app's API error handling is consistent before
|
|
771
|
-
planning a refactor.
|
|
772
|
-
|
|
773
|
-
Serial orientation: the manager reads the router entry point enough to identify
|
|
774
|
-
twelve API route modules, one shared error middleware, and an integration test
|
|
775
|
-
directory. The manager keeps the middleware local because it is one file and
|
|
776
|
-
anchors every other judgment.
|
|
777
|
-
|
|
778
|
-
Pass manifest: twelve countable route modules remain after the local check, and
|
|
779
|
-
4 + 3 + 5 adds back to 12 with no overlaps or gaps. The pass id is
|
|
780
|
-
\`api-error-handling-read\`.
|
|
781
|
-
|
|
782
|
-
| Row id | Slice scope | Expected coverage | Mode | Depends on | Write scope | Verification tier | Handoff ref | Verification status | Synthesis ref |
|
|
783
|
-
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
784
|
-
| \`routes-auth\` | auth and account routes | 4/12 modules | \`evidence\` | none | none | accept locally | pending | pending | pending |
|
|
785
|
-
| \`routes-billing\` | billing and subscription routes | 3/12 modules | \`review\` | none | none | verify once | pending | pending | pending |
|
|
786
|
-
| \`routes-admin\` | remaining content and admin routes | 5/12 modules | \`audit\` | none | none | verify once | pending | pending | pending |
|
|
787
|
-
|
|
788
|
-
Worker prompts:
|
|
789
|
-
|
|
790
|
-
\`\`\`text
|
|
791
|
-
Overall goal, context only: confirm API error handling is consistent.
|
|
792
|
-
Mode: evidence
|
|
793
|
-
Pass id and manifest row id: api-error-handling-read / routes-auth
|
|
794
|
-
Your exact slice: the four auth and account route modules under src/routes/.
|
|
795
|
-
Expected coverage: 4/4 modules.
|
|
796
|
-
Dependencies and write scope: none; none.
|
|
797
|
-
Do: report each route's error paths, status codes, and middleware usage with file:line evidence.
|
|
798
|
-
Do not: call state-changing Flow tools, edit .flow/**, own sibling slices, or make the final Flow verdict.
|
|
799
|
-
Return only the Flow handoff in this exact shape:
|
|
800
|
-
<matching handoff template copied verbatim from handoff-format.md>
|
|
801
|
-
\`\`\`
|
|
802
|
-
|
|
803
|
-
\`\`\`text
|
|
804
|
-
Overall goal, context only: confirm API error handling is consistent.
|
|
805
|
-
Mode: review
|
|
806
|
-
Pass id and manifest row id: api-error-handling-read / routes-billing
|
|
807
|
-
Your exact slice: the three billing and subscription route modules under src/routes/.
|
|
808
|
-
Expected coverage: 3/3 modules.
|
|
809
|
-
Dependencies and write scope: none; none.
|
|
810
|
-
Do: separate blocking findings from advisory notes and cite file:line evidence.
|
|
811
|
-
Do not: call state-changing Flow tools, edit .flow/**, own sibling slices, or make the final Flow verdict.
|
|
812
|
-
Return only the Flow handoff in this exact shape:
|
|
813
|
-
<matching handoff template copied verbatim from handoff-format.md>
|
|
814
|
-
\`\`\`
|
|
815
|
-
|
|
816
|
-
\`\`\`text
|
|
817
|
-
Overall goal, context only: confirm API error handling is consistent.
|
|
818
|
-
Mode: audit
|
|
819
|
-
Pass id and manifest row id: api-error-handling-read / routes-admin
|
|
820
|
-
Your exact slice: the five content and admin route modules under src/routes/.
|
|
821
|
-
Expected coverage: 5/5 modules.
|
|
822
|
-
Dependencies and write scope: none; none.
|
|
823
|
-
Do: check each claimed error path against the shared middleware contract and report divergences with evidence.
|
|
824
|
-
Do not: call state-changing Flow tools, edit .flow/**, own sibling slices, or make the final Flow verdict.
|
|
825
|
-
Return only the Flow handoff in this exact shape:
|
|
826
|
-
<matching handoff template copied verbatim from handoff-format.md>
|
|
827
|
-
\`\`\`
|
|
828
|
-
|
|
829
|
-
Accounting: three manifest rows spawned means three handoffs collected before
|
|
830
|
-
synthesis. If slice B returned \`partial\`, the manager would re-spawn it once
|
|
831
|
-
with a narrower scope, then cover it directly, and as a last resort carry it
|
|
832
|
-
into the synthesis explicitly as not-covered.
|
|
833
|
-
The manager fills \`handoffRefs\`, \`verificationStatus\`, \`outcome\`, and
|
|
834
|
-
\`synthesisRef\` for each row before any claim becomes a plan decision or review
|
|
835
|
-
payload.
|
|
836
|
-
|
|
837
|
-
Handoff checks: the manager accepts only reports with terminal status, matching
|
|
838
|
-
coverage counts, concrete file:line evidence, confidence tags, and claims inside
|
|
839
|
-
the assigned slice. A claim such as \`[high] billing routes bypass the error
|
|
840
|
-
middleware; evidence: src/routes/billing.ts:88-104; corroboration: single
|
|
841
|
-
source\` is usable. A claim such as \`[high] error handling looks fine; evidence:
|
|
842
|
-
routes reviewed\` is dropped or retasked.
|
|
843
|
-
|
|
844
|
-
Verifier pass: the manager sends any single-source claim that will enter the
|
|
845
|
-
Flow payload to \`flow-verifier-worker\`, for example: \`C1: billing and
|
|
846
|
-
subscription routes return raw exceptions while all other routes use the shared
|
|
847
|
-
error envelope; sources: src/routes/billing.ts, src/routes/subscription.ts\`.
|
|
848
|
-
|
|
849
|
-
Final synthesis: the manager re-reads the relevant route and middleware lines,
|
|
850
|
-
keeps only verified or clearly labeled claims, and records one artifact such as
|
|
851
|
-
a plan decision, review payload, or docs patch. Raw handoffs and unverified
|
|
852
|
-
suggestions do not move into the next pass or user-facing answer.
|
|
853
|
-
|
|
854
|
-
If the pass shaped feature execution, the manager records compact accounting in
|
|
855
|
-
\`flow_feature_complete.orchestrationPasses\`, such as pass id
|
|
856
|
-
\`api-error-handling-read\`, kind \`review\`, worker count \`3\`, slice ids
|
|
857
|
-
\`routes-auth\`, \`routes-billing\`, and \`routes-admin\`, verification status
|
|
858
|
-
\`mixed\` or \`passed\`, and a synthesis ref pointing to the manager-owned summary.
|
|
859
|
-
`;
|
|
860
|
-
|
|
861
|
-
// skills/flow/references/recovery-playbook.md
|
|
862
|
-
var recovery_playbook_default = '# Recovery playbook\n\nUse this when a Flow tool returns `status: "error"`, a blocker, or a `nextAction` that conflicts with memory.\n\n## First response\n\n1. Re-anchor with `flow_status`.\n2. Read the returned `summary`, `recovery`, `lastError`, and active feature.\n3. Fix the cause, then retry the smallest valid Flow action.\n\n## Common cases\n\n- `missing_session`: start with `flow_plan_save` using the user\'s goal.\n- `missing_goal`: ask for a concrete goal before planning.\n- `Approved plans cannot be changed`: use `flow_feature_reset` when only affected features need another pass; otherwise close and start a new goal.\n- `No feature is currently running`: call `flow_run_start` before completing.\n- `already in progress`: finish, reset, or block the active feature before starting another.\n- `Completion requires recorded validation evidence`: run real validation and include at least one passing `validationRun`.\n- `Completion requires all recorded validation to pass`: fix failures and rerun. Do not relabel failed checks as passed.\n- `Non-final feature completion requires targeted validation`: use `validationScope: "targeted"` for ordinary features.\n- `Final feature completion requires broad validation`: run the project-level gate and use `validationScope: "broad"`.\n- `Feature review depth ... does not meet the plan requirement`: rerun review\n at the feature\'s planned depth or reset/replan if the depth was chosen\n incorrectly.\n- `Completion requires a passing featureReview`: run or request a real review and include a passing `featureReview` only when there are no blocking findings.\n- `Review retry budget exhausted`: stop and report the remaining blocker. Do\n not keep patching; reset or replan only after explicit user direction.\n- `Final feature completion requires a finalReview`: perform final review and include `finalReview`.\n- `Final review depth must match the plan policy`: use `reviewDepth` equal to the approved plan\'s `finalReviewPolicy`; valid final-review values are `broad` and `detailed`.\n- `Cannot close ... unfinished features`: complete, reset, defer, or abandon honestly. Do not mark completed while work remains.\n\n## Reset guidance\n\nUse `flow_feature_reset` when the active or completed work was built on the wrong assumption, validation revealed a design issue, dependencies need to be rerun, or dependent features must be invalidated. Resetting a feature also resets its dependents.\n\n## Closure guidance\n\nUse `flow_session_close`:\n\n- `completed`: only after all planned features are complete.\n- `deferred`: the user intentionally postpones unfinished work.\n- `abandoned`: the session should be archived without claiming delivery.\n\nAfter closure, the active `.flow/session.json` is removed and the archived JSON is stored under `.flow/history/`.\n';
|
|
863
|
-
|
|
864
|
-
// skills/flow/SKILL.md
|
|
865
|
-
var SKILL_default = "---\nname: flow\ndescription: Manage the end-to-end Flow loop for skills-first OpenCode work. Use when a user asks for Flow-guided delivery from goal to completion, resumable autonomous delivery, or resuming or closing a Flow session. For plan-only work use flow-plan; for executing one approved feature use flow-run.\n---\n\n# Flow\n\nUse Flow as a minimal state ledger, not as a framework. Skills provide judgment; the runtime only records the approved plan, active feature, validation evidence, review evidence, and closure.\n\nRouting: this manager skill owns the whole loop and every state-changing `flow_*` call. Load `flow-plan` alone for plan-only requests and `flow-run` alone when an approved plan needs one feature executed. Answer status-only questions with `flow_status`; no skill load is needed. `flow-test`, `flow-deslop`, and `flow-ui-quality` are optional helpers loaded from inside the loop; `flow-commit` is user-triggered only and never part of the autonomous loop.\n\n## Loop\n\n1. Call `flow_status` first. Trust its active session and next action over conversation memory.\n If the result includes `setup.skills`, follow the Skill Availability rules\n below before loading any Flow skill.\n If it includes `session.resumePacket` or `session.budget.phaseBoundary`, stop\n and report the resume instructions unless this is a fresh user invocation\n explicitly resuming the session. Only then may the next `flow_run_start` use\n `phaseBoundaryAck: true`.\n2. If there is no active session and the user gave a goal, load `flow-plan`, save a plan with `flow_plan_save`, then approve it with `flow_plan_approve` only after explicit user approval or prior authorization for autonomous implementation. If there is no goal, ask for one.\n3. Load `flow-run`, call `flow_run_start`, implement exactly one feature, validate it, and prepare a `flow_feature_complete` payload. For validation-heavy, regression-sensitive, browser QA, route QA, or failure-prone work, use `flow-test` to choose and summarize evidence before completion.\n4. Load `flow-review` for the required feature review. Send a compact review\n packet, not the accumulated root transcript. The reviewer reports\n `featureReviewDepth` and `featureReview`; the manager records both inside\n `flow_feature_complete`.\n5. On the final feature, run broad validation and include `finalReview` in the same `flow_feature_complete` call. Its `reviewDepth` must match the plan's `finalReviewPolicy`.\n6. After all features are complete, archive the session with `flow_session_close` using `kind: \"completed\"`.\n\nUse `references/parallel-orchestration.md` for broad read-only discovery, audit, validation, review, verification, or candidate implementation passes. It is the whole pass playbook — orient, slice, manifest, fan out, account, verify, synthesize, extend or stop — and its `references/handoff-format.md` companion holds the worker report templates the manager pastes into prompts. Hidden Flow workers are injected by plugin config; invoke the named worker when it is available. The manager owns every `flow_*` state change.\n\nDo not commit, push, amend, rebase, publish, or mutate releases during the\nautonomous Flow loop. Load `flow-commit` only when the user explicitly asks for\ncommit preparation or commit creation.\n\n## Skill Availability\n\nIf `flow_status` returns `setup.skills`, report that setup status and stop\nnative-loading Flow skills in the current OpenCode startup. Missing, incomplete,\nor outdated managed skills require a sync/restart cycle before their native skill\ninstructions can be trusted by the running process. Public command bundles are\nself-contained and may continue when the command prompt already embeds the\nrequired Flow instructions.\n\nIf optional helper skills such as `flow-test`, `flow-deslop`, or\n`flow-ui-quality` are unavailable, continue only with explicit coverage gaps. Do\nnot copy their rubrics into another skill and do not claim their quality checks\nwere completed.\n\n## Runtime Surface\n\n- `flow_status`: read the active session.\n- `flow_plan_save`: create a session and/or save a draft plan.\n- `flow_plan_approve`: lock the draft plan.\n- `flow_run_start`: start one runnable feature.\n- `flow_feature_complete`: record completion or a real blocker with validation and review evidence.\n- `flow_feature_reset`: reset one feature and its dependents.\n- `flow_session_close`: archive the active session as `completed`, `deferred`, or `abandoned`.\n\nThere is no `flow_context`, no separate review-record tool, and no multi-session activation surface. The single active source of truth is `.flow/session.json`; closed sessions are archived under `.flow/history/`.\n\nPlanning and running require loaded Flow tools; do not simulate plan approval or feature completion when the runtime is unavailable. Review may still return advisory output when tools, skills, or references are stale or unavailable, but the manager must not record it as Flow-gated evidence.\n\n## Hard Gates\n\n- Approved plans are immutable. To change direction, reset affected features or close the session and start a new goal.\n- Only one feature can be active at a time.\n- Each feature's planned `reviewDepth` is the minimum accepted\n `featureReviewDepth` for completion.\n- Completion requires at least one passing `validationRun` entry.\n- Non-final completion requires `validationScope: \"targeted\"`.\n- Final completion requires `validationScope: \"broad\"` and a passing `finalReview`.\n- Every completed feature requires a passing `featureReview` with no blocking findings.\n- Failed reviews pause the loop by default. Autonomous repair may make at most\n one repair plus one retry review before stopping.\n- Phase boundaries stop the current root session; resume from\n `.flow/session.json` in a fresh OpenCode session.\n- `flow_session_close` accepts `kind: \"completed\"` only after an approved plan has passed final completion.\n\n## Budget And Retry Boundaries\n\nFlow enforces review retry counts in the runtime ledger and tracks completed\nfeature counts as telemetry only. The current OpenCode plugin surface does not\nexpose per-turn token usage to Flow; when usage is visible in the host UI or\nlogs, stop the current autonomous loop once the root session is large enough to\nthreaten latency or cost and report a compact handoff instead of continuing.\nTreat high visible tokens, high non-cache tokens, or repeated reviewer fan-out\nas a reason to finish the current feature, emit the resume packet, and continue\nin a fresh session.\n\n## Recovery\n\n- Confused state: call `flow_status` and follow `nextAction`.\n- Wrong assumption or failed implementation path: use `flow_feature_reset` for the feature and dependents, then rerun from the corrected plan.\n- Missing validation or review evidence: gather real evidence, then call `flow_feature_complete`.\n- Approved plan is materially wrong: reset the affected features, save a revised plan if the session is back in planning; otherwise close and start a new goal.\n- Unknown runtime error: read `summary` and `recovery`; see `references/recovery-playbook.md` for common cases.\n\nNever fabricate validation output, backfill review approval you did not perform, or close as `deferred`/`abandoned` merely to avoid an unfinished-work blocker.\n";
|
|
866
|
-
|
|
867
|
-
// skills/flow-commit/SKILL.md
|
|
868
|
-
var SKILL_default2 = `---
|
|
869
|
-
name: flow-commit
|
|
870
|
-
description: Prepare safe Git commits and commit messages. Use only when the user asks to inspect, stage, validate, write a commit message, or create a commit; preserves unrelated work and never pushes, amends, rebases, or publishes without explicit authorization.
|
|
871
|
-
---
|
|
872
|
-
|
|
873
|
-
# Flow Commit
|
|
874
|
-
|
|
875
|
-
Use this skill only when the user asks to prepare or create a commit, write a
|
|
876
|
-
commit message, stage intended work, or validate staged changes before
|
|
877
|
-
committing. It is not part of the autonomous Flow loop and must not be loaded
|
|
878
|
-
automatically by \`flow\`, \`flow-run\`, or \`flow_feature_complete\`.
|
|
879
|
-
|
|
880
|
-
When a Flow session exists, a commit never substitutes for Flow completion. The
|
|
881
|
-
manager still records validation and review evidence through
|
|
882
|
-
\`flow_feature_complete\` before claiming a Flow feature is done. Default to commit
|
|
883
|
-
preparation only after \`flow_feature_complete\` has recorded the relevant
|
|
884
|
-
completion evidence. If the user explicitly asks for a WIP commit, preserve
|
|
885
|
-
failing or incomplete validation context in the message.
|
|
886
|
-
|
|
887
|
-
## Boundaries
|
|
888
|
-
|
|
889
|
-
- Preserve unrelated user work.
|
|
890
|
-
- Stage explicit paths or hunks only. Do not default to \`git add .\` or
|
|
891
|
-
\`git add -A\`.
|
|
892
|
-
- Do not commit \`.flow/**\` state unless the maintainer explicitly asks to
|
|
893
|
-
archive those exact files.
|
|
894
|
-
- Do not push, amend, rebase, squash, reset, force-push, tag, release, publish,
|
|
895
|
-
or mutate remote state unless the user explicitly authorizes that exact
|
|
896
|
-
operation.
|
|
897
|
-
- Stop before committing secrets, local config, credentials, private keys,
|
|
898
|
-
generated release artifacts, or suspicious environment files.
|
|
899
|
-
- Stop when validation fails unless the user explicitly wants an unfinished WIP
|
|
900
|
-
commit and the commit message says so.
|
|
901
|
-
|
|
902
|
-
## Inspect
|
|
903
|
-
|
|
904
|
-
Start with the worktree and intent:
|
|
905
|
-
|
|
906
|
-
1. Run \`git status --short\`.
|
|
907
|
-
2. Inspect unstaged and staged changes separately with \`git diff\` and
|
|
908
|
-
\`git diff --cached\`.
|
|
909
|
-
3. Inspect untracked files before deciding whether they belong.
|
|
910
|
-
4. Group changes by intent, feature, and risk. Prefer one coherent commit over
|
|
911
|
-
one large mixed commit.
|
|
912
|
-
5. Identify exclusions: unrelated files, local notes, \`.flow/**\`, generated
|
|
913
|
-
artifacts, logs, caches, credentials, and temporary outputs.
|
|
914
|
-
|
|
915
|
-
If the commit boundary is unclear, propose the boundary and ask before staging.
|
|
916
|
-
|
|
917
|
-
## Stage
|
|
918
|
-
|
|
919
|
-
Stage only the intended boundary:
|
|
920
|
-
|
|
921
|
-
- Use explicit file paths for whole-file staging.
|
|
922
|
-
- Use patch staging for mixed-intent files.
|
|
923
|
-
- Re-run \`git status --short\` and \`git diff --cached --stat\` after staging.
|
|
924
|
-
- Review the full staged diff before validation and commit.
|
|
925
|
-
|
|
926
|
-
Never undo or rewrite user changes to make staging easier. If a file contains
|
|
927
|
-
mixed user and agent work, either stage selected hunks or ask for direction.
|
|
928
|
-
|
|
929
|
-
## Screen and Validate
|
|
930
|
-
|
|
931
|
-
Before commit creation, check the staged diff for:
|
|
932
|
-
|
|
933
|
-
- Secrets, tokens, private keys, credentials, cookies, and unredacted personal
|
|
934
|
-
data.
|
|
935
|
-
- \`.env\`, local config, machine-specific paths, and editor files.
|
|
936
|
-
- \`.flow/**\` state.
|
|
937
|
-
- Generated artifacts that are not normally versioned.
|
|
938
|
-
- Package or version metadata drift unrelated to the requested change.
|
|
939
|
-
|
|
940
|
-
If the repository documents its own commit preflight (a package script, a
|
|
941
|
-
repo-local preflight script, or guidance in AGENTS/docs or CI config), defer to
|
|
942
|
-
it for staged validation instead of duplicating its checks. Run it after
|
|
943
|
-
staging and rerun it after any staging change. A staged-boundary preflight
|
|
944
|
-
validates diff hygiene and staged secret screening; it does not run a
|
|
945
|
-
whole-worktree gate, choose commit boundaries, or write commit messages.
|
|
946
|
-
|
|
947
|
-
Use the repository's documented broad validation gate when a full local check is
|
|
948
|
-
appropriate, such as package scripts, AGENTS/docs, or CI guidance. Treat broad
|
|
949
|
-
checks as whole-worktree evidence unless the repository explicitly provides a
|
|
950
|
-
staged-content runner. Use narrower tests only when the user has asked for a
|
|
951
|
-
lighter pass or when the change is intentionally not ready for the broad gate.
|
|
952
|
-
|
|
953
|
-
## Message
|
|
954
|
-
|
|
955
|
-
Propose a commit message that reflects the staged diff:
|
|
956
|
-
|
|
957
|
-
- Subject: imperative, specific, and scoped.
|
|
958
|
-
- Body when useful: context, changed areas, validation run, and remaining risk.
|
|
959
|
-
- Do not mention unstaged or excluded work as if it were included.
|
|
960
|
-
- Include WIP or failing-validation context only when the user explicitly chose
|
|
961
|
-
that path.
|
|
962
|
-
|
|
963
|
-
## Create Commit
|
|
964
|
-
|
|
965
|
-
Create the commit only after the user explicitly asks for commit creation or has
|
|
966
|
-
already authorized it in the current request.
|
|
967
|
-
|
|
968
|
-
Before running \`git commit\`, report:
|
|
969
|
-
|
|
970
|
-
- Staged paths.
|
|
971
|
-
- Excluded dirty or untracked paths.
|
|
972
|
-
- Validation command and result.
|
|
973
|
-
- Proposed message.
|
|
974
|
-
- Any risks or gaps.
|
|
975
|
-
|
|
976
|
-
After a successful commit, report the commit hash and leave push or release
|
|
977
|
-
actions for a separate explicit request.
|
|
978
|
-
`;
|
|
979
|
-
|
|
980
|
-
// skills/flow-deslop/references/refactor-workflow.md
|
|
981
|
-
var refactor_workflow_default = `# Safe refactor workflow
|
|
982
|
-
|
|
983
|
-
Refactoring is a behavior-preserving sequence of small changes. This workflow keeps cleanup from becoming an unreviewable rewrite.
|
|
984
|
-
|
|
985
|
-
## Before editing
|
|
986
|
-
|
|
987
|
-
- Define the invariant: what behavior, API, schema, command, state path, or visual output must remain unchanged.
|
|
988
|
-
- Locate callers and tests before changing the target. If there is no test coverage, add or run the narrowest check that proves current behavior.
|
|
989
|
-
- Identify the smallest reversible move: remove dead code, rename, extract, inline, move, consolidate, or split phase.
|
|
990
|
-
- Choose a validation command that can fail for the behavior you might break.
|
|
991
|
-
|
|
992
|
-
## During editing
|
|
993
|
-
|
|
994
|
-
- Make one structural move at a time, then re-run the relevant check when risk is non-trivial.
|
|
995
|
-
- Prefer deleting or inlining a useless layer before introducing a new one.
|
|
996
|
-
- Keep names domain-specific. Generic names like \`manager\`, \`processor\`, \`utils\`, and \`helper\` are suspect unless the repo already owns that vocabulary.
|
|
997
|
-
- Avoid mixed commits inside a feature: no unrelated formatting, package churn, comment rewrites, or style sweeps.
|
|
998
|
-
- If the refactor uncovers a behavior bug, stop and replan unless the approved feature already includes fixing that bug.
|
|
999
|
-
|
|
1000
|
-
## Validation evidence
|
|
1001
|
-
|
|
1002
|
-
Good cleanup evidence includes:
|
|
1003
|
-
|
|
1004
|
-
- focused tests for behavior touched by the refactor.
|
|
1005
|
-
- typecheck/lint/build output for mechanical structure changes.
|
|
1006
|
-
- before/after references for deleted exports, commands, generated files, and docs when static search is not enough.
|
|
1007
|
-
- broad validation when shared abstractions, public APIs, persistence, or cross-feature integration changed.
|
|
1008
|
-
|
|
1009
|
-
Weak evidence includes:
|
|
1010
|
-
|
|
1011
|
-
- "No tests needed" for behavior-adjacent refactors.
|
|
1012
|
-
- tests that were edited to match the new shape but do not prove the old behavior.
|
|
1013
|
-
- scanner metrics without human inspection.
|
|
1014
|
-
- green tests after changing unrelated surfaces not covered by those tests.
|
|
1015
|
-
|
|
1016
|
-
## Review checklist
|
|
1017
|
-
|
|
1018
|
-
- Every changed artifact maps to the approved cleanup scope.
|
|
1019
|
-
- The new structure has fewer reasons to change, not just fewer lines.
|
|
1020
|
-
- Public contracts and compatibility shims remain intact or were explicitly planned.
|
|
1021
|
-
- Deleted code is actually unreachable or obsolete.
|
|
1022
|
-
- Validation can catch a realistic mistake in the refactor.
|
|
1023
|
-
`;
|
|
1024
|
-
|
|
1025
|
-
// skills/flow-deslop/references/smell-rubric.md
|
|
1026
|
-
var smell_rubric_default = `# Deslop smell rubric
|
|
1027
|
-
|
|
1028
|
-
Use this rubric to turn vague cleanup instincts into reviewable findings.
|
|
1029
|
-
|
|
1030
|
-
## Actionable smell classes
|
|
1031
|
-
|
|
1032
|
-
- **duplication** — repeated logic or conditionals that must change together. Confirm whether small repetition is clearer than abstraction.
|
|
1033
|
-
- **bloat** — long function, large class/module, or oversized component whose responsibilities are mixed enough to hide behavior.
|
|
1034
|
-
- **speculative generality** — unused extension points, factories, options, interfaces, or configuration added for imagined futures.
|
|
1035
|
-
- **dead code** — unreachable branches, unused exports, stale flags, abandoned helpers, obsolete tests, or comments describing code that no longer exists.
|
|
1036
|
-
- **primitive obsession** — stringly typed modes, loosely shaped objects, or magic literals that obscure a domain constraint already present elsewhere.
|
|
1037
|
-
- **shotgun surgery** — one conceptual change requires scattered edits across unrelated modules.
|
|
1038
|
-
- **feature envy / misplaced responsibility** — code repeatedly reaches into another module's internals instead of using the owning boundary.
|
|
1039
|
-
- **message chains / excessive delegation** — call chains or wrappers that add no policy and make behavior harder to locate.
|
|
1040
|
-
- **agent slop** — verbose scaffolding, duplicate defensive branches, generic helper layers, temporary flags, commented-out code, debug output, or invented patterns that do not match the repo.
|
|
1041
|
-
- **test-oracle slop** — tests that assert implementation trivia, snapshots of noisy markup, or mocks that make broken behavior pass.
|
|
1042
|
-
|
|
1043
|
-
## Non-smells until proven
|
|
1044
|
-
|
|
1045
|
-
- Repetition that makes two workflows intentionally independent.
|
|
1046
|
-
- Framework-required shape, generated code, migration history, compatibility shims, or public API affordances.
|
|
1047
|
-
- Verbose guards protecting data loss, security, lifecycle ordering, or error observability.
|
|
1048
|
-
- Logging/metrics that operators or tests rely on.
|
|
1049
|
-
- Local style differences already accepted by the repo and not hurting changeability.
|
|
1050
|
-
|
|
1051
|
-
## Finding shape
|
|
1052
|
-
|
|
1053
|
-
Each blocking cleanup finding should carry:
|
|
1054
|
-
|
|
1055
|
-
\`\`\`text
|
|
1056
|
-
class; severity; location; evidence read; refutation checked; why it matters; safe fix shape; validation command
|
|
1057
|
-
\`\`\`
|
|
1058
|
-
|
|
1059
|
-
Rate as blocking only when the smell materially raises defect risk, blocks planned work, hides behavior, or makes the success claim unverifiable. Style-only cleanup is advisory.
|
|
1060
|
-
`;
|
|
1061
|
-
|
|
1062
|
-
// skills/flow-deslop/SKILL.md
|
|
1063
|
-
var SKILL_default3 = `---
|
|
1064
|
-
name: flow-deslop
|
|
1065
|
-
description: Clean up and refactor code with evidence-backed code-smell analysis. Use for AI-slop removal, overengineering reduction, maintainability refactors, behavior-preserving cleanup, duplicated or bloated code, speculative abstractions, and dead code. Review verdicts on cleanup work stay in flow-review, which loads this skill to judge cleanup claims.
|
|
1066
|
-
---
|
|
1067
|
-
|
|
1068
|
-
# Flow deslop
|
|
1069
|
-
|
|
1070
|
-
Use this skill when the Flow work is about improving code quality rather than adding a new user-visible feature. The job is to make the code easier to change without changing behavior unless the approved plan explicitly says behavior changes.
|
|
1071
|
-
|
|
1072
|
-
This is a helper skill: it produces cleanup findings and evidence only. The manager owns every state-changing \`flow_*\` call, and cleanup review verdicts are returned through \`flow-review\`.
|
|
1073
|
-
|
|
1074
|
-
## Ground the cleanup
|
|
1075
|
-
|
|
1076
|
-
- Start from concrete evidence: duplicated code, unnecessary abstraction, long or tangled functions, dead branches, confusing ownership, repeated conditionals, excessive coupling, or validation gaps that hide maintainability risk.
|
|
1077
|
-
- Load \`references/smell-rubric.md\` when classifying findings or deciding what is worth fixing.
|
|
1078
|
-
- Load \`references/refactor-workflow.md\` before implementing or reviewing non-trivial cleanup.
|
|
1079
|
-
- Treat scanner output, metrics, and model impressions as candidates only. A smell becomes actionable after reading the surrounding code, callers, tests, and relevant contracts.
|
|
1080
|
-
- Record cleanup context in existing Flow plan fields: \`requirements\`, \`decisions\`, feature \`targets\`, and feature \`validation\`. Do not invent new Flow payload fields.
|
|
1081
|
-
|
|
1082
|
-
## Plan cleanup work
|
|
1083
|
-
|
|
1084
|
-
- Prefer one feature per validated cleanup theme with a clear validation story. "Clean the whole repo" starts with a review-first feature that produces evidence-backed findings, then fix features for confirmed clusters.
|
|
1085
|
-
- Keep refactors small and behavior-preserving. If a cleanup requires behavior change, surface it as product scope and replan.
|
|
1086
|
-
- State what will not be cleaned. Broad cleanup without boundaries invites churn and makes review impossible.
|
|
1087
|
-
- Choose validation before editing: focused tests for affected behavior, typecheck/lint for mechanical changes, and a broad gate when cleanup spans shared abstractions.
|
|
1088
|
-
|
|
1089
|
-
## Execute cleanup safely
|
|
1090
|
-
|
|
1091
|
-
- Preserve public APIs, persisted data, command names, tool names, and observable behavior unless the approved plan explicitly changes them.
|
|
1092
|
-
- Prefer removal, consolidation, naming, and local extraction before new abstractions. New abstractions must reduce real duplication or clarify an existing boundary.
|
|
1093
|
-
- Delete dead code only after checking references, exports, generated entrypoints, docs, tests, and runtime/distribution paths that static search may miss.
|
|
1094
|
-
- Keep every change tied to a finding or plan target. Opportunistic style edits are out of scope.
|
|
1095
|
-
|
|
1096
|
-
## Review cleanup claims
|
|
1097
|
-
|
|
1098
|
-
For each claimed smell removal, verify:
|
|
1099
|
-
|
|
1100
|
-
- **location** — the changed code and the original smell were actually read.
|
|
1101
|
-
- **impact** — the change reduces duplication, coupling, complexity, or future-change risk in a concrete way.
|
|
1102
|
-
- **refutation checked** — apparent smell was not intentional compatibility, performance, generated code, framework convention, or a safety guard.
|
|
1103
|
-
- **behavior preserved** — tests or other evidence cover the behavior touched.
|
|
1104
|
-
- **blast radius** — public contracts and downstream callers still work.
|
|
1105
|
-
|
|
1106
|
-
Never approve cleanup because it "looks cleaner" without evidence. Tests passing is necessary but not sufficient when the refactor changes structure across files.
|
|
1107
|
-
`;
|
|
1108
|
-
|
|
1109
|
-
// skills/flow-plan/references/parallel-discovery.md
|
|
1110
|
-
var parallel_discovery_default = `# Parallel discovery
|
|
1111
|
-
|
|
1112
|
-
Use this only after a serial orientation pass has identified the repo shape and the likely slices. Workers are read-only evidence gatherers; the planner owns the plan.
|
|
1113
|
-
|
|
1114
|
-
For broad parallel passes, also load \`../../flow/references/parallel-orchestration.md\`.
|
|
1115
|
-
Use its pass manifest as the pre-fan-out coverage gate and
|
|
1116
|
-
\`../../flow/references/handoff-format.md\` response shapes.
|
|
1117
|
-
|
|
1118
|
-
## Good slices
|
|
1119
|
-
|
|
1120
|
-
- Independent modules or packages.
|
|
1121
|
-
- Frontend route and backend endpoint pairs.
|
|
1122
|
-
- Test, CI, and release surfaces.
|
|
1123
|
-
- Risk lenses such as security, persistence, accessibility, migration, or performance.
|
|
1124
|
-
- Documentation and operator-contract checks.
|
|
1125
|
-
|
|
1126
|
-
## Deriving first-pass slices
|
|
1127
|
-
|
|
1128
|
-
Derive slices from the repo shape found during the serial orientation pass:
|
|
1129
|
-
top-level packages or source directories, the test tree, CI and release
|
|
1130
|
-
config, and docs. Name each slice by the paths it owns, for example "runtime:
|
|
1131
|
-
\`src/core/**\` plus its tests" or "release contract: CI workflows,
|
|
1132
|
-
\`package.json\`, and the changelog".
|
|
1133
|
-
|
|
1134
|
-
Treat derived slices as starting points, not a simultaneous coverage map.
|
|
1135
|
-
Before fan-out, choose the relevant entries and de-overlap shared docs,
|
|
1136
|
-
config, or release surfaces in the pass manifest.
|
|
1137
|
-
|
|
1138
|
-
## Manifest and prompts
|
|
1139
|
-
|
|
1140
|
-
Write the pass manifest and the worker prompts exactly as Stages 3 and 4 of
|
|
1141
|
-
\`../../flow/references/parallel-orchestration.md\` define them: one manifest row
|
|
1142
|
-
per slice with expected coverage, dependencies, write scope, and a verification
|
|
1143
|
-
tier, and a self-contained prompt per worker naming the mode (usually
|
|
1144
|
-
\`evidence\`), the exact slice, and the expected coverage. Discovery-specific
|
|
1145
|
-
rules:
|
|
1146
|
-
|
|
1147
|
-
- Workers are read-only. For validation-oriented discovery, workers may report
|
|
1148
|
-
commands that should be run, and include raw output only for commands they
|
|
1149
|
-
actually ran.
|
|
1150
|
-
- Workers cannot read reference files themselves; paste the matching handoff
|
|
1151
|
-
template from \`../../flow/references/handoff-format.md\` into the prompt.
|
|
1152
|
-
- If discovery finds later features with disjoint path ownership, preserve that
|
|
1153
|
-
fact in feature \`targets\` and \`dependsOn\` so execution can make an explicit
|
|
1154
|
-
serial or candidate-pass decision instead of rediscovering ownership.
|
|
1155
|
-
|
|
1156
|
-
## Synthesis
|
|
1157
|
-
|
|
1158
|
-
Convert only evidence-backed work into plan fields:
|
|
1159
|
-
|
|
1160
|
-
- \`requirements\`: user promises and externally visible acceptance criteria.
|
|
1161
|
-
- \`decisions\`: architecture boundaries, rejected approaches, and scope cuts.
|
|
1162
|
-
- feature \`targets\`: files, modules, routes, commands, docs, or workflows the feature owns.
|
|
1163
|
-
- feature \`validation\`: checks expected to prove the feature.
|
|
1164
|
-
|
|
1165
|
-
If workers disagree, inspect the source artifact yourself. If a candidate finding lacks a concrete citation or refutation pass, make it a review-first deliverable rather than a fix feature.
|
|
1166
|
-
|
|
1167
|
-
Apply the manager synthesis barrier from
|
|
1168
|
-
\`../../flow/references/parallel-orchestration.md\`: only distilled,
|
|
1169
|
-
evidence-backed claims become plan fields.
|
|
1170
|
-
`;
|
|
1171
|
-
|
|
1172
|
-
// skills/flow-plan/references/plan-quality-checklist.md
|
|
1173
|
-
var plan_quality_checklist_default = `# Plan quality checklist
|
|
1174
|
-
|
|
1175
|
-
Use this checklist before \`flow_plan_save\` and again before approval if the plan
|
|
1176
|
-
changed during discussion. The goal is not a long planning artifact; it is a
|
|
1177
|
-
compact plan another agent can execute without rediscovering the work.
|
|
1178
|
-
|
|
1179
|
-
## Must pass
|
|
1180
|
-
|
|
1181
|
-
- Outcome: \`summary\` names the user-visible result, not an internal activity.
|
|
1182
|
-
- Requirements: acceptance criteria, constraints, and non-goals that affect
|
|
1183
|
-
implementation are captured in \`requirements\`.
|
|
1184
|
-
- Decisions: assumptions, scope choices, and architecture choices already made
|
|
1185
|
-
are captured in \`decisions\`.
|
|
1186
|
-
- Uncertainty: specification uncertainty is resolved by a decision or a user
|
|
1187
|
-
question; environment uncertainty is resolved by inspection, discovery, or a
|
|
1188
|
-
first evidence-producing feature.
|
|
1189
|
-
- Feature shape: each feature has one coherent outcome and can be reviewed on
|
|
1190
|
-
its own.
|
|
1191
|
-
- Targets: each feature names bounded files, modules, routes, commands, docs, or
|
|
1192
|
-
generated surfaces. Whole-repo targets are allowed only for explicit broad
|
|
1193
|
-
audits or final validation.
|
|
1194
|
-
- Validation: each feature names expected check levels, such as targeted unit,
|
|
1195
|
-
integration, browser/e2e, package/build, docs/static, cleanup preservation, or
|
|
1196
|
-
broad project gate.
|
|
1197
|
-
- Dependencies: \`dependsOn\` captures true ordering and avoids hidden dependency
|
|
1198
|
-
chains.
|
|
1199
|
-
- Review policy: \`finalReviewPolicy\` is \`detailed\` when the work changes
|
|
1200
|
-
behavior, persistence, public contracts, security posture, release surfaces,
|
|
1201
|
-
or multiple modules.
|
|
1202
|
-
|
|
1203
|
-
## Revise when you see this
|
|
1204
|
-
|
|
1205
|
-
- A feature title describes a step like "update files" instead of a result.
|
|
1206
|
-
- A validation entry says only "manual testing" or "run tests".
|
|
1207
|
-
- A feature has targets but no behavior or artifact that can be judged.
|
|
1208
|
-
- A feature claims cleanup or simplification without an evidence-producing
|
|
1209
|
-
audit or cited smell.
|
|
1210
|
-
- A docs feature depends on behavior that is not yet implemented but lacks
|
|
1211
|
-
\`dependsOn\`.
|
|
1212
|
-
- A low-risk \`finalReviewPolicy: "broad"\` is used while the plan crosses runtime,
|
|
1213
|
-
schema, persistence, security, or release boundaries.
|
|
1214
|
-
|
|
1215
|
-
## Approval summary
|
|
1216
|
-
|
|
1217
|
-
When presenting the plan for approval, include:
|
|
1218
|
-
|
|
1219
|
-
- The promised outcome.
|
|
1220
|
-
- The feature order and any dependencies that matter.
|
|
1221
|
-
- The main validation levels.
|
|
1222
|
-
- Material assumptions in \`decisions\`.
|
|
1223
|
-
- Any known gaps that remain intentional.
|
|
1224
|
-
`;
|
|
1225
|
-
|
|
1226
|
-
// skills/flow-plan/references/planning-examples.md
|
|
1227
|
-
var planning_examples_default = `# Planning examples
|
|
1228
|
-
|
|
1229
|
-
## Rate limiting feature set
|
|
1230
|
-
|
|
1231
|
-
Human summary:
|
|
1232
|
-
|
|
1233
|
-
1. **In-memory rate limit middleware** - add request counting and response headers for one-process deployments.
|
|
1234
|
-
2. **Redis-backed limiter** - add shared store adapter for multi-instance deployments.
|
|
1235
|
-
3. **Operator docs** - document configuration and rollout notes.
|
|
1236
|
-
|
|
1237
|
-
Payload:
|
|
1238
|
-
|
|
1239
|
-
\`\`\`json
|
|
1240
|
-
{
|
|
1241
|
-
"goal": "Add API rate limiting with local and Redis-backed stores",
|
|
1242
|
-
"plan": {
|
|
1243
|
-
"summary": "Add configurable rate limiting for API routes.",
|
|
1244
|
-
"overview": "Implement middleware first, then a Redis store, then document rollout.",
|
|
1245
|
-
"requirements": [
|
|
1246
|
-
"Preserve existing route behavior except rate-limit responses.",
|
|
1247
|
-
"Expose deterministic headers for limit, remaining, and reset time."
|
|
1248
|
-
],
|
|
1249
|
-
"decisions": [
|
|
1250
|
-
"Start with an in-memory store for single-process deployments.",
|
|
1251
|
-
"Keep Redis behind a store interface so tests can use a mock."
|
|
1252
|
-
],
|
|
1253
|
-
"finalReviewPolicy": "detailed",
|
|
1254
|
-
"features": [
|
|
1255
|
-
{
|
|
1256
|
-
"id": "rate-limit-middleware",
|
|
1257
|
-
"title": "In-memory limiter",
|
|
1258
|
-
"summary": "Add middleware, config, and tests for single-process rate limiting.",
|
|
1259
|
-
"targets": ["src/middleware/rate-limit.ts", "src/app.ts", "src/config.ts"],
|
|
1260
|
-
"validation": ["route tests for limit/reset/header behavior", "typecheck"],
|
|
1261
|
-
"dependsOn": []
|
|
1262
|
-
},
|
|
1263
|
-
{
|
|
1264
|
-
"id": "redis-store",
|
|
1265
|
-
"title": "Redis store",
|
|
1266
|
-
"summary": "Add a Redis-backed rate limit store without changing middleware behavior.",
|
|
1267
|
-
"targets": ["src/middleware/stores/redis.ts", "src/middleware/rate-limit.ts"],
|
|
1268
|
-
"validation": ["store tests with Redis mock", "manual two-process recipe if practical"],
|
|
1269
|
-
"dependsOn": ["rate-limit-middleware"]
|
|
1270
|
-
},
|
|
1271
|
-
{
|
|
1272
|
-
"id": "operator-docs",
|
|
1273
|
-
"title": "Operator docs",
|
|
1274
|
-
"summary": "Document configuration, headers, and rollout guidance.",
|
|
1275
|
-
"targets": ["README.md", "docs/operations.md"],
|
|
1276
|
-
"validation": ["lint docs if available", "review examples against implemented config"],
|
|
1277
|
-
"dependsOn": ["redis-store"]
|
|
1278
|
-
}
|
|
1279
|
-
]
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
\`\`\`
|
|
1283
|
-
|
|
1284
|
-
## Review-first cleanup
|
|
1285
|
-
|
|
1286
|
-
Bad plan:
|
|
1287
|
-
|
|
1288
|
-
\`\`\`text
|
|
1289
|
-
1. Simplify services
|
|
1290
|
-
2. Remove duplication
|
|
1291
|
-
3. Improve tests
|
|
1292
|
-
\`\`\`
|
|
1293
|
-
|
|
1294
|
-
Why it is bad: no evidence names which services are actually tangled, what duplication exists, or which behavior needs test coverage.
|
|
1295
|
-
|
|
1296
|
-
Better plan:
|
|
1297
|
-
|
|
1298
|
-
\`\`\`text
|
|
1299
|
-
1. Audit service layer - produce evidence-backed findings with file:line citations, guards checked, and follow-up order.
|
|
1300
|
-
2. Consolidate confirmed config parsing duplication - only if the audit proves the duplication exists and is safe to merge.
|
|
1301
|
-
3. Add behavior-preservation tests for the changed service paths.
|
|
1302
|
-
\`\`\`
|
|
1303
|
-
|
|
1304
|
-
## Bugfix plan
|
|
1305
|
-
|
|
1306
|
-
Human summary:
|
|
1307
|
-
|
|
1308
|
-
1. Reproduce and localize the failed password reset redirect.
|
|
1309
|
-
2. Fix the redirect state handling and cover the regression.
|
|
1310
|
-
3. Update release notes only if user-facing behavior changed.
|
|
1311
|
-
|
|
1312
|
-
Payload:
|
|
1313
|
-
|
|
1314
|
-
\`\`\`json
|
|
1315
|
-
{
|
|
1316
|
-
"goal": "Fix password reset links landing users on the wrong page",
|
|
1317
|
-
"plan": {
|
|
1318
|
-
"summary": "Password reset links land users on the intended reset confirmation flow.",
|
|
1319
|
-
"overview": "Start with a focused reproduction, then fix the redirect state and update user-facing notes only if the behavior change needs documentation.",
|
|
1320
|
-
"requirements": [
|
|
1321
|
-
"Preserve existing token validation and expiry behavior.",
|
|
1322
|
-
"Users with valid reset links should not be sent to the generic sign-in page before completing the reset."
|
|
1323
|
-
],
|
|
1324
|
-
"decisions": [
|
|
1325
|
-
"Treat the current redirect mismatch as a regression until reproduction proves otherwise."
|
|
1326
|
-
],
|
|
1327
|
-
"finalReviewPolicy": "detailed",
|
|
1328
|
-
"features": [
|
|
1329
|
-
{
|
|
1330
|
-
"id": "reset-redirect-repro",
|
|
1331
|
-
"title": "Redirect reproduction",
|
|
1332
|
-
"summary": "Produce a failing focused check or trace that identifies where the reset redirect is lost.",
|
|
1333
|
-
"targets": ["src/auth/reset", "tests/auth"],
|
|
1334
|
-
"validation": ["targeted unit or integration reproduction for reset redirect behavior"],
|
|
1335
|
-
"dependsOn": []
|
|
1336
|
-
},
|
|
1337
|
-
{
|
|
1338
|
-
"id": "reset-redirect-fix",
|
|
1339
|
-
"title": "Redirect fix",
|
|
1340
|
-
"summary": "Preserve reset redirect state through token validation and completion.",
|
|
1341
|
-
"targets": ["src/auth/reset", "tests/auth"],
|
|
1342
|
-
"validation": ["targeted regression test passes", "auth package/build check if available"],
|
|
1343
|
-
"dependsOn": ["reset-redirect-repro"]
|
|
1344
|
-
},
|
|
1345
|
-
{
|
|
1346
|
-
"id": "reset-redirect-notes",
|
|
1347
|
-
"title": "User-facing notes",
|
|
1348
|
-
"summary": "Document the corrected reset-link behavior if release notes or help text mention the flow.",
|
|
1349
|
-
"targets": ["CHANGELOG.md", "docs/auth.md"],
|
|
1350
|
-
"validation": ["docs/static check if available", "review docs against implemented behavior"],
|
|
1351
|
-
"dependsOn": ["reset-redirect-fix"]
|
|
1352
|
-
}
|
|
1353
|
-
]
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
\`\`\`
|
|
1357
|
-
|
|
1358
|
-
## UI/frontend plan
|
|
1359
|
-
|
|
1360
|
-
Human summary:
|
|
1361
|
-
|
|
1362
|
-
1. Map the current checkout empty state and responsive constraints.
|
|
1363
|
-
2. Implement the empty state with accessible controls and mobile layout.
|
|
1364
|
-
3. Verify the visual states with screenshots or browser evidence.
|
|
1365
|
-
|
|
1366
|
-
Good feature outline:
|
|
1367
|
-
|
|
1368
|
-
\`\`\`text
|
|
1369
|
-
1. Empty-state discovery - inspect the route, component boundaries, design tokens, existing empty states, and likely responsive breakpoints.
|
|
1370
|
-
2. Empty-state implementation - add the checkout empty state, action wiring, focus order, and loading/error boundaries in the existing component style.
|
|
1371
|
-
3. Visual and interaction verification - capture desktop and mobile evidence, run available route/component checks, and fix overlap or accessibility regressions.
|
|
1372
|
-
\`\`\`
|
|
1373
|
-
|
|
1374
|
-
Why this is better than one "build UI" feature: the plan names the uncertain
|
|
1375
|
-
surface first, keeps implementation scoped to the route/components, and makes
|
|
1376
|
-
visual evidence part of completion rather than an afterthought.
|
|
1377
|
-
|
|
1378
|
-
## Runtime or schema plan
|
|
1379
|
-
|
|
1380
|
-
Human summary:
|
|
1381
|
-
|
|
1382
|
-
1. Introduce the schema change behind a backward-compatible parser.
|
|
1383
|
-
2. Migrate callers and persistence writes.
|
|
1384
|
-
3. Add compatibility validation and docs.
|
|
1385
|
-
|
|
1386
|
-
Good feature outline:
|
|
1387
|
-
|
|
1388
|
-
\`\`\`text
|
|
1389
|
-
1. Compatible schema reader - accept old and new session payloads, with targeted parser tests for both.
|
|
1390
|
-
2. New writer path - emit the new field from runtime transitions and update affected callers.
|
|
1391
|
-
3. Compatibility sweep - run persistence/workspace tests, update docs, and verify old sessions still recover.
|
|
1392
|
-
\`\`\`
|
|
1393
|
-
|
|
1394
|
-
Use \`finalReviewPolicy: "detailed"\` for this shape. Persistence and schema work
|
|
1395
|
-
usually has hidden downstream contracts, so feature validation should name both
|
|
1396
|
-
targeted parser checks and broader workspace/runtime gates.
|
|
1397
|
-
|
|
1398
|
-
## Docs-only plan
|
|
1399
|
-
|
|
1400
|
-
Docs-only work can use \`finalReviewPolicy: "broad"\` when it does not change
|
|
1401
|
-
commands, configuration, generated files, or release metadata.
|
|
1402
|
-
|
|
1403
|
-
Good feature outline:
|
|
1404
|
-
|
|
1405
|
-
\`\`\`text
|
|
1406
|
-
1. Align installation docs - update README and troubleshooting steps for the current setup flow.
|
|
1407
|
-
2. Verify commands and links - check documented commands against package scripts and make sure links/paths resolve.
|
|
1408
|
-
\`\`\`
|
|
1409
|
-
|
|
1410
|
-
Bad validation:
|
|
1411
|
-
|
|
1412
|
-
\`\`\`text
|
|
1413
|
-
validation: ["manual review"]
|
|
1414
|
-
\`\`\`
|
|
1415
|
-
|
|
1416
|
-
Better validation:
|
|
1417
|
-
|
|
1418
|
-
\`\`\`text
|
|
1419
|
-
validation: ["docs/static link and path review", "command examples checked against package scripts"]
|
|
1420
|
-
\`\`\`
|
|
1421
|
-
|
|
1422
|
-
## Audit-first and review-first plans
|
|
1423
|
-
|
|
1424
|
-
Use an evidence-producing first feature when the request asks to "review",
|
|
1425
|
-
"audit", "clean up", "modernize", or "improve" a broad area.
|
|
1426
|
-
|
|
1427
|
-
Good feature outline:
|
|
1428
|
-
|
|
1429
|
-
\`\`\`text
|
|
1430
|
-
1. Audit checkout state management - cite concrete findings with file:line evidence, refutation checks, severity, and recommended fix order.
|
|
1431
|
-
2. Fix confirmed high-impact state leak - only for findings that survived the audit.
|
|
1432
|
-
3. Regression validation - add or run checks covering the changed state paths.
|
|
1433
|
-
\`\`\`
|
|
1434
|
-
|
|
1435
|
-
Do not plan fixes for guessed findings. If the audit might find no actionable
|
|
1436
|
-
issue, say that in the first feature summary and make later features conditional
|
|
1437
|
-
on evidence.
|
|
1438
|
-
|
|
1439
|
-
## Validation examples
|
|
1440
|
-
|
|
1441
|
-
Weak:
|
|
1442
|
-
|
|
1443
|
-
\`\`\`text
|
|
1444
|
-
validation: ["run tests", "manual testing"]
|
|
1445
|
-
\`\`\`
|
|
1446
|
-
|
|
1447
|
-
Stronger:
|
|
1448
|
-
|
|
1449
|
-
\`\`\`text
|
|
1450
|
-
validation: [
|
|
1451
|
-
"targeted unit tests for empty and invalid input",
|
|
1452
|
-
"integration test for persisted session recovery",
|
|
1453
|
-
"package/build gate for changed TypeScript exports",
|
|
1454
|
-
"browser screenshot at desktop and mobile widths for layout-sensitive UI",
|
|
1455
|
-
"docs/static review for changed command examples"
|
|
1456
|
-
]
|
|
1457
|
-
\`\`\`
|
|
1458
|
-
|
|
1459
|
-
The stronger version says what level of evidence is expected and which behavior
|
|
1460
|
-
or surface it covers.
|
|
1461
|
-
|
|
1462
|
-
## Decomposition anti-patterns
|
|
1463
|
-
|
|
1464
|
-
- Feature per file when behavior crosses files.
|
|
1465
|
-
- Feature per implementation step with no user-visible or reviewable outcome.
|
|
1466
|
-
- Plan fixes for findings not yet verified.
|
|
1467
|
-
- Validation that only says "manual testing".
|
|
1468
|
-
- Targets that name the entire repo.
|
|
1469
|
-
- Features with hidden dependencies instead of \`dependsOn\`.
|
|
1470
|
-
`;
|
|
1471
|
-
|
|
1472
|
-
// skills/flow-plan/SKILL.md
|
|
1473
|
-
var SKILL_default4 = `---
|
|
1474
|
-
name: flow-plan
|
|
1475
|
-
description: "Use when Flow work needs planning before implementation: a new goal to turn into an approved Flow feature plan, a draft plan to revise, or a decomposition or plan-approval decision in the v4 skills-first runtime. For executing an approved feature use flow-run; for the full goal-to-completion loop use flow."
|
|
1476
|
-
---
|
|
1477
|
-
|
|
1478
|
-
# Flow Plan
|
|
1479
|
-
|
|
1480
|
-
Use this skill before implementation. The output is a compact plan the runtime can enforce and future agents can execute without rediscovering the goal.
|
|
1481
|
-
|
|
1482
|
-
If \`flow_plan_save\` or \`flow_plan_approve\` is unavailable, stop and tell the user to check that \`opencode-plugin-flow\` is loaded in OpenCode. Planning requires the loaded Flow runtime.
|
|
1483
|
-
|
|
1484
|
-
## Inspect first
|
|
1485
|
-
|
|
1486
|
-
- Read the files, docs, tests, package scripts, and local conventions that determine the work.
|
|
1487
|
-
- For broad discovery, read \`references/parallel-discovery.md\` after a serial orientation pass. Use \`../flow/references/parallel-orchestration.md\` when discovery needs multiple workers, and write its pass manifest before fan-out.
|
|
1488
|
-
- Helper rule: when a named helper skill is unavailable, record a planning gap
|
|
1489
|
-
and keep the corresponding claims conservative instead of simulating its
|
|
1490
|
-
checks.
|
|
1491
|
-
- For complex validation, regression-sensitive changes, browser QA, route QA,
|
|
1492
|
-
failure-prone checks, or uncertain test strategy, load \`flow-test\`.
|
|
1493
|
-
- For cleanup/refactor goals, load \`flow-deslop\`.
|
|
1494
|
-
- For UI/frontend goals, load \`flow-ui-quality\`.
|
|
1495
|
-
- Do not invent findings. Broad "review and fix" goals start with a review-first feature whose deliverable is evidence-backed findings.
|
|
1496
|
-
|
|
1497
|
-
## Reduce uncertainty before decomposing
|
|
1498
|
-
|
|
1499
|
-
A vague goal does not slice into reliable features yet. Name what is uncertain,
|
|
1500
|
-
because the two kinds resolve differently:
|
|
1501
|
-
|
|
1502
|
-
- **Specification uncertainty** — what the user wants: ambiguous goal, missing
|
|
1503
|
-
acceptance criteria, unstated constraints. Resolve by stating an explicit
|
|
1504
|
-
assumption in \`decisions\` and proceeding, or by asking only when a wrong
|
|
1505
|
-
guess would be expensive to undo.
|
|
1506
|
-
- **Environment uncertainty** — facts the repo, docs, commands, or data can
|
|
1507
|
-
answer: code shape, schema, API behavior, current conventions. Resolve by
|
|
1508
|
-
inspecting or by a discovery pass, never by asking the user.
|
|
1509
|
-
|
|
1510
|
-
Spend the cheapest probe that removes the most uncertainty first: local reads
|
|
1511
|
-
before worker fan-out, fan-out before user questions. Decompose into features
|
|
1512
|
-
only once the remaining uncertainty is low enough that \`targets\` and
|
|
1513
|
-
\`validation\` can be stated concretely; otherwise the first feature is a
|
|
1514
|
-
review-first or discovery deliverable that produces the missing evidence.
|
|
1515
|
-
|
|
1516
|
-
## Plan shape
|
|
1517
|
-
|
|
1518
|
-
Call \`flow_plan_save\` with:
|
|
1519
|
-
|
|
1520
|
-
\`\`\`json
|
|
1521
|
-
{
|
|
1522
|
-
"goal": "user-visible goal",
|
|
1523
|
-
"plan": {
|
|
1524
|
-
"summary": "one-sentence outcome",
|
|
1525
|
-
"overview": "implementation strategy and boundaries",
|
|
1526
|
-
"requirements": ["constraints, acceptance criteria, user promises"],
|
|
1527
|
-
"decisions": ["architecture or scope decisions already made"],
|
|
1528
|
-
"finalReviewPolicy": "detailed",
|
|
1529
|
-
"features": [
|
|
1530
|
-
{
|
|
1531
|
-
"id": "lowercase-kebab-case",
|
|
1532
|
-
"title": "Short title",
|
|
1533
|
-
"summary": "Outcome this feature delivers",
|
|
1534
|
-
"reviewDepth": "standard",
|
|
1535
|
-
"targets": ["files, modules, routes, commands, or docs in scope"],
|
|
1536
|
-
"validation": ["focused checks expected before completion"],
|
|
1537
|
-
"dependsOn": []
|
|
1538
|
-
}
|
|
1539
|
-
]
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
\`\`\`
|
|
1543
|
-
|
|
1544
|
-
Use only \`finalReviewPolicy: "broad"\` or \`"detailed"\`. These are the canonical final-review policy and \`reviewDepth\` enum values. Use \`"broad"\` only for low-risk, narrow work. Use \`"detailed"\` for behavioral changes, cross-module edits, migrations, releases, security-sensitive code, or large refactors.
|
|
1545
|
-
|
|
1546
|
-
Set each feature's \`reviewDepth\` to one of:
|
|
1547
|
-
|
|
1548
|
-
- \`quick\`: docs, comments, config-only changes, generated output, or mechanical changes fully covered by tooling.
|
|
1549
|
-
- \`standard\`: the default for ordinary implementation slices. The review reads every changed file and relevant tests.
|
|
1550
|
-
- \`detailed\`: persistence, migrations, concurrency, security, cross-module behavior, release/package surfaces, large refactors, weak validation, or any work where a missed edge case would be expensive.
|
|
1551
|
-
|
|
1552
|
-
Do not make reviews shallower to save tokens. Reduce token use by splitting features, keeping \`targets\` precise, and using scoped review packets during execution.
|
|
1553
|
-
|
|
1554
|
-
## Plan quality gate
|
|
1555
|
-
|
|
1556
|
-
Before saving or asking for approval, load
|
|
1557
|
-
\`references/plan-quality-checklist.md\` and check the draft against it. Revise the
|
|
1558
|
-
plan until it passes, or record the remaining gap in \`decisions\` when the gap is
|
|
1559
|
-
an intentional assumption. Do not approve a plan whose outcome, requirements,
|
|
1560
|
-
targets, validation, or dependency order are still too vague for another agent
|
|
1561
|
-
to execute.
|
|
1562
|
-
|
|
1563
|
-
## Feature sizing
|
|
1564
|
-
|
|
1565
|
-
- Each feature should have one owner, one coherent outcome, and a validation story.
|
|
1566
|
-
- Split by dependency order: foundations before callers, schema before consumers, implementation before docs when docs depend on behavior.
|
|
1567
|
-
- Avoid "misc cleanup" features. Tie cleanup to evidence and targets.
|
|
1568
|
-
- Keep feature ids stable once the plan is approved.
|
|
1569
|
-
- Put scope boundaries in \`targets\` and expected checks in \`validation\`. Each
|
|
1570
|
-
validation entry should name the expected test level, such as targeted unit,
|
|
1571
|
-
integration, browser/e2e, package/build, docs/static, cleanup preservation, or
|
|
1572
|
-
broad project gate.
|
|
1573
|
-
- When a feature may benefit from parallel implementation, make \`targets\`
|
|
1574
|
-
precise enough for later ownership decisions: name exact modules, docs,
|
|
1575
|
-
commands, or route groups, and use \`dependsOn\` to preserve prerequisite order.
|
|
1576
|
-
Broad shared-contract work should stay in one feature or an earlier foundation
|
|
1577
|
-
feature so later candidate passes can own disjoint paths safely.
|
|
1578
|
-
- Assign \`reviewDepth\` from risk. Use \`detailed\` for persistence, migration,
|
|
1579
|
-
concurrency, security, final-delivery-adjacent, or cross-module slices; use
|
|
1580
|
-
\`standard\` for normal code changes; reserve \`quick\` for low-risk non-behavioral
|
|
1581
|
-
work.
|
|
1582
|
-
|
|
1583
|
-
## Approval
|
|
1584
|
-
|
|
1585
|
-
After saving, summarize the plan to the user. Call \`flow_plan_approve\` only after explicit user approval, unless the user already authorized autonomous implementation. Approved plans are immutable; changing them later requires reset/closure rather than silent edits.
|
|
1586
|
-
|
|
1587
|
-
See \`references/planning-examples.md\` for payload examples and decomposition
|
|
1588
|
-
anti-patterns.
|
|
1589
|
-
`;
|
|
1590
|
-
|
|
1591
|
-
// skills/flow-review/references/review-rubric.md
|
|
1592
|
-
var review_rubric_default = `# Review rubric
|
|
1593
|
-
|
|
1594
|
-
Use this to decide whether a \`featureReview\` or \`finalReview\` payload may pass.
|
|
1595
|
-
|
|
1596
|
-
## Finding classes
|
|
1597
|
-
|
|
1598
|
-
- **correctness**: wrong result, broken state transition, bad edge case, race, data loss, or crash.
|
|
1599
|
-
- **contract**: public API, CLI, config, persisted data, or documented behavior changed without plan approval.
|
|
1600
|
-
- **security/privacy**: unsafe input handling, secret exposure, permission bypass, or insecure default.
|
|
1601
|
-
- **test-coverage**: behavioral change lacks a check strong enough for the risk.
|
|
1602
|
-
- **maintainability**: complexity or coupling creates concrete future-change risk.
|
|
1603
|
-
- **ui/accessibility**: user cannot complete the workflow, layout breaks, accessibility basics fail, or visual claims lack evidence.
|
|
1604
|
-
|
|
1605
|
-
## Severity
|
|
1606
|
-
|
|
1607
|
-
- **blocking**: must fail the review. Includes incorrect behavior, data loss, security risk, unverifiable completion claims, missing validation for behavioral work, or unresolved scope drift.
|
|
1608
|
-
- **advisory**: worth noting but does not block the current goal.
|
|
1609
|
-
|
|
1610
|
-
If unsure whether a finding is real, read more or downgrade it. Do not promote guesses to blockers.
|
|
1611
|
-
|
|
1612
|
-
## Feature review checklist
|
|
1613
|
-
|
|
1614
|
-
- The work matches the active feature's \`summary\`, \`targets\`, and dependencies.
|
|
1615
|
-
- Plan \`requirements\` and \`decisions\` are still honored.
|
|
1616
|
-
- Changed files were read, not just summarized.
|
|
1617
|
-
- Validation evidence covers the behavior touched.
|
|
1618
|
-
- New tests or manual checks would fail or visibly differ without the change where practical.
|
|
1619
|
-
- No unrelated scope slipped in.
|
|
1620
|
-
- Public contracts and downstream callers still work.
|
|
1621
|
-
|
|
1622
|
-
## Final review checklist
|
|
1623
|
-
|
|
1624
|
-
- The original goal is satisfied by the delivered behavior or artifacts.
|
|
1625
|
-
- Every approved requirement is either met or explicitly accounted for by an
|
|
1626
|
-
accepted gap.
|
|
1627
|
-
- Plan decisions and scope boundaries still match the implementation.
|
|
1628
|
-
- Every planned feature is complete, has recorded validation evidence, and
|
|
1629
|
-
contributes to the final outcome.
|
|
1630
|
-
- Feature dependencies were completed in an order that makes the evidence
|
|
1631
|
-
trustworthy.
|
|
1632
|
-
- Changed artifacts match the plan's \`targets\`; extra changed surfaces are
|
|
1633
|
-
explained and reviewed.
|
|
1634
|
-
- Broad validation ran and passed, or any skipped broad check is justified as a
|
|
1635
|
-
non-blocking gap.
|
|
1636
|
-
- The final \`reviewDepth\` equals the approved \`finalReviewPolicy\`; the only final-review enum values are \`broad\` and \`detailed\`.
|
|
1637
|
-
- Feature-level reviews have no unresolved blocking findings.
|
|
1638
|
-
- Docs, commands, package metadata, and release surfaces match the delivered behavior.
|
|
1639
|
-
- Remaining gaps are explicit and do not contradict \`kind: "completed"\`.
|
|
1640
|
-
|
|
1641
|
-
## Final convergence scan
|
|
1642
|
-
|
|
1643
|
-
Run this scan before returning a passing \`finalReview\`:
|
|
1644
|
-
|
|
1645
|
-
1. Restate the original goal and the approved plan summary in your own words.
|
|
1646
|
-
2. Map each requirement to delivered evidence, validation output, or an explicit
|
|
1647
|
-
accepted gap.
|
|
1648
|
-
3. Walk every planned feature and confirm its completion evidence, review
|
|
1649
|
-
result, and validation level.
|
|
1650
|
-
4. Compare the changed files, docs, commands, generated surfaces, and package
|
|
1651
|
-
metadata to the planned targets and requirements.
|
|
1652
|
-
5. Check whether the validation evidence would have caught the main failure
|
|
1653
|
-
modes introduced by the work.
|
|
1654
|
-
6. Decide whether remaining gaps are advisory or blocking before setting
|
|
1655
|
-
\`status\`.
|
|
1656
|
-
|
|
1657
|
-
Fail the final review when the delivered work cannot be traced back to the
|
|
1658
|
-
approved goal and requirements, even if each individual feature review passed.
|
|
1659
|
-
|
|
1660
|
-
## Payloads
|
|
1661
|
-
|
|
1662
|
-
Feature review:
|
|
1663
|
-
|
|
1664
|
-
\`\`\`json
|
|
1665
|
-
{
|
|
1666
|
-
"featureReviewDepth": "standard",
|
|
1667
|
-
"featureReview": {
|
|
1668
|
-
"status": "passed",
|
|
1669
|
-
"summary": "Reviewed changed runtime files and focused tests; validation covers the new gate.",
|
|
1670
|
-
"blockingFindings": []
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
\`\`\`
|
|
1674
|
-
|
|
1675
|
-
Failed feature review:
|
|
1676
|
-
|
|
1677
|
-
\`\`\`json
|
|
1678
|
-
{
|
|
1679
|
-
"featureReviewDepth": "detailed",
|
|
1680
|
-
"featureReview": {
|
|
1681
|
-
"status": "failed",
|
|
1682
|
-
"summary": "Validation does not exercise the changed persistence path.",
|
|
1683
|
-
"blockingFindings": [
|
|
1684
|
-
{
|
|
1685
|
-
"summary": "No test covers archive removal of .flow/session.json after close.",
|
|
1686
|
-
"severity": "blocking"
|
|
1687
|
-
}
|
|
1688
|
-
]
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
\`\`\`
|
|
1692
|
-
|
|
1693
|
-
Final review:
|
|
1694
|
-
|
|
1695
|
-
\`\`\`json
|
|
1696
|
-
{
|
|
1697
|
-
"status": "passed",
|
|
1698
|
-
"summary": "Reviewed plan scope, all changed files, broad validation, and release metadata.",
|
|
1699
|
-
"blockingFindings": [],
|
|
1700
|
-
"reviewDepth": "detailed"
|
|
1701
|
-
}
|
|
1702
|
-
\`\`\`
|
|
1703
|
-
|
|
1704
|
-
## Audit report reviews
|
|
1705
|
-
|
|
1706
|
-
When reviewing a findings report, verify findings adversarially:
|
|
1707
|
-
|
|
1708
|
-
- Check the cited file and surrounding code.
|
|
1709
|
-
- Trace mitigating paths before accepting blocking severity.
|
|
1710
|
-
- Confirm the deployment model used for severity.
|
|
1711
|
-
- Dedupe overlapping findings.
|
|
1712
|
-
- Downgrade or reject findings that do not survive refutation.
|
|
1713
|
-
|
|
1714
|
-
Approve only on evidence actually inspected. A review is a claim of coverage, not a courtesy stamp.
|
|
1715
|
-
`;
|
|
1716
|
-
|
|
1717
|
-
// skills/flow-review/SKILL.md
|
|
1718
|
-
var SKILL_default5 = `---
|
|
1719
|
-
name: flow-review
|
|
1720
|
-
description: "Use when Flow work needs a review verdict in the v4 runtime: a completed feature awaiting its featureReview, a final session review, or an assigned review slice. Validation evidence gathering stays in flow-test; cleanup judgment stays in flow-deslop."
|
|
1721
|
-
---
|
|
1722
|
-
|
|
1723
|
-
# Flow Review
|
|
1724
|
-
|
|
1725
|
-
Use this skill for review. The reviewer is usually read-only and does not mutate Flow state. The manager records the returned review payload inside \`flow_feature_complete\`.
|
|
1726
|
-
|
|
1727
|
-
If Flow tools, required Flow skills, or required references are unavailable or
|
|
1728
|
-
stale, perform an advisory review and say that no Flow-gated review payload was
|
|
1729
|
-
recorded.
|
|
1730
|
-
|
|
1731
|
-
## Execution contexts
|
|
1732
|
-
|
|
1733
|
-
These instructions run in two contexts, and only one of them can load helpers:
|
|
1734
|
-
|
|
1735
|
-
- **Manager context**: the manager reviews inside the Flow loop (the \`flow\` or
|
|
1736
|
-
\`flow-run\` skills, or a bundled public Flow command) before recording
|
|
1737
|
-
evidence. The manager may load helper skills and fan out read-only workers.
|
|
1738
|
-
- **Hidden reviewer context**: \`/flow-review\` runs as the \`flow-reviewer\`
|
|
1739
|
-
subagent, whose permissions deny skill loading, shell commands, and
|
|
1740
|
-
subagents. In this context, skip every "load" and "fan out" instruction
|
|
1741
|
-
below: judge from the diff, the plan fields, and the recorded validation
|
|
1742
|
-
evidence, and record a coverage gap for any judgment that would have needed
|
|
1743
|
-
a helper skill or a command run.
|
|
1744
|
-
|
|
1745
|
-
## Start
|
|
1746
|
-
|
|
1747
|
-
- Call \`flow_status\` when available.
|
|
1748
|
-
- Identify whether this is a feature review or final review.
|
|
1749
|
-
- Prefer the manager's compact review packet over parent-session memory. The
|
|
1750
|
-
packet should name the active feature, minimum \`reviewDepth\`, changed files,
|
|
1751
|
-
diff summary, validation evidence, and targeted paths or risk lenses. If the
|
|
1752
|
-
packet is missing important scope or evidence, record that as a coverage gap
|
|
1753
|
-
or blocker instead of searching the full conversation transcript.
|
|
1754
|
-
- Read the approved plan fields relevant to the work: \`requirements\`, \`decisions\`, feature \`targets\`, feature \`validation\`, and dependencies.
|
|
1755
|
-
- For final review, also compare the original goal, full feature list, completed
|
|
1756
|
-
feature evidence, changed artifacts, and final validation against the
|
|
1757
|
-
convergence checklist in \`references/review-rubric.md\`.
|
|
1758
|
-
- Inspect the actual diff, changed files, tests, and validation output. Do not review only the completion summary.
|
|
1759
|
-
- In manager context, load \`flow-test\` for validation-heavy,
|
|
1760
|
-
regression-sensitive, browser QA, or unclear coverage reviews. If it is
|
|
1761
|
-
unavailable or you are the hidden reviewer, record a coverage gap and treat
|
|
1762
|
-
missing validation evidence as a gap or blocker based on user impact.
|
|
1763
|
-
- Load \`references/review-rubric.md\` for severity, depth, and payload shape.
|
|
1764
|
-
|
|
1765
|
-
## Feature Review Depth
|
|
1766
|
-
|
|
1767
|
-
- **quick**: docs, comments, config-only changes, or mechanical changes fully covered by tooling.
|
|
1768
|
-
- **standard**: default feature review. Read every changed file and relevant tests.
|
|
1769
|
-
- **detailed**: risky behavior, persistence, security, cross-module refactors, migrations, releases, or weak validation.
|
|
1770
|
-
|
|
1771
|
-
\`quick\` and \`standard\` are feature-review depth descriptions only. Final reviews use \`reviewDepth: "broad"\` or \`"detailed"\` to match the plan's \`finalReviewPolicy\`; these runtime enum values are the canonical final-review terms. Claim only the depth actually performed. Missing evidence is a finding, not a nuisance.
|
|
1772
|
-
|
|
1773
|
-
## Output
|
|
1774
|
-
|
|
1775
|
-
For a feature review, return a packet the manager can copy into
|
|
1776
|
-
\`flow_feature_complete\`:
|
|
1777
|
-
|
|
1778
|
-
\`\`\`json
|
|
1779
|
-
{
|
|
1780
|
-
"featureReviewDepth": "standard",
|
|
1781
|
-
"featureReview": {
|
|
1782
|
-
"status": "passed",
|
|
1783
|
-
"summary": "what was reviewed and why it is acceptable",
|
|
1784
|
-
"blockingFindings": []
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
\`\`\`
|
|
1788
|
-
|
|
1789
|
-
\`featureReviewDepth\` must be at least the feature's planned \`reviewDepth\`.
|
|
1790
|
-
Use the actual depth performed: \`quick\`, \`standard\`, or \`detailed\`.
|
|
1791
|
-
|
|
1792
|
-
For a final review, return:
|
|
1793
|
-
|
|
1794
|
-
\`\`\`json
|
|
1795
|
-
{
|
|
1796
|
-
"status": "passed",
|
|
1797
|
-
"summary": "session-level review summary",
|
|
1798
|
-
"blockingFindings": [],
|
|
1799
|
-
"reviewDepth": "detailed"
|
|
1800
|
-
}
|
|
1801
|
-
\`\`\`
|
|
1802
|
-
|
|
1803
|
-
Use \`status: "failed"\` when any blocking finding remains. Advisory findings may be included in the prose summary, but \`blockingFindings\` contains only blockers.
|
|
1804
|
-
|
|
1805
|
-
## Special cases
|
|
1806
|
-
|
|
1807
|
-
- Cleanup/refactor: in manager context, load \`flow-deslop\`; verify the smell was real, refutation paths were checked, and behavior was preserved. If it is unavailable or you are the hidden reviewer, record a coverage gap instead of approving cleanup claims.
|
|
1808
|
-
- UI/frontend: in manager context, load \`flow-ui-quality\`; verify state coverage and visual evidence when a local target was available. If it is unavailable or you are the hidden reviewer, record a coverage gap and do not claim visual polish was verified.
|
|
1809
|
-
- Audit reports: use \`../flow-run/references/audit-rubric.md\`; findings must survive refutation before they can drive fix features.
|
|
1810
|
-
- Large reviews (manager context only): use
|
|
1811
|
-
\`../flow/references/parallel-orchestration.md\` for read-only slices by
|
|
1812
|
-
changed-file group, risk lens, or validation surface. Use the named review,
|
|
1813
|
-
audit, evidence, or validation agents from that reference instead of generic
|
|
1814
|
-
subagents. Write its pass manifest before fan-out and apply its Stage 6
|
|
1815
|
-
handoff acceptance and verification tiers; only the manager
|
|
1816
|
-
returns the final \`featureReview\` or \`finalReview\` payload. If that reference
|
|
1817
|
-
is unavailable in the current context (for example in a bundled public Flow
|
|
1818
|
-
command that does not include it), review serially and record the skipped
|
|
1819
|
-
fan-out as a coverage gap instead of improvising worker contracts. The hidden
|
|
1820
|
-
reviewer cannot spawn workers; it reviews its assigned scope directly and
|
|
1821
|
-
reports coverage gaps for the rest.
|
|
1822
|
-
|
|
1823
|
-
Never approve to unblock completion, fix findings in the review pass, or vouch for validation you did not inspect.
|
|
1824
|
-
`;
|
|
1825
|
-
|
|
1826
|
-
// skills/flow-run/references/audit-rubric.md
|
|
1827
|
-
var audit_rubric_default = `# Audit findings rubric
|
|
1828
|
-
|
|
1829
|
-
What counts as a valid finding when the feature's deliverable is a findings report: a codebase audit, a review-first feature, or any report whose findings a later feature will fix. The commands you run are still governed by \`validation-rubric.md\`; this rubric governs the findings themselves.
|
|
1830
|
-
|
|
1831
|
-
A findings report is a set of claims about code you did not write. Its failure mode is not "missed something" — it is the confident, accurately-cited finding that is wrong because the mitigating code path was never read. Accurate citations are necessary, never sufficient: a citation proves you found the suspicious site, not that the suspicion survives contact with the rest of the codebase.
|
|
1832
|
-
|
|
1833
|
-
## Refute before you report
|
|
1834
|
-
|
|
1835
|
-
Before any finding earns blocking severity (P1/P2 or equivalent), actively try to kill it:
|
|
1836
|
-
|
|
1837
|
-
- **Trace the mitigating paths.** Read the callers of the suspicious site and the code it delegates to. The question is never "could this line misbehave?" but "does anything between input and this line already prevent that?"
|
|
1838
|
-
- **Cross the layer boundary.** In a multi-layer repo, a finding in one layer is unverified until you have read its counterpart in the other. A frontend finding requires reading the backend handler it calls (it may already validate or dedupe); a library-internals finding requires checking what validation real callers pass through; an API finding requires checking what the client can actually send.
|
|
1839
|
-
- **Check the surrounding lifecycle.** State that "leaks" or "goes stale" may already be reset by an effect, a guard clause, or an invalidation a few lines away from where you stopped reading.
|
|
1840
|
-
|
|
1841
|
-
A finding that survives this pass is worth reporting. A finding you did not try to refute is a guess with a citation.
|
|
1842
|
-
|
|
1843
|
-
## Parallel audit slices
|
|
1844
|
-
|
|
1845
|
-
For broad audits, use \`../../flow/references/parallel-orchestration.md\` to split
|
|
1846
|
-
read-only slices by module, data flow, or risk lens. Workers surface candidates;
|
|
1847
|
-
the audit author owns the report. Apply its handoff format and verification
|
|
1848
|
-
gates. Before blocking severity, dedupe, trace guards, fill cross-layer checks,
|
|
1849
|
-
verify contested or high-stakes claims, and downgrade missing context.
|
|
1850
|
-
|
|
1851
|
-
## Every blocking finding records "guards checked"
|
|
1852
|
-
|
|
1853
|
-
In addition to evidence, why-it-matters, and fix shape, every blocking finding names the mitigating paths you traced and why they do not cover this case ("\`suggest_mappings()\` enforces one-to-one via \`used_a\`/\`used_b\` — but nothing dedupes after the frontend re-sorts" reads very differently from silence). No guards-checked line means the finding is unverified: downgrade it to advisory and say what you did not trace.
|
|
1854
|
-
|
|
1855
|
-
## Observed, not hypothesized
|
|
1856
|
-
|
|
1857
|
-
- A blocking finding describes behavior the current code exhibits, with the input that triggers it. "If the backend ever returns X" is a hypothesis about code you chose not to read — either read it and confirm, or record the item as a defense-in-depth note (advisory at most).
|
|
1858
|
-
- Uncertainty after tracing is honest — state it and rate by the realistic worst case. Uncertainty instead of tracing is padding.
|
|
1859
|
-
|
|
1860
|
-
## Severity is rated in deployment context
|
|
1861
|
-
|
|
1862
|
-
- The report header states the deployment model the product actually has: desktop app, shared server, library consumed by others, CLI, and so on.
|
|
1863
|
-
- Rate impact within that model. Unbounded memory in a single-user desktop process whose lifetime is one window is not the severity it would be in a long-running shared service. When a finding only matters under a deployment the product does not have, say so explicitly ("becomes blocking if this ships as a shared service") instead of rating for the imagined deployment.
|
|
1864
|
-
|
|
1865
|
-
## Report shape
|
|
1866
|
-
|
|
1867
|
-
\`\`\`
|
|
1868
|
-
header: scope audited; deployment context; validation commands actually run
|
|
1869
|
-
findings, strongest first, each with:
|
|
1870
|
-
- class and severity
|
|
1871
|
-
- evidence — file:line actually read
|
|
1872
|
-
- guards checked — mitigating paths traced and why they fall short (blocking findings)
|
|
1873
|
-
- why it matters — the concrete failure, with triggering input
|
|
1874
|
-
- fix shape — one sentence, not an implementation
|
|
1875
|
-
positive findings — what is genuinely solid, so fixes do not regress it
|
|
1876
|
-
follow-up order — correctness and persisted/user-input surfaces first
|
|
1877
|
-
\`\`\`
|
|
1878
|
-
|
|
1879
|
-
Never: promote a hypothesis to blocking severity; cite a line you did not read in context; rate severity against a deployment model the product does not have; pad the report to look thorough — six verified findings outrank nine where three die on first contact.
|
|
1880
|
-
`;
|
|
1881
|
-
|
|
1882
|
-
// skills/flow-run/references/validation-rubric.md
|
|
1883
|
-
var validation_rubric_default = `# Validation evidence rubric
|
|
1884
|
-
|
|
1885
|
-
Use this before recording \`flow_feature_complete\`.
|
|
1886
|
-
|
|
1887
|
-
## Evidence tiers
|
|
1888
|
-
|
|
1889
|
-
1. **Behavioral automated test**: a targeted unit/integration/e2e test exercises the changed behavior and fails without the change.
|
|
1890
|
-
2. **Manual reproducible check**: you ran the app, CLI, endpoint, or workflow and recorded exact steps plus observed result.
|
|
1891
|
-
3. **Indirect automated check**: typecheck, lint, build, or compile proves shape but not behavior. Acceptable alone only for docs, comments, renames fully covered by tooling, or purely mechanical changes.
|
|
1892
|
-
4. **Static inspection**: reading code without running anything. This is a gap, not completion evidence for behavioral work.
|
|
1893
|
-
|
|
1894
|
-
Use the strongest practical tier. For risky work, combine tiers.
|
|
1895
|
-
|
|
1896
|
-
## Recording rules
|
|
1897
|
-
|
|
1898
|
-
- Each \`validationRun\` entry has \`command\`, \`status\`, and \`summary\`.
|
|
1899
|
-
- Completion accepts only passing entries. Failed or skipped checks belong in the summary/notes and must be resolved or explained as blockers.
|
|
1900
|
-
- Do not claim a command was run unless it was run in this session or directly reported by a trusted worker with raw output.
|
|
1901
|
-
- Worker-reported command output must satisfy the verification stage of \`../../flow/references/parallel-orchestration.md\`: exact command, status, raw outcome summary, coverage, and manager acceptance.
|
|
1902
|
-
- Include scope in the summary: what behavior, files, routes, or states the check covered.
|
|
1903
|
-
- UI work should include browser or screenshot evidence when the app can run locally.
|
|
1904
|
-
- Cleanup/refactor work should show behavior preservation, not only formatting success.
|
|
1905
|
-
|
|
1906
|
-
## Scope
|
|
1907
|
-
|
|
1908
|
-
- Use \`validationScope: "targeted"\` for ordinary feature completion.
|
|
1909
|
-
- Use \`validationScope: "broad"\` only when the session is on its final feature and the project-level gate was run.
|
|
1910
|
-
|
|
1911
|
-
Broad validation usually means the repo's full check command, full relevant test suite, build, or equivalent release gate. If the broad gate cannot run, do not mark the final feature complete; report \`needs_input\` or fix the blocker.
|
|
1912
|
-
|
|
1913
|
-
## Good payload fragment
|
|
1914
|
-
|
|
1915
|
-
\`\`\`json
|
|
1916
|
-
{
|
|
1917
|
-
"validationRun": [
|
|
1918
|
-
{
|
|
1919
|
-
"command": "bun test tests/runtime-gates.test.ts",
|
|
1920
|
-
"status": "passed",
|
|
1921
|
-
"summary": "12 pass; covered approval immutability, active feature, and completion gates"
|
|
1922
|
-
},
|
|
1923
|
-
{
|
|
1924
|
-
"command": "bun run typecheck",
|
|
1925
|
-
"status": "passed",
|
|
1926
|
-
"summary": "TypeScript accepted runtime and adapter changes"
|
|
1927
|
-
}
|
|
1928
|
-
],
|
|
1929
|
-
"validationScope": "broad"
|
|
1930
|
-
}
|
|
1931
|
-
\`\`\`
|
|
1932
|
-
|
|
1933
|
-
## Blockers and resets
|
|
1934
|
-
|
|
1935
|
-
- If validation fails due to a code bug, fix it and rerun.
|
|
1936
|
-
- If validation reveals a wrong design or interface assumption, call \`flow_feature_reset\` and rerun from the corrected approach.
|
|
1937
|
-
- If validation needs external access, missing credentials, or ambiguous user input, record \`status: "needs_input"\` with an honest \`outcome\`.
|
|
1938
|
-
|
|
1939
|
-
Never trim failing output, relabel a failed command as passed, or use "not run" as completion evidence.
|
|
1940
|
-
`;
|
|
1941
|
-
|
|
1942
|
-
// skills/flow-run/SKILL.md
|
|
1943
|
-
var SKILL_default6 = '---\nname: flow-run\ndescription: "Use when an approved Flow plan has a feature to implement, validate, or complete in the v4 runtime, and the work is scoped to one active feature. For planning a goal first use flow-plan; for the full goal-to-completion loop or resuming a session use flow."\n---\n\n# Flow Run\n\nUse this skill for implementation after a Flow plan is approved. Work one feature at a time.\n\nIf `flow_run_start` is unavailable, stop and tell the user to check that `opencode-plugin-flow` is loaded in OpenCode.\n\n## Start\n\n- Call `flow_status`.\n- If `flow_status` returns a `session.resumePacket` or\n `session.budget.phaseBoundary`, stop the current autonomous loop and report\n the resume instructions. Only call `flow_run_start` with\n `phaseBoundaryAck: true` at the start of a fresh user invocation that is\n explicitly resuming the Flow session; do not acknowledge a boundary inside\n the same uninterrupted loop that created it.\n- Call `flow_run_start` with no `featureId` unless the user or plan requires a specific runnable feature.\n- Treat the returned feature as the sole scope until it is completed, blocked, or reset.\n- Helper rule: when a named helper skill is unavailable, record the gap and\n keep the corresponding claims conservative instead of simulating its checks.\n- Load `flow-deslop` for cleanup/refactor features.\n- Load `flow-ui-quality` for frontend, UX, responsive, accessibility, or visual work.\n\n## Implement\n\n- Read the feature `targets`, `summary`, `validation`, dependencies, and plan `requirements`/`decisions`.\n- Treat the feature\'s `reviewDepth` as the minimum feature-review depth that\n must be recorded in `flow_feature_complete`.\n- For broad, risky, or multi-target work, record an implementation pass\n decision before editing: `serial`, `candidate-exact-path`,\n `candidate-worktree`, `tournament`, or `skipped`. Use\n `../flow/references/parallel-orchestration.md` for the decision rules,\n manifest fields, and compact `orchestrationPasses` record.\n- Classify `candidateEligibility` (`eligible`, `not_eligible`, or `unknown`)\n and `candidateDecision` (`used`, `skipped`, or `serial_required`) separately;\n implementation decisions must use `eligible` or `not_eligible` and always set\n an explicit `decision`. The valid pairings and the candidate execution\n evidence rules are in `../flow/references/parallel-orchestration.md` under\n "Implementation pass decision" — follow that reference when composing the\n record.\n- Record structured `decisionFactors`: `shared_state`, `overlapping_files`,\n `small_slice`, `needs_manager_judgment`, `independent_surface`, and\n `validation_available`.\n- Keep edits scoped to the active feature. If new scope appears, stop and replan or defer it to another feature.\n- Preserve unrelated user changes in the worktree.\n- When a wrong assumption invalidates the feature, use `flow_feature_reset`; do not pile patches onto a bad path.\n- Do not stage, commit, push, amend, rebase, publish, or mutate releases as part\n of feature execution. If the user explicitly asks for commit preparation, load\n `flow-commit` only after `flow_feature_complete` has been recorded, unless the\n user explicitly asks for a WIP commit path. Keep Git boundaries separate from\n Flow state recording.\n\n## Validate\n\n- For complex validation, regression-sensitive changes, browser QA, route QA,\n failure-prone checks, unclear coverage, exploratory QA, or\n `validationRun` summarization, load `flow-test` (helper rule applies).\n- Read `references/validation-rubric.md` before completing.\n- Run the strongest practical checks for the changed behavior.\n- Record concrete command names, status, and observed results. "Tests pass" is not evidence.\n- Non-final features complete with `validationScope: "targeted"`.\n- The final feature must run a broad project-level gate and use `validationScope: "broad"`.\n\nFor broad validation research, risky changes, or unclear coverage, use\n`../flow/references/parallel-orchestration.md` to fan out named Flow workers.\nUse the mode-to-agent mapping in that reference instead of generic subagents.\nWrite its pass manifest before fan-out, paste the matching handoff template\nfrom `../flow/references/handoff-format.md` into every worker prompt, and\napply its verification tiers to the handoffs that come back.\nThey may report command output they actually ran or propose focused checks; the\nmanager decides what is strong enough to record.\n\nFor independent implementation attempts, use candidate workers only with\nexplicit user authorization plus isolated worktrees or exact non-overlapping\npath ownership. Treat their output as candidate patches. The manager inspects,\nmerges or rejects, validates, and records Flow state serially. Record whether a\ncandidate was `accepted`, `modified`, or `rejected`.\nWhen a candidate pass or serial/skipped implementation decision materially\nshaped the feature, include its compact record in\n`flow_feature_complete.orchestrationPasses`. Do not paste full worker handoffs\nor long logs into the runtime payload.\n\n## Review and complete\n\nBefore `flow_feature_complete`, obtain a `featureReview` payload. Load\n`flow-review`; for read-only subagent reviews, the manager receives the review\npacket and records both `featureReviewDepth` and `featureReview`.\n\nSend reviewers a compact review packet. Do not rely on the accumulated parent\nconversation. Include only:\n\n- active feature id, title, summary, `reviewDepth`, targets, validation, and dependencies\n- relevant plan requirements, decisions, and final review policy\n- changed files and a short diff summary\n- validation evidence with exact commands, status, and observed result\n- targeted paths or risk lenses the reviewer must inspect\n\nIf the review returns `status: "failed"`, do not fix inside the review pass.\nRecord the failed attempt by calling `flow_feature_complete` with the otherwise\nprepared completion payload, the failed `featureReview`, and the attempted\n`featureReviewDepth`; the runtime will reject completion and update the retry\nbudget. Default to stopping and reporting the blocker. When the user already\nauthorized autonomous implementation, make at most one repair and run one retry\nreview. If the retry fails or the runtime reports review retry budget\nexhausted, stop with the blocker.\n\nIf `flow_status` reports `setup.skills` or `flow-review` cannot be loaded, do\nnot record a Flow-gated `featureReview` or `finalReview`. You may perform an\nadvisory review using available context or the bundled review fallback provided\nby plugin config, then complete with `status: "needs_input"` if review evidence\nis required to proceed.\n\nFor the final feature, also obtain a `finalReview` payload whose `reviewDepth` equals the approved plan\'s `finalReviewPolicy`.\n\nComplete with:\n\n```json\n{\n "status": "ok",\n "featureId": "active-feature-id",\n "summary": "what changed",\n "artifactsChanged": [{ "path": "src/file.ts" }],\n "validationRun": [\n { "command": "bun test tests/foo.test.ts", "status": "passed", "summary": "3 pass, exercised foo behavior" }\n ],\n "validationScope": "targeted",\n "featureReviewDepth": "standard",\n "featureReview": { "status": "passed", "summary": "review summary", "blockingFindings": [] },\n "orchestrationPasses": [\n {\n "id": "active-feature-id-implementation-decision",\n "kind": "implementation-decision",\n "decision": "serial",\n "decisionReason": "Shared contract edits made worker ownership unsafe.",\n "candidateEligibility": "not_eligible",\n "candidateDecision": "serial_required",\n "decisionFactors": ["shared_state", "overlapping_files"],\n "writeScope": "manager-serial",\n "verificationStatus": "not-needed",\n "outcome": "accepted"\n }\n ]\n}\n```\n\nIf `flow_feature_complete` returns a `session.resumePacket` or\n`session.budget.phaseBoundary`, stop after reporting the compact handoff. If\ngenuinely blocked, call `flow_feature_complete` with `status: "needs_input"` and\nan `outcome` that explains the blocker and next step. Never fabricate validation\nor review evidence to force progress.\n';
|
|
1944
|
-
|
|
1945
|
-
// skills/flow-test/SKILL.md
|
|
1946
|
-
var SKILL_default7 = `---
|
|
1947
|
-
name: flow-test
|
|
1948
|
-
description: Choose, run, and summarize validation checks for Flow features. Use when selecting validation coverage, running tests or browser/e2e QA, classifying test failures, or preparing validationRun evidence for flow_feature_complete. Visual design judgment stays in flow-ui-quality and review verdicts stay in flow-review.
|
|
1949
|
-
---
|
|
1950
|
-
|
|
1951
|
-
# Flow Test
|
|
1952
|
-
|
|
1953
|
-
Use this skill to decide and gather validation evidence. It produces validation
|
|
1954
|
-
evidence only: the manager still owns \`flow_feature_complete\`, review payloads,
|
|
1955
|
-
plan approval, session closure, and every other Flow state change.
|
|
1956
|
-
|
|
1957
|
-
Do not mutate \`.flow/**\`, approve plans, complete features, close sessions, or
|
|
1958
|
-
substitute for \`flow-review\`. If Flow tools are unavailable, this skill can still
|
|
1959
|
-
produce an advisory validation plan or test summary, but it cannot record Flow
|
|
1960
|
-
state.
|
|
1961
|
-
|
|
1962
|
-
## Inputs
|
|
1963
|
-
|
|
1964
|
-
Start from the smallest concrete surface:
|
|
1965
|
-
|
|
1966
|
-
- The approved feature \`summary\`, \`targets\`, and \`validation\` entries when a
|
|
1967
|
-
Flow session exists.
|
|
1968
|
-
- The actual diff, changed files, package scripts, docs, and test conventions.
|
|
1969
|
-
- Recent command output from this session or from a trusted worker handoff.
|
|
1970
|
-
- Any user-stated acceptance criteria, browser target, fixture, or environment
|
|
1971
|
-
constraint.
|
|
1972
|
-
|
|
1973
|
-
Prefer repository scripts and local conventions over invented commands. If a
|
|
1974
|
-
command has not been run in this session or directly reported by a trusted
|
|
1975
|
-
worker with raw outcome, recommend it instead of claiming it passed.
|
|
1976
|
-
|
|
1977
|
-
## Select Coverage
|
|
1978
|
-
|
|
1979
|
-
Choose checks from changed-surface risk, not from habit:
|
|
1980
|
-
|
|
1981
|
-
- **Targeted behavior**: unit, integration, CLI, route, or component tests that
|
|
1982
|
-
exercise the changed behavior and would fail without the fix.
|
|
1983
|
-
- **Integration and persistence**: database, filesystem, API, adapter, lock, or
|
|
1984
|
-
serialization paths touched by the feature.
|
|
1985
|
-
- **Browser or e2e**: user-visible workflows, responsive states, accessibility
|
|
1986
|
-
basics, form flows, and screenshots when a local target and browser tooling
|
|
1987
|
-
are available.
|
|
1988
|
-
- **Package and build shape**: typecheck, lint, build, generated distribution,
|
|
1989
|
-
or schema checks when public contracts, bundling, or package exports changed.
|
|
1990
|
-
- **Docs and mechanical edits**: markdown rendering, link/path sanity, spelling
|
|
1991
|
-
of commands, or the narrowest project check when behavior is unchanged.
|
|
1992
|
-
- **Cleanup/refactor**: behavior-preservation tests plus the relevant broad
|
|
1993
|
-
check; formatting alone is not evidence of preserved behavior.
|
|
1994
|
-
- **Final feature**: the repository's broad gate, full relevant suite, build, or
|
|
1995
|
-
equivalent release gate before \`validationScope: "broad"\` is recorded.
|
|
1996
|
-
|
|
1997
|
-
If the planned coverage is weaker than the risk, say so explicitly and list the
|
|
1998
|
-
missing evidence.
|
|
1999
|
-
|
|
2000
|
-
## Run Discipline
|
|
2001
|
-
|
|
2002
|
-
For each check:
|
|
2003
|
-
|
|
2004
|
-
1. State the hypothesis: what behavior or contract the check is expected to
|
|
2005
|
-
prove.
|
|
2006
|
-
2. Run the command or manual workflow when the environment allows it.
|
|
2007
|
-
3. Record exact command, status, and observed result.
|
|
2008
|
-
4. If it fails, classify the failure before editing:
|
|
2009
|
-
- product failure
|
|
2010
|
-
- test failure
|
|
2011
|
-
- environment failure
|
|
2012
|
-
- pre-existing failure
|
|
2013
|
-
- flake
|
|
2014
|
-
- unrelated failure
|
|
2015
|
-
5. Before a fix attempt, write a short failure hypothesis that names the likely
|
|
2016
|
-
cause and the file or behavior to inspect.
|
|
2017
|
-
6. After a fix, rerun the failing check and one appropriate regression check.
|
|
2018
|
-
|
|
2019
|
-
Do not trim failure output so far that the manager cannot understand the
|
|
2020
|
-
failure. Do redact secrets and credentials.
|
|
2021
|
-
|
|
2022
|
-
## Browser and Exploratory QA
|
|
2023
|
-
|
|
2024
|
-
For meaningful UI or browser workflow changes, browser evidence is expected when
|
|
2025
|
-
a local target can run:
|
|
2026
|
-
|
|
2027
|
-
- Open the relevant route or story with the available browser tooling.
|
|
2028
|
-
- Exercise the main changed workflow, not only page load.
|
|
2029
|
-
- Check desktop and mobile breakpoints when responsive behavior is in scope.
|
|
2030
|
-
- Capture screenshots or describe the viewport, route, steps, and observed
|
|
2031
|
-
result.
|
|
2032
|
-
- Inspect visible error states, empty states, long labels, focus behavior, and
|
|
2033
|
-
console or network failures when the tooling exposes them.
|
|
2034
|
-
|
|
2035
|
-
Browser claims are evidence requirements, not guaranteed coverage. If browser
|
|
2036
|
-
tooling, credentials, seed data, or a local server is unavailable, record the
|
|
2037
|
-
gap and provide the next-best evidence such as component tests, build output, or
|
|
2038
|
-
static inspection.
|
|
2039
|
-
|
|
2040
|
-
Exploratory QA should be scenario-based. Name the user path, the state varied,
|
|
2041
|
-
and the expected outcome. Do not replace automated evidence with exploratory QA
|
|
2042
|
-
when a practical automated check exists.
|
|
2043
|
-
|
|
2044
|
-
## Output
|
|
2045
|
-
|
|
2046
|
-
Return a concise validation summary and a \`validationRun\` array that the manager
|
|
2047
|
-
can record through \`flow_feature_complete\` if it accepts the evidence:
|
|
2048
|
-
|
|
2049
|
-
\`\`\`json
|
|
2050
|
-
{
|
|
2051
|
-
"validationRun": [
|
|
2052
|
-
{
|
|
2053
|
-
"command": "bun test tests/foo.test.ts",
|
|
2054
|
-
"status": "passed",
|
|
2055
|
-
"summary": "3 pass; covered foo creation, duplicate rejection, and reset behavior"
|
|
2056
|
-
}
|
|
2057
|
-
],
|
|
2058
|
-
"testSummary": "Targeted behavior and package shape passed. Browser evidence was not applicable.",
|
|
2059
|
-
"gaps": []
|
|
2060
|
-
}
|
|
2061
|
-
\`\`\`
|
|
2062
|
-
|
|
2063
|
-
Only passing checks belong in \`validationRun\` for completion. Failed, skipped,
|
|
2064
|
-
or unavailable checks belong in \`testSummary\`, \`gaps\`, or a blocker outcome.
|
|
2065
|
-
Each summary must state what behavior, file set, route, command, or state was
|
|
2066
|
-
covered. Static inspection alone is a gap for behavioral changes.
|
|
2067
|
-
|
|
2068
|
-
Never relabel a failed command as passed, invent output, or use "not run" as
|
|
2069
|
-
completion evidence.
|
|
2070
|
-
`;
|
|
2071
|
-
|
|
2072
|
-
// skills/flow-ui-quality/references/ui-rubric.md
|
|
2073
|
-
var ui_rubric_default = `# UI quality rubric
|
|
2074
|
-
|
|
2075
|
-
Use this rubric for frontend planning, implementation, and review.
|
|
2076
|
-
|
|
2077
|
-
## Product fit
|
|
2078
|
-
|
|
2079
|
-
- The screen solves the user's actual task, not a generic demo of components.
|
|
2080
|
-
- The first viewport shows the product, data, object, or workflow the user came for.
|
|
2081
|
-
- The information density matches use: operational tools favor scannable, compact structure; expressive pages need stronger visual identity and media.
|
|
2082
|
-
- Navigation and primary actions are obvious without explanatory helper text.
|
|
2083
|
-
|
|
2084
|
-
## Visual design
|
|
2085
|
-
|
|
2086
|
-
- **Typography**: hierarchy is clear; font choices fit the product; body text remains readable; compact surfaces do not use hero-scale type.
|
|
2087
|
-
- **Color**: palette has a coherent role system; contrast is sufficient; accent colors guide attention; avoid one-note palettes and generic purple-blue gradients unless the brand requires them.
|
|
2088
|
-
- **Composition**: alignment, spacing, and grouping make comparison easy; repeated items are consistent; page sections are not nested decorative cards.
|
|
2089
|
-
- **Controls**: use familiar controls for the job: icons for common tools, toggles for binary settings, segmented controls for modes, sliders/inputs for numbers, menus for option sets.
|
|
2090
|
-
- **Motion**: animation clarifies state or creates a focused moment; it does not hide latency, distract from work, or ignore reduced-motion needs.
|
|
2091
|
-
- **Imagery/media**: when the subject matters, show the actual product/place/object/state rather than atmospheric filler.
|
|
2092
|
-
|
|
2093
|
-
## Interaction and states
|
|
2094
|
-
|
|
2095
|
-
- Loading, empty, error, disabled, hover, focus, selected, and validation states exist for the changed workflow.
|
|
2096
|
-
- Long strings, missing data, large numbers, and small screens do not break layout.
|
|
2097
|
-
- Destructive actions have appropriate confirmation or undo patterns.
|
|
2098
|
-
- Form errors are close to the field and clear enough to fix.
|
|
2099
|
-
- Async state cannot double-submit, lose edits, or leave stale UI behind.
|
|
2100
|
-
|
|
2101
|
-
## Accessibility baseline
|
|
2102
|
-
|
|
2103
|
-
- Interactive elements are semantic or have correct roles and labels.
|
|
2104
|
-
- Keyboard users can reach and operate controls in a logical order.
|
|
2105
|
-
- Focus indicators are visible.
|
|
2106
|
-
- Text and essential UI meet contrast expectations.
|
|
2107
|
-
- Status, error, and progress messages are not conveyed by color alone.
|
|
2108
|
-
- Motion respects reduced-motion preferences when substantial.
|
|
2109
|
-
|
|
2110
|
-
## Review finding shape
|
|
2111
|
-
|
|
2112
|
-
\`\`\`text
|
|
2113
|
-
class; severity; location or screenshot area; evidence inspected; user impact; fix shape; visual/validation evidence needed
|
|
2114
|
-
\`\`\`
|
|
2115
|
-
|
|
2116
|
-
Blocking UI findings are issues that prevent task completion, hide required information, break accessibility basics, create incoherent layout at supported sizes, or make the visual success claim unverifiable.
|
|
2117
|
-
`;
|
|
2118
|
-
|
|
2119
|
-
// skills/flow-ui-quality/references/visual-verification.md
|
|
2120
|
-
var visual_verification_default = `# Visual verification workflow
|
|
2121
|
-
|
|
2122
|
-
Use this workflow when UI changes can be run locally. Flow execution may create visual evidence; Flow review usually assesses recorded evidence because the reviewer is read-only.
|
|
2123
|
-
|
|
2124
|
-
## Execution lane
|
|
2125
|
-
|
|
2126
|
-
- Identify the target route, state, viewport sizes, and any required seed data.
|
|
2127
|
-
- Start the repo's normal dev server or storybook command from the recorded repo profile.
|
|
2128
|
-
- Prefer existing browser or Playwright tooling when available. Do not add heavy visual tooling just to inspect a small change.
|
|
2129
|
-
- Capture at least one desktop viewport and one mobile viewport for user-facing layout changes.
|
|
2130
|
-
- Exercise the primary interaction changed by the feature.
|
|
2131
|
-
- Inspect loading, empty, and error states when they are part of the changed workflow or easy to reach.
|
|
2132
|
-
- Check browser console output when the tooling exposes it.
|
|
2133
|
-
- For canvas/3D/media-heavy UI, verify rendered pixels are nonblank and the subject is framed.
|
|
2134
|
-
|
|
2135
|
-
## Review lane
|
|
2136
|
-
|
|
2137
|
-
- Inspect the screenshots, browser notes, console output, or visual artifacts recorded by execution.
|
|
2138
|
-
- Compare recorded evidence against the plan's design intent, supported viewports, state coverage, and the UI rubric.
|
|
2139
|
-
- If the current reviewer has browser/shell tools and permissions, it may perform additional read-only visual checks.
|
|
2140
|
-
- If the reviewer is read-only without browser or shell access, do not try to recreate evidence. Treat missing or insufficient visual evidence as a finding or coverage gap.
|
|
2141
|
-
|
|
2142
|
-
## What to look for
|
|
2143
|
-
|
|
2144
|
-
- Text overlap, clipped labels, unintended wrapping, and controls resizing on hover.
|
|
2145
|
-
- Incoherent spacing, nested cards, generic placeholder visuals, and decorative elements that compete with the task.
|
|
2146
|
-
- Missing focus states, low contrast, unreachable controls, and color-only status.
|
|
2147
|
-
- Broken responsive behavior: horizontal scroll, collapsed controls, hidden primary actions, or unreadable tables.
|
|
2148
|
-
- State bugs: stale loading indicators, duplicate submissions, lost input, or errors that cannot be recovered.
|
|
2149
|
-
|
|
2150
|
-
## If visual verification is unavailable
|
|
2151
|
-
|
|
2152
|
-
Record the reason and use the strongest available substitute:
|
|
2153
|
-
|
|
2154
|
-
- build/typecheck/lint for changed frontend code.
|
|
2155
|
-
- component or interaction tests.
|
|
2156
|
-
- Storybook/static render output.
|
|
2157
|
-
- code inspection against existing component patterns.
|
|
2158
|
-
|
|
2159
|
-
Do not claim visual polish was verified if no visual artifact was inspected.
|
|
2160
|
-
`;
|
|
2161
|
-
|
|
2162
|
-
// skills/flow-ui-quality/SKILL.md
|
|
2163
|
-
var SKILL_default8 = `---
|
|
2164
|
-
name: flow-ui-quality
|
|
2165
|
-
description: Review and improve frontend UI quality for Flow work. Use for UX/UI design, frontend polish, visual quality review, responsive and accessible interfaces, interaction states, screenshot assessment, and avoiding generic AI-generated UI. Browser-run mechanics and validationRun summaries stay in flow-test.
|
|
2166
|
-
---
|
|
2167
|
-
|
|
2168
|
-
# Flow UI quality
|
|
2169
|
-
|
|
2170
|
-
Use this skill when Flow work changes what a user sees or how they interact with an interface. The goal is production UI quality: useful, coherent, accessible, responsive, and visually intentional.
|
|
2171
|
-
|
|
2172
|
-
This is a helper skill: it contributes UI judgment and visual evidence only. The manager owns every state-changing \`flow_*\` call.
|
|
2173
|
-
|
|
2174
|
-
## Establish the interface intent
|
|
2175
|
-
|
|
2176
|
-
- Identify the user, job-to-be-done, primary workflow, density needs, device constraints, and brand/product tone before choosing visuals.
|
|
2177
|
-
- Choose a clear design direction that fits the product context. Distinctive does not mean decorative; utilitarian tools can be excellent through restraint, hierarchy, and speed.
|
|
2178
|
-
- Load \`references/ui-rubric.md\` for design and UX review criteria.
|
|
2179
|
-
- Load \`references/visual-verification.md\` before completing meaningful UI changes to capture visual evidence. During review, use it to assess recorded evidence; only run browser checks yourself if the current agent and tools permit it.
|
|
2180
|
-
- Record design constraints and verification expectations in Flow plan fields: \`requirements\`, \`decisions\`, feature \`targets\`, and feature \`validation\`. Do not add new Flow payload fields.
|
|
2181
|
-
|
|
2182
|
-
## Build with visual intent
|
|
2183
|
-
|
|
2184
|
-
- Use existing design systems, component libraries, tokens, icons, and layout conventions before inventing new primitives.
|
|
2185
|
-
- Make typography, spacing, color, motion, and hierarchy deliberate. Avoid default-looking AI output: centered everything, purple gradients, generic cards, uniform oversized radii, stock SaaS layouts, and unexamined Inter/system-font sameness.
|
|
2186
|
-
- Match composition to domain: operational apps need scanability, alignment, predictable controls, efficient density, and clear states; marketing or editorial surfaces can carry more expressive imagery and motion.
|
|
2187
|
-
- Include states a real user will hit: loading, empty, error, disabled, hover, focus, selected, validation, and long content.
|
|
2188
|
-
- Protect accessibility: semantic controls, labels, focus order, keyboard reachability, contrast, reduced-motion behavior, and non-color-only status.
|
|
2189
|
-
|
|
2190
|
-
## Verify visually
|
|
2191
|
-
|
|
2192
|
-
- For meaningful UI changes, run the app and capture screenshots when a local browser target is available.
|
|
2193
|
-
- For browser-driven QA, route selection, failure classification, and
|
|
2194
|
-
\`validationRun\` summaries, load \`flow-test\`. Keep visual judgment, design
|
|
2195
|
-
quality, and screenshot assessment in \`flow-ui-quality\`.
|
|
2196
|
-
- Check desktop and mobile breakpoints, not only the viewport you developed in.
|
|
2197
|
-
- Verify text does not overlap, truncate unintentionally, or escape controls; long labels and empty/error states must fit.
|
|
2198
|
-
- Compare against provided screenshots, design references, or the stated product intent. List meaningful differences and fix the ones that violate the goal.
|
|
2199
|
-
- If browser verification cannot run, record the gap and the next-best evidence such as component tests, Storybook snapshots, build output, or static inspection.
|
|
2200
|
-
|
|
2201
|
-
## Review UI work
|
|
2202
|
-
|
|
2203
|
-
Approve only when the interface is both useful and inspectable:
|
|
2204
|
-
|
|
2205
|
-
- The main workflow is visible and efficient.
|
|
2206
|
-
- Visual hierarchy makes the next action obvious.
|
|
2207
|
-
- Responsive behavior is deliberate.
|
|
2208
|
-
- Accessibility basics are covered.
|
|
2209
|
-
- State coverage is present or the gaps are explicit.
|
|
2210
|
-
- Screenshot/browser evidence supports the claim whenever feasible.
|
|
2211
|
-
|
|
2212
|
-
Never approve a UI change based only on code shape. If users will judge it visually, Flow evidence should include visual inspection.
|
|
2213
|
-
`;
|
|
2214
|
-
|
|
2215
|
-
// src/distribution/flow-skill-definitions.ts
|
|
2216
|
-
var FLOW_SKILL_DEFINITIONS = [
|
|
2217
|
-
{
|
|
2218
|
-
name: "flow",
|
|
2219
|
-
files: [
|
|
2220
|
-
{ relativePath: "SKILL.md", content: SKILL_default },
|
|
2221
|
-
{
|
|
2222
|
-
relativePath: "references/recovery-playbook.md",
|
|
2223
|
-
content: recovery_playbook_default
|
|
2224
|
-
},
|
|
2225
|
-
{
|
|
2226
|
-
relativePath: "references/parallel-orchestration.md",
|
|
2227
|
-
content: parallel_orchestration_default
|
|
2228
|
-
},
|
|
2229
|
-
{
|
|
2230
|
-
relativePath: "references/parallel-pass-example.md",
|
|
2231
|
-
content: parallel_pass_example_default
|
|
2232
|
-
},
|
|
2233
|
-
{
|
|
2234
|
-
relativePath: "references/handoff-format.md",
|
|
2235
|
-
content: handoff_format_default
|
|
2236
|
-
}
|
|
2237
|
-
]
|
|
2238
|
-
},
|
|
2239
|
-
{
|
|
2240
|
-
name: "flow-plan",
|
|
2241
|
-
files: [
|
|
2242
|
-
{ relativePath: "SKILL.md", content: SKILL_default4 },
|
|
2243
|
-
{
|
|
2244
|
-
relativePath: "references/planning-examples.md",
|
|
2245
|
-
content: planning_examples_default
|
|
2246
|
-
},
|
|
2247
|
-
{
|
|
2248
|
-
relativePath: "references/plan-quality-checklist.md",
|
|
2249
|
-
content: plan_quality_checklist_default
|
|
2250
|
-
},
|
|
2251
|
-
{
|
|
2252
|
-
relativePath: "references/parallel-discovery.md",
|
|
2253
|
-
content: parallel_discovery_default
|
|
2254
|
-
}
|
|
2255
|
-
]
|
|
2256
|
-
},
|
|
2257
|
-
{
|
|
2258
|
-
name: "flow-run",
|
|
2259
|
-
files: [
|
|
2260
|
-
{ relativePath: "SKILL.md", content: SKILL_default6 },
|
|
2261
|
-
{
|
|
2262
|
-
relativePath: "references/validation-rubric.md",
|
|
2263
|
-
content: validation_rubric_default
|
|
2264
|
-
},
|
|
2265
|
-
{
|
|
2266
|
-
relativePath: "references/audit-rubric.md",
|
|
2267
|
-
content: audit_rubric_default
|
|
2268
|
-
}
|
|
2269
|
-
]
|
|
2270
|
-
},
|
|
2271
|
-
{
|
|
2272
|
-
name: "flow-test",
|
|
2273
|
-
files: [{ relativePath: "SKILL.md", content: SKILL_default7 }]
|
|
2274
|
-
},
|
|
2275
|
-
{
|
|
2276
|
-
name: "flow-review",
|
|
2277
|
-
files: [
|
|
2278
|
-
{ relativePath: "SKILL.md", content: SKILL_default5 },
|
|
2279
|
-
{
|
|
2280
|
-
relativePath: "references/review-rubric.md",
|
|
2281
|
-
content: review_rubric_default
|
|
2282
|
-
}
|
|
2283
|
-
]
|
|
2284
|
-
},
|
|
2285
|
-
{
|
|
2286
|
-
name: "flow-deslop",
|
|
2287
|
-
files: [
|
|
2288
|
-
{ relativePath: "SKILL.md", content: SKILL_default3 },
|
|
2289
|
-
{
|
|
2290
|
-
relativePath: "references/smell-rubric.md",
|
|
2291
|
-
content: smell_rubric_default
|
|
2292
|
-
},
|
|
2293
|
-
{
|
|
2294
|
-
relativePath: "references/refactor-workflow.md",
|
|
2295
|
-
content: refactor_workflow_default
|
|
2296
|
-
}
|
|
2297
|
-
]
|
|
2298
|
-
},
|
|
2299
|
-
{
|
|
2300
|
-
name: "flow-ui-quality",
|
|
2301
|
-
files: [
|
|
2302
|
-
{ relativePath: "SKILL.md", content: SKILL_default8 },
|
|
2303
|
-
{
|
|
2304
|
-
relativePath: "references/ui-rubric.md",
|
|
2305
|
-
content: ui_rubric_default
|
|
2306
|
-
},
|
|
2307
|
-
{
|
|
2308
|
-
relativePath: "references/visual-verification.md",
|
|
2309
|
-
content: visual_verification_default
|
|
2310
|
-
}
|
|
2311
|
-
]
|
|
2312
|
-
},
|
|
2313
|
-
{
|
|
2314
|
-
name: "flow-commit",
|
|
2315
|
-
files: [{ relativePath: "SKILL.md", content: SKILL_default2 }]
|
|
2316
|
-
}
|
|
5
|
+
import { constants } from "node:fs";
|
|
6
|
+
import {
|
|
7
|
+
lstat,
|
|
8
|
+
mkdir,
|
|
9
|
+
open,
|
|
10
|
+
readdir,
|
|
11
|
+
rename
|
|
12
|
+
} from "node:fs/promises";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
import { isAbsolute, join, normalize, sep } from "node:path";
|
|
15
|
+
|
|
16
|
+
// src/guidance/ids.ts
|
|
17
|
+
var FLOW_GUIDANCE_TOPICS = [
|
|
18
|
+
"flow",
|
|
19
|
+
"flow-plan",
|
|
20
|
+
"flow-run",
|
|
21
|
+
"flow-test",
|
|
22
|
+
"flow-review",
|
|
23
|
+
"flow-deslop",
|
|
24
|
+
"flow-ui-quality",
|
|
25
|
+
"flow-commit"
|
|
2317
26
|
];
|
|
2318
27
|
|
|
2319
|
-
// src/distribution/
|
|
2320
|
-
var
|
|
2321
|
-
var
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
const namedHash = backupHashFromName(relativePath);
|
|
2327
|
-
if (!namedHash)
|
|
2328
|
-
return false;
|
|
2329
|
-
const content = await optionalRead(resolveSkillFile(folder, relativePath));
|
|
2330
|
-
if (content === null)
|
|
2331
|
-
return false;
|
|
2332
|
-
return sha256(content).slice(0, 12) === namedHash;
|
|
2333
|
-
}
|
|
2334
|
-
function normalizeNewlines(value) {
|
|
2335
|
-
return value.replace(/\r\n/g, `
|
|
2336
|
-
`);
|
|
2337
|
-
}
|
|
2338
|
-
var CHANGED_SYNC_ACTIONS = [
|
|
2339
|
-
"installed",
|
|
2340
|
-
"updated",
|
|
2341
|
-
"updated_with_backup"
|
|
2342
|
-
];
|
|
2343
|
-
function isChangedSyncAction(action) {
|
|
2344
|
-
return CHANGED_SYNC_ACTIONS.includes(action);
|
|
28
|
+
// src/distribution/legacy-cleanup.ts
|
|
29
|
+
var LEGACY_MARKER = ".flow-skill-version";
|
|
30
|
+
var NO_FOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
31
|
+
var SUPPORTED_LEGACY_MAJOR = "4";
|
|
32
|
+
var SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
33
|
+
function configuredHome() {
|
|
34
|
+
return process.env.HOME?.trim() || process.env.USERPROFILE?.trim() || homedir();
|
|
2345
35
|
}
|
|
2346
|
-
function
|
|
2347
|
-
const configured = process.env.HOME?.trim() || process.env.USERPROFILE?.trim();
|
|
2348
|
-
return configured || homedir();
|
|
2349
|
-
}
|
|
2350
|
-
function resolveFlowSkillsRoot(home = homeDir()) {
|
|
36
|
+
function resolveLegacySkillsRoot(home = configuredHome()) {
|
|
2351
37
|
return join(home, ".config", "opencode", "skills");
|
|
2352
38
|
}
|
|
2353
|
-
function
|
|
2354
|
-
return
|
|
39
|
+
function resolveLegacyArchiveRoot(home = configuredHome()) {
|
|
40
|
+
return join(home, ".config", "opencode", "flow-legacy-skills");
|
|
2355
41
|
}
|
|
2356
|
-
function
|
|
2357
|
-
return
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
42
|
+
function sha256(content) {
|
|
43
|
+
return createHash("sha256").update(content).digest("hex");
|
|
44
|
+
}
|
|
45
|
+
function safeLegacyPath(folder, relativePath) {
|
|
46
|
+
if (!relativePath || isAbsolute(relativePath) || relativePath.includes("\\") || relativePath.split("/").some((part) => !part || part === "." || part === "..")) {
|
|
47
|
+
throw new Error(`unsafe marker path '${relativePath}'`);
|
|
48
|
+
}
|
|
49
|
+
const resolved = normalize(join(folder, ...relativePath.split("/")));
|
|
50
|
+
if (!resolved.startsWith(`${folder}${sep}`)) {
|
|
51
|
+
throw new Error(`unsafe marker path '${relativePath}'`);
|
|
52
|
+
}
|
|
53
|
+
return resolved;
|
|
2363
54
|
}
|
|
2364
|
-
async function
|
|
55
|
+
async function optionalStat(path) {
|
|
2365
56
|
try {
|
|
2366
|
-
return await
|
|
57
|
+
return await lstat(path, { bigint: false });
|
|
2367
58
|
} catch (error) {
|
|
2368
|
-
|
|
2369
|
-
if (code === "ENOENT" || code === "ENOTDIR")
|
|
59
|
+
if (error.code === "ENOENT")
|
|
2370
60
|
return null;
|
|
2371
61
|
throw error;
|
|
2372
62
|
}
|
|
2373
63
|
}
|
|
2374
|
-
function
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
64
|
+
async function readRegularFileWithoutFollowing(path) {
|
|
65
|
+
let handle;
|
|
66
|
+
try {
|
|
67
|
+
const pathMetadata = await lstat(path);
|
|
68
|
+
if (pathMetadata.isSymbolicLink()) {
|
|
69
|
+
throw new Error(`symbolic link refused: ${path}`);
|
|
70
|
+
}
|
|
71
|
+
if (!pathMetadata.isFile())
|
|
72
|
+
throw new Error(`not a regular file: ${path}`);
|
|
73
|
+
handle = await open(path, constants.O_RDONLY | NO_FOLLOW);
|
|
74
|
+
const metadata = await handle.stat();
|
|
75
|
+
if (!metadata.isFile())
|
|
76
|
+
throw new Error(`not a regular file: ${path}`);
|
|
77
|
+
if (metadata.dev !== pathMetadata.dev || metadata.ino !== pathMetadata.ino) {
|
|
78
|
+
throw new Error(`file changed while cleanup was running: ${path}`);
|
|
2385
79
|
}
|
|
80
|
+
return await handle.readFile({ encoding: "utf8" });
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error.code === "ELOOP") {
|
|
83
|
+
throw new Error(`symbolic link refused: ${path}`);
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
} finally {
|
|
87
|
+
await handle?.close();
|
|
2386
88
|
}
|
|
2387
|
-
return files;
|
|
2388
89
|
}
|
|
2389
|
-
function
|
|
2390
|
-
|
|
2391
|
-
|
|
90
|
+
function parseMarker(content) {
|
|
91
|
+
let version;
|
|
92
|
+
const files = new Map;
|
|
2392
93
|
for (const line of content.split(/\r?\n/)) {
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
if (resolved !== folder && resolved.startsWith(`${folder}${sep}`)) {
|
|
2402
|
-
return resolved;
|
|
2403
|
-
}
|
|
2404
|
-
throw new Error(`Unsafe skill file path '${relativePath}'.`);
|
|
2405
|
-
}
|
|
2406
|
-
async function writeBackup(path, content) {
|
|
2407
|
-
const basePath = `${path}.backup.${sha256(content).slice(0, 12)}`;
|
|
2408
|
-
for (let index = 0;; index += 1) {
|
|
2409
|
-
const backupPath = index === 0 ? basePath : `${basePath}.${index}`;
|
|
2410
|
-
try {
|
|
2411
|
-
await writeFile(backupPath, content, { encoding: "utf8", flag: "wx" });
|
|
2412
|
-
return backupPath;
|
|
2413
|
-
} catch (error) {
|
|
2414
|
-
if (error.code === "EEXIST")
|
|
2415
|
-
continue;
|
|
2416
|
-
throw error;
|
|
94
|
+
if (!line)
|
|
95
|
+
continue;
|
|
96
|
+
const versionMatch = /^version=(.+)$/.exec(line);
|
|
97
|
+
if (versionMatch?.[1]) {
|
|
98
|
+
if (version)
|
|
99
|
+
throw new Error("marker contains duplicate versions");
|
|
100
|
+
version = versionMatch[1];
|
|
101
|
+
continue;
|
|
2417
102
|
}
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
const markerPath = join(folder, MARKER_FILENAME);
|
|
2423
|
-
const markerContent = await optionalRead(markerPath);
|
|
2424
|
-
const existingMarkerHashes = parseMarkerFiles(markerContent);
|
|
2425
|
-
if (markerContent === null) {
|
|
2426
|
-
for (const file of definition.files) {
|
|
2427
|
-
const existing = await optionalRead(resolveSkillFile(folder, file.relativePath));
|
|
2428
|
-
if (existing !== null) {
|
|
2429
|
-
return { name: definition.name, action: "skipped_foreign" };
|
|
103
|
+
const fileMatch = /^file=(.+) sha256=([a-f0-9]{64})$/.exec(line) ?? /^file=(.+)=sha256:([a-f0-9]{64})$/.exec(line);
|
|
104
|
+
if (fileMatch?.[1] && fileMatch[2]) {
|
|
105
|
+
if (files.has(fileMatch[1])) {
|
|
106
|
+
throw new Error(`marker contains duplicate file '${fileMatch[1]}'`);
|
|
2430
107
|
}
|
|
2431
|
-
|
|
2432
|
-
}
|
|
2433
|
-
let changed = false;
|
|
2434
|
-
const backupPaths = [];
|
|
2435
|
-
const currentRelativePaths = new Set(definition.files.map((file) => file.relativePath));
|
|
2436
|
-
for (const file of definition.files) {
|
|
2437
|
-
const path = resolveSkillFile(folder, file.relativePath);
|
|
2438
|
-
const existing = await optionalRead(path);
|
|
2439
|
-
if (existing === file.content)
|
|
108
|
+
files.set(fileMatch[1], fileMatch[2]);
|
|
2440
109
|
continue;
|
|
2441
|
-
changed = true;
|
|
2442
|
-
const recordedHash = existingMarkerHashes.get(file.relativePath);
|
|
2443
|
-
const userEdited = existing !== null && (recordedHash ? sha256(existing) !== recordedHash : markerContent !== null);
|
|
2444
|
-
if (userEdited) {
|
|
2445
|
-
backupPaths.push(await writeBackup(path, existing));
|
|
2446
110
|
}
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
continue;
|
|
2451
|
-
const path = resolveSkillFile(folder, relativePath);
|
|
2452
|
-
const existing = await optionalRead(path);
|
|
2453
|
-
if (existing === null)
|
|
111
|
+
const topLevelHash = /^hash=sha256:([a-f0-9]{64})$/.exec(line);
|
|
112
|
+
if (topLevelHash?.[1] && !files.has("SKILL.md")) {
|
|
113
|
+
files.set("SKILL.md", topLevelHash[1]);
|
|
2454
114
|
continue;
|
|
2455
|
-
changed = true;
|
|
2456
|
-
if (sha256(existing) !== recordedHash) {
|
|
2457
|
-
backupPaths.push(await writeBackup(path, existing));
|
|
2458
115
|
}
|
|
2459
|
-
|
|
2460
|
-
}
|
|
2461
|
-
if (!
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
const
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
116
|
+
throw new Error(`marker contains an invalid line: '${line}'`);
|
|
117
|
+
}
|
|
118
|
+
if (!version)
|
|
119
|
+
throw new Error("marker has no version");
|
|
120
|
+
if (!files.has("SKILL.md"))
|
|
121
|
+
throw new Error("marker does not own SKILL.md");
|
|
122
|
+
return { version, files };
|
|
123
|
+
}
|
|
124
|
+
function assertSupportedLegacyVersion(version) {
|
|
125
|
+
const match = SEMVER_PATTERN.exec(version);
|
|
126
|
+
if (!match) {
|
|
127
|
+
throw new Error(`marker version '${version}' is not a valid semantic version`);
|
|
128
|
+
}
|
|
129
|
+
if (match[1] !== SUPPORTED_LEGACY_MAJOR) {
|
|
130
|
+
throw new Error(`marker version '${version}' is outside the supported legacy range >=4.0.0 <5.0.0`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function expectedDirectoryEntries(marker) {
|
|
134
|
+
const entries = new Map([
|
|
135
|
+
["", new Set([LEGACY_MARKER])]
|
|
136
|
+
]);
|
|
137
|
+
for (const relativePath of marker.files.keys()) {
|
|
138
|
+
const parts = relativePath.split("/");
|
|
139
|
+
let parent = "";
|
|
140
|
+
for (let index = 0;index < parts.length; index += 1) {
|
|
141
|
+
const part = parts[index];
|
|
142
|
+
if (!part)
|
|
143
|
+
throw new Error(`unsafe marker path '${relativePath}'`);
|
|
144
|
+
const children = entries.get(parent) ?? new Set;
|
|
145
|
+
children.add(part);
|
|
146
|
+
entries.set(parent, children);
|
|
147
|
+
if (index < parts.length - 1) {
|
|
148
|
+
parent = parent ? `${parent}/${part}` : part;
|
|
149
|
+
if (!entries.has(parent))
|
|
150
|
+
entries.set(parent, new Set);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
2473
153
|
}
|
|
2474
|
-
|
|
2475
|
-
return {
|
|
2476
|
-
name: definition.name,
|
|
2477
|
-
action: backupPaths.length > 0 ? "updated_with_backup" : managedSkillExists ? "updated" : "installed",
|
|
2478
|
-
...backupPaths.length > 0 ? { backupPaths } : {}
|
|
2479
|
-
};
|
|
2480
|
-
}
|
|
2481
|
-
function expectedSkillNames() {
|
|
2482
|
-
return FLOW_SKILL_DEFINITIONS.map((definition) => definition.name);
|
|
2483
|
-
}
|
|
2484
|
-
function formatFlowDoctorCommand(version) {
|
|
2485
|
-
const pin = version === "0.0.0" ? "latest" : version;
|
|
2486
|
-
return `npx -y opencode-plugin-flow@${pin} doctor`;
|
|
154
|
+
return entries;
|
|
2487
155
|
}
|
|
2488
|
-
function
|
|
2489
|
-
|
|
2490
|
-
|
|
156
|
+
async function inspectLegacyFolder(name, folder) {
|
|
157
|
+
const metadata = await optionalStat(folder);
|
|
158
|
+
if (!metadata)
|
|
159
|
+
return { name, path: folder, status: "absent" };
|
|
160
|
+
if (!metadata.isDirectory()) {
|
|
161
|
+
return {
|
|
162
|
+
name,
|
|
163
|
+
path: folder,
|
|
164
|
+
status: "refused",
|
|
165
|
+
reason: "path is not a real directory"
|
|
166
|
+
};
|
|
167
|
+
}
|
|
2491
168
|
try {
|
|
2492
|
-
const
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
const skills = await Promise.all(FLOW_SKILL_DEFINITIONS.map(async (definition) => {
|
|
2511
|
-
const folder = join(root, definition.name);
|
|
2512
|
-
const markerContent = await optionalRead(join(folder, MARKER_FILENAME));
|
|
2513
|
-
const markerVersion = parseMarkerVersion(markerContent);
|
|
2514
|
-
const markerHashes = parseMarkerFiles(markerContent);
|
|
2515
|
-
const existingSkill = await optionalRead(join(folder, "SKILL.md"));
|
|
2516
|
-
const backupFiles = markerContent === null ? [] : await listFlowBackupFiles(folder);
|
|
2517
|
-
if (existingSkill === null) {
|
|
2518
|
-
return {
|
|
2519
|
-
name: definition.name,
|
|
2520
|
-
path: folder,
|
|
2521
|
-
status: "missing",
|
|
2522
|
-
markerVersion,
|
|
2523
|
-
missingFiles: definition.files.map((file) => file.relativePath),
|
|
2524
|
-
editedFiles: [],
|
|
2525
|
-
outdatedFiles: [],
|
|
2526
|
-
backupFiles
|
|
2527
|
-
};
|
|
2528
|
-
}
|
|
2529
|
-
if (markerContent === null) {
|
|
2530
|
-
return {
|
|
2531
|
-
name: definition.name,
|
|
2532
|
-
path: folder,
|
|
2533
|
-
status: "foreign",
|
|
2534
|
-
markerVersion,
|
|
2535
|
-
missingFiles: [],
|
|
2536
|
-
editedFiles: [],
|
|
2537
|
-
outdatedFiles: [],
|
|
2538
|
-
backupFiles
|
|
2539
|
-
};
|
|
2540
|
-
}
|
|
2541
|
-
const missingFiles = [];
|
|
2542
|
-
const editedFiles = [];
|
|
2543
|
-
const outdatedFiles = [];
|
|
2544
|
-
for (const file of definition.files) {
|
|
2545
|
-
const existing = await optionalRead(resolveSkillFile(folder, file.relativePath));
|
|
2546
|
-
if (existing === null) {
|
|
2547
|
-
missingFiles.push(file.relativePath);
|
|
2548
|
-
continue;
|
|
169
|
+
const markerPath = join(folder, LEGACY_MARKER);
|
|
170
|
+
const marker = parseMarker(await readRegularFileWithoutFollowing(markerPath));
|
|
171
|
+
assertSupportedLegacyVersion(marker.version);
|
|
172
|
+
const directories = expectedDirectoryEntries(marker);
|
|
173
|
+
for (const [relativeDirectory, expectedEntries] of directories) {
|
|
174
|
+
const directory = relativeDirectory ? safeLegacyPath(folder, relativeDirectory) : folder;
|
|
175
|
+
const directoryMetadata = await optionalStat(directory);
|
|
176
|
+
if (!directoryMetadata?.isDirectory()) {
|
|
177
|
+
throw new Error(`expected real directory: ${relativeDirectory || "."}`);
|
|
178
|
+
}
|
|
179
|
+
const actualEntries = await readdir(directory);
|
|
180
|
+
const unexpected = actualEntries.filter((entry) => !expectedEntries.has(entry));
|
|
181
|
+
const missing = [...expectedEntries].filter((entry) => !actualEntries.includes(entry));
|
|
182
|
+
if (unexpected.length > 0 || missing.length > 0) {
|
|
183
|
+
throw new Error([
|
|
184
|
+
unexpected.length > 0 ? `unexpected entries: ${unexpected.join(", ")}` : "",
|
|
185
|
+
missing.length > 0 ? `missing entries: ${missing.join(", ")}` : ""
|
|
186
|
+
].filter(Boolean).join("; "));
|
|
2549
187
|
}
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
const
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
188
|
+
}
|
|
189
|
+
for (const [relativePath, expectedHash] of marker.files) {
|
|
190
|
+
const path = safeLegacyPath(folder, relativePath);
|
|
191
|
+
const content = await readRegularFileWithoutFollowing(path);
|
|
192
|
+
if (sha256(content) !== expectedHash) {
|
|
193
|
+
throw new Error(`edited file refused: ${relativePath}`);
|
|
2556
194
|
}
|
|
2557
|
-
outdatedFiles.push(file.relativePath);
|
|
2558
195
|
}
|
|
2559
|
-
const markerDrift = normalizeNewlines(markerContent) !== markerFor(definition, version);
|
|
2560
|
-
const status = missingFiles.length > 0 ? "incomplete" : editedFiles.length > 0 ? "edited" : markerDrift || outdatedFiles.length > 0 ? "outdated" : "ok";
|
|
2561
196
|
return {
|
|
2562
|
-
name
|
|
197
|
+
name,
|
|
2563
198
|
path: folder,
|
|
2564
|
-
status
|
|
2565
|
-
markerVersion,
|
|
2566
|
-
missingFiles,
|
|
2567
|
-
editedFiles,
|
|
2568
|
-
outdatedFiles,
|
|
2569
|
-
backupFiles
|
|
199
|
+
status: "eligible"
|
|
2570
200
|
};
|
|
2571
|
-
}));
|
|
2572
|
-
let entries = [];
|
|
2573
|
-
try {
|
|
2574
|
-
entries = await readdir(root);
|
|
2575
201
|
} catch (error) {
|
|
2576
|
-
|
|
2577
|
-
|
|
202
|
+
return {
|
|
203
|
+
name,
|
|
204
|
+
path: folder,
|
|
205
|
+
status: "refused",
|
|
206
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
207
|
+
};
|
|
2578
208
|
}
|
|
2579
|
-
const unmanagedFlowSkills = entries.filter((name) => (name === "flow" || name.startsWith("flow-")) && !expected.has(name)).map((name) => join(root, name));
|
|
2580
|
-
const syncRequiredSkills = skills.filter((skill) => ["missing", "incomplete", "outdated"].includes(skill.status)).map((skill) => skill.name);
|
|
2581
|
-
const actionRequiredSkills = skills.filter((skill) => ["foreign", "edited"].includes(skill.status) || skill.backupFiles.length > 0).map((skill) => skill.name);
|
|
2582
|
-
const actionRequired = actionRequiredSkills.length > 0;
|
|
2583
|
-
const syncRequired = syncRequiredSkills.length > 0;
|
|
2584
|
-
return {
|
|
2585
|
-
status: actionRequired ? "action_required" : syncRequired ? "sync_required" : "ok",
|
|
2586
|
-
version,
|
|
2587
|
-
root,
|
|
2588
|
-
expectedSkills: [...expected],
|
|
2589
|
-
skills,
|
|
2590
|
-
syncRequiredSkills,
|
|
2591
|
-
actionRequiredSkills,
|
|
2592
|
-
unmanagedFlowSkills
|
|
2593
|
-
};
|
|
2594
|
-
}
|
|
2595
|
-
function appendSkillList(lines, label, skills) {
|
|
2596
|
-
if (skills.length === 0)
|
|
2597
|
-
return;
|
|
2598
|
-
lines.push(`- ${label}: ${skills.join(", ")}`);
|
|
2599
209
|
}
|
|
2600
|
-
function
|
|
2601
|
-
const
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
`- skills root: ${report.root}`,
|
|
2606
|
-
`- expected skills: ${report.expectedSkills.join(", ")}`
|
|
2607
|
-
];
|
|
2608
|
-
appendSkillList(lines, "startup sync can install/update", report.syncRequiredSkills);
|
|
2609
|
-
appendSkillList(lines, "needs user decision", report.actionRequiredSkills);
|
|
2610
|
-
lines.push("", "Skills:");
|
|
2611
|
-
for (const skill of report.skills) {
|
|
2612
|
-
lines.push(`- ${skill.name}: ${skill.status} (${skill.path})${skill.markerVersion ? ` marker=${skill.markerVersion}` : ""}`);
|
|
2613
|
-
if (skill.missingFiles.length > 0) {
|
|
2614
|
-
lines.push(` missing: ${skill.missingFiles.join(", ")}`);
|
|
2615
|
-
}
|
|
2616
|
-
if (skill.editedFiles.length > 0) {
|
|
2617
|
-
lines.push(` edited: ${skill.editedFiles.join(", ")}`);
|
|
2618
|
-
}
|
|
2619
|
-
if (skill.outdatedFiles.length > 0) {
|
|
2620
|
-
lines.push(` outdated: ${skill.outdatedFiles.join(", ")}`);
|
|
2621
|
-
}
|
|
2622
|
-
if (skill.backupFiles.length > 0) {
|
|
2623
|
-
lines.push(` backups: ${skill.backupFiles.join(", ")}`);
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
if (report.unmanagedFlowSkills.length > 0) {
|
|
2627
|
-
lines.push("", "Unmanaged Flow-like skill folders:");
|
|
2628
|
-
for (const path of report.unmanagedFlowSkills)
|
|
2629
|
-
lines.push(`- ${path}`);
|
|
2630
|
-
}
|
|
2631
|
-
lines.push("", "Recommendation:");
|
|
2632
|
-
if (report.status === "ok") {
|
|
2633
|
-
lines.push("- Flow skills are present and current.");
|
|
2634
|
-
} else if (report.status === "sync_required") {
|
|
2635
|
-
lines.push("- Start or restart OpenCode with opencode-plugin-flow enabled so startup sync can install or update the listed skills. If Flow then reports restart_required, restart OpenCode once more so the refreshed skill registry is used.");
|
|
2636
|
-
} else {
|
|
2637
|
-
lines.push("- Resolve user-owned or edited managed skill folders, then restart OpenCode. Move a folder aside to let Flow recreate it, or keep it intentionally as a local override.");
|
|
2638
|
-
if (report.skills.some((skill) => skill.backupFiles.length > 0)) {
|
|
2639
|
-
lines.push("- Flow saved earlier local edits as .backup files; review each one and delete it once the saved copy is no longer needed. Sync ignores them, and uninstall removes them (naming each) along with the folder.");
|
|
210
|
+
async function ensureRealArchiveRoot(path) {
|
|
211
|
+
const existing = await optionalStat(path);
|
|
212
|
+
if (existing) {
|
|
213
|
+
if (!existing.isDirectory()) {
|
|
214
|
+
throw new Error(`Legacy archive path is not a real directory: ${path}`);
|
|
2640
215
|
}
|
|
216
|
+
return;
|
|
2641
217
|
}
|
|
2642
|
-
lines.push(`- Details command: ${formatFlowDoctorCommand(report.version)}`);
|
|
2643
|
-
return `${lines.join(`
|
|
2644
|
-
`)}
|
|
2645
|
-
`;
|
|
2646
|
-
}
|
|
2647
|
-
async function listSkillFolderFiles(folder) {
|
|
2648
|
-
const entries = await readdir(folder, {
|
|
2649
|
-
recursive: true,
|
|
2650
|
-
withFileTypes: true
|
|
2651
|
-
});
|
|
2652
|
-
return entries.filter((entry) => entry.isFile()).map((entry) => join(entry.parentPath, entry.name).slice(folder.length + 1).split(sep).join("/"));
|
|
2653
|
-
}
|
|
2654
|
-
async function listFlowBackupFiles(folder) {
|
|
2655
|
-
let names;
|
|
2656
218
|
try {
|
|
2657
|
-
|
|
219
|
+
await mkdir(path, { mode: 448 });
|
|
2658
220
|
} catch (error) {
|
|
2659
|
-
if (error.code
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
if (await isFlowCreatedBackup(folder, name))
|
|
2666
|
-
backups.push(name);
|
|
221
|
+
if (error.code !== "EEXIST")
|
|
222
|
+
throw error;
|
|
223
|
+
const raced = await optionalStat(path);
|
|
224
|
+
if (!raced?.isDirectory()) {
|
|
225
|
+
throw new Error(`Legacy archive path is not a real directory: ${path}`);
|
|
226
|
+
}
|
|
2667
227
|
}
|
|
2668
|
-
return backups;
|
|
2669
228
|
}
|
|
2670
|
-
async function
|
|
2671
|
-
const
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
const
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
const
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
return { pristine: false, backups };
|
|
2683
|
-
}
|
|
2684
|
-
continue;
|
|
2685
|
-
}
|
|
2686
|
-
if (await isFlowCreatedBackup(folder, relativePath)) {
|
|
2687
|
-
backups.push(relativePath);
|
|
229
|
+
async function cleanupLegacySkills(options) {
|
|
230
|
+
const home = options?.home ?? configuredHome();
|
|
231
|
+
const root = resolveLegacySkillsRoot(home);
|
|
232
|
+
const archiveRoot = resolveLegacyArchiveRoot(home);
|
|
233
|
+
const apply = options?.apply === true;
|
|
234
|
+
const results = [];
|
|
235
|
+
let archiveReady = false;
|
|
236
|
+
for (const name of FLOW_GUIDANCE_TOPICS) {
|
|
237
|
+
const path = join(root, name);
|
|
238
|
+
const inspected = await inspectLegacyFolder(name, path);
|
|
239
|
+
if (!apply || inspected.status !== "eligible") {
|
|
240
|
+
results.push(inspected);
|
|
2688
241
|
continue;
|
|
2689
242
|
}
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
}
|
|
2694
|
-
async function uninstallFlowSkills(home = homeDir(), options = {}) {
|
|
2695
|
-
const root = resolveFlowSkillsRoot(home);
|
|
2696
|
-
const removed = [];
|
|
2697
|
-
const kept = [];
|
|
2698
|
-
const removedBackups = [];
|
|
2699
|
-
let entries;
|
|
2700
|
-
try {
|
|
2701
|
-
entries = await readdir(root);
|
|
2702
|
-
} catch (error) {
|
|
2703
|
-
if (error.code === "ENOENT") {
|
|
2704
|
-
return { removed, kept, removedBackups };
|
|
243
|
+
if (!archiveReady) {
|
|
244
|
+
await ensureRealArchiveRoot(archiveRoot);
|
|
245
|
+
archiveReady = true;
|
|
2705
246
|
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
247
|
+
const archivePath = join(archiveRoot, `${name}-${new Date().toISOString().replaceAll(":", "-")}-${crypto.randomUUID()}`);
|
|
248
|
+
try {
|
|
249
|
+
await rename(path, archivePath);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
if (error.code !== "ENOENT")
|
|
252
|
+
throw error;
|
|
253
|
+
results.push({
|
|
254
|
+
name,
|
|
255
|
+
path,
|
|
256
|
+
status: "refused",
|
|
257
|
+
reason: "folder changed while cleanup was running"
|
|
258
|
+
});
|
|
2715
259
|
continue;
|
|
2716
260
|
}
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
261
|
+
await options?.afterQuarantine?.({ name, path, archivePath });
|
|
262
|
+
const verified = await inspectLegacyFolder(name, archivePath);
|
|
263
|
+
if (verified.status !== "eligible") {
|
|
264
|
+
results.push({
|
|
265
|
+
name,
|
|
266
|
+
path,
|
|
267
|
+
status: "quarantined",
|
|
268
|
+
reason: "folder changed while cleanup was running; preserved for manual recovery",
|
|
269
|
+
archivePath
|
|
270
|
+
});
|
|
2720
271
|
continue;
|
|
2721
272
|
}
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
}
|
|
2728
|
-
removed.push(folder);
|
|
273
|
+
results.push({
|
|
274
|
+
name,
|
|
275
|
+
path,
|
|
276
|
+
status: "archived",
|
|
277
|
+
archivePath
|
|
278
|
+
});
|
|
2729
279
|
}
|
|
2730
|
-
return {
|
|
280
|
+
return {
|
|
281
|
+
mode: apply ? "apply" : "dry-run",
|
|
282
|
+
root,
|
|
283
|
+
archiveRoot,
|
|
284
|
+
results
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/version.ts
|
|
289
|
+
import { createRequire } from "node:module";
|
|
290
|
+
function resolveFlowPluginVersion() {
|
|
291
|
+
try {
|
|
292
|
+
const require2 = createRequire(import.meta.url);
|
|
293
|
+
const manifest = require2("../package.json");
|
|
294
|
+
if (manifest.version)
|
|
295
|
+
return manifest.version;
|
|
296
|
+
} catch {}
|
|
297
|
+
return "0.0.0";
|
|
2731
298
|
}
|
|
2732
299
|
|
|
2733
300
|
// src/cli.ts
|
|
2734
301
|
function usage() {
|
|
2735
302
|
return [
|
|
2736
|
-
"usage: opencode-plugin-flow
|
|
303
|
+
"usage: opencode-plugin-flow legacy-cleanup <--dry-run|--apply> [--json]",
|
|
2737
304
|
"",
|
|
2738
305
|
"commands:",
|
|
2739
|
-
"
|
|
2740
|
-
" sync Install or refresh managed Flow skills",
|
|
2741
|
-
" uninstall Remove pristine Flow-owned managed skills",
|
|
2742
|
-
"",
|
|
2743
|
-
"doctor options:",
|
|
2744
|
-
" --json Write the doctor report as JSON",
|
|
2745
|
-
" --check, --strict Exit nonzero when doctor status is not ok",
|
|
306
|
+
" legacy-cleanup Inspect or archive marker-proven legacy global Flow skills",
|
|
2746
307
|
"",
|
|
2747
|
-
"
|
|
2748
|
-
" --dry-run
|
|
2749
|
-
"",
|
|
2750
|
-
"
|
|
308
|
+
"options:",
|
|
309
|
+
" --dry-run Report eligible folders without changing the filesystem",
|
|
310
|
+
" --apply Move eligible folders to a recoverable archive outside skill discovery",
|
|
311
|
+
" Cleanup never deletes legacy folders",
|
|
312
|
+
" --json Write the report as JSON",
|
|
2751
313
|
" --help Show this help",
|
|
2752
314
|
" --version Print the plugin version"
|
|
2753
315
|
].join(`
|
|
2754
316
|
`);
|
|
2755
317
|
}
|
|
2756
|
-
function
|
|
2757
|
-
|
|
2758
|
-
}
|
|
2759
|
-
function writeDoctorReport(report, options) {
|
|
2760
|
-
if (options.json) {
|
|
318
|
+
function writeReport(report, json) {
|
|
319
|
+
if (json) {
|
|
2761
320
|
process.stdout.write(`${JSON.stringify(report, null, 2)}
|
|
2762
321
|
`);
|
|
2763
322
|
return;
|
|
2764
323
|
}
|
|
2765
|
-
process.stdout.write(
|
|
324
|
+
process.stdout.write(`Flow legacy skill cleanup (${report.mode})
|
|
325
|
+
`);
|
|
326
|
+
process.stdout.write(`- legacy root: ${report.root}
|
|
327
|
+
`);
|
|
328
|
+
process.stdout.write(`- archive root: ${report.archiveRoot}
|
|
329
|
+
`);
|
|
330
|
+
for (const result of report.results) {
|
|
331
|
+
process.stdout.write(`- ${result.name}: ${result.status}
|
|
332
|
+
`);
|
|
333
|
+
if (result.reason)
|
|
334
|
+
process.stdout.write(` reason: ${result.reason}
|
|
335
|
+
`);
|
|
336
|
+
if (result.archivePath) {
|
|
337
|
+
const label = result.status === "archived" ? "archived" : "preserved";
|
|
338
|
+
process.stdout.write(` ${label} at: ${result.archivePath}
|
|
339
|
+
`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
2766
342
|
}
|
|
2767
343
|
async function main(argv) {
|
|
2768
|
-
const command = argv
|
|
2769
|
-
const flags = argv.slice(3);
|
|
344
|
+
const [command, ...flags] = argv.slice(2);
|
|
2770
345
|
if (command === "--help" || command === "-h") {
|
|
2771
346
|
process.stdout.write(`${usage()}
|
|
2772
347
|
`);
|
|
@@ -2777,86 +352,21 @@ async function main(argv) {
|
|
|
2777
352
|
`);
|
|
2778
353
|
return;
|
|
2779
354
|
}
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
}
|
|
2786
|
-
if (command === "doctor") {
|
|
2787
|
-
const knownDoctorFlags = new Set(["--json", "--check", "--strict"]);
|
|
2788
|
-
if (!hasOnlyKnownFlags(flags, knownDoctorFlags)) {
|
|
2789
|
-
process.stderr.write(`${usage()}
|
|
2790
|
-
`);
|
|
2791
|
-
process.exitCode = 2;
|
|
2792
|
-
return;
|
|
2793
|
-
}
|
|
2794
|
-
const report = await inspectFlowSkillInstall();
|
|
2795
|
-
writeDoctorReport(report, { json: flags.includes("--json") });
|
|
2796
|
-
if ((report.status === "sync_required" || report.status === "action_required") && (flags.includes("--check") || flags.includes("--strict"))) {
|
|
2797
|
-
process.exitCode = 1;
|
|
2798
|
-
}
|
|
2799
|
-
return;
|
|
2800
|
-
}
|
|
2801
|
-
const knownUninstallFlags = new Set(["--dry-run"]);
|
|
2802
|
-
if (command === "uninstall" && !hasOnlyKnownFlags(flags, knownUninstallFlags)) {
|
|
2803
|
-
process.stderr.write(`${usage()}
|
|
2804
|
-
`);
|
|
2805
|
-
process.exitCode = 2;
|
|
2806
|
-
return;
|
|
2807
|
-
}
|
|
2808
|
-
if (command === "sync" && flags.length > 0) {
|
|
355
|
+
const knownFlags = new Set(["--dry-run", "--apply", "--json"]);
|
|
356
|
+
const validFlags = flags.every((flag) => knownFlags.has(flag));
|
|
357
|
+
const dryRun = flags.includes("--dry-run");
|
|
358
|
+
const apply = flags.includes("--apply");
|
|
359
|
+
if (command !== "legacy-cleanup" || !validFlags || dryRun === apply) {
|
|
2809
360
|
process.stderr.write(`${usage()}
|
|
2810
361
|
`);
|
|
2811
362
|
process.exitCode = 2;
|
|
2812
363
|
return;
|
|
2813
364
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
const actionRequired = results.filter((result2) => result2.action === "skipped_foreign");
|
|
2819
|
-
process.stdout.write(`Flow skill sync (${version})
|
|
2820
|
-
`);
|
|
2821
|
-
for (const result2 of results) {
|
|
2822
|
-
process.stdout.write(`- ${result2.name}: ${result2.action}
|
|
2823
|
-
`);
|
|
2824
|
-
for (const backupPath of result2.backupPaths ?? []) {
|
|
2825
|
-
process.stdout.write(` backup: ${backupPath}
|
|
2826
|
-
`);
|
|
2827
|
-
}
|
|
2828
|
-
}
|
|
2829
|
-
if (changed.length > 0) {
|
|
2830
|
-
process.stdout.write(`Restart OpenCode so the refreshed skill registry is used.
|
|
2831
|
-
`);
|
|
2832
|
-
}
|
|
2833
|
-
if (actionRequired.length > 0) {
|
|
2834
|
-
process.stdout.write(`Some managed skill folders are user-owned or edited; run doctor for repair guidance.
|
|
2835
|
-
`);
|
|
2836
|
-
}
|
|
2837
|
-
return;
|
|
2838
|
-
}
|
|
2839
|
-
const dryRun = flags.includes("--dry-run");
|
|
2840
|
-
const result = await uninstallFlowSkills(undefined, { dryRun });
|
|
2841
|
-
for (const path of result.removed) {
|
|
2842
|
-
process.stdout.write(`${dryRun ? "Would remove" : "Removed"} Flow skill: ${path}
|
|
2843
|
-
`);
|
|
2844
|
-
}
|
|
2845
|
-
for (const path of result.kept) {
|
|
2846
|
-
process.stdout.write(`Kept non-Flow or user-edited skill: ${path}
|
|
2847
|
-
`);
|
|
2848
|
-
}
|
|
2849
|
-
if (result.removedBackups.length > 0) {
|
|
2850
|
-
process.stdout.write(`${dryRun ? "Would remove" : "Removed"} Flow-created backup files holding your earlier edits:
|
|
2851
|
-
`);
|
|
2852
|
-
for (const path of result.removedBackups) {
|
|
2853
|
-
process.stdout.write(` ${path}
|
|
2854
|
-
`);
|
|
2855
|
-
}
|
|
365
|
+
const report = await cleanupLegacySkills({ apply });
|
|
366
|
+
writeReport(report, flags.includes("--json"));
|
|
367
|
+
if (apply && report.results.some((result) => ["refused", "quarantined"].includes(result.status))) {
|
|
368
|
+
process.exitCode = 1;
|
|
2856
369
|
}
|
|
2857
|
-
process.stdout.write(dryRun ? `Dry run: no files were removed.
|
|
2858
|
-
` : `Remove opencode-plugin-flow from your OpenCode plugin config and restart OpenCode.
|
|
2859
|
-
`);
|
|
2860
370
|
}
|
|
2861
371
|
main(process.argv).catch((error) => {
|
|
2862
372
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
@@ -2864,4 +374,4 @@ main(process.argv).catch((error) => {
|
|
|
2864
374
|
process.exitCode = 1;
|
|
2865
375
|
});
|
|
2866
376
|
|
|
2867
|
-
//# debugId=
|
|
377
|
+
//# debugId=690F8C77CD4F802F64756E2164756E21
|