opencode-plugin-flow 4.1.6 → 4.1.8

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/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{createHash as Fe}from"node:crypto";import{mkdir as Ce,readdir as ee,readFile as Ue,rm as qe,writeFile as y}from"node:fs/promises";import{createRequire as Ae}from"node:module";import{dirname as Te,join as l,normalize as Pe,sep as De}from"node:path";var j=`# Flow worker handoff contract
2
+ import{createHash as qe}from"node:crypto";import{mkdir as Pe,readdir as te,readFile as Te,rm as De,writeFile as y}from"node:fs/promises";import{createRequire as je}from"node:module";import{dirname as Be,join as l,normalize as We,sep as Se}from"node:path";var j=`# Flow worker handoff contract
3
3
 
4
4
  Flow managers merge only the worker's final response. Treat that response as the
5
5
  worker report of record: it must include the assigned scope, what was actually
@@ -118,7 +118,7 @@ live-verified | test-verified | type-check-only | not-verified
118
118
 
119
119
  The manager must inspect and validate any candidate patch before recording Flow
120
120
  completion.
121
- `;var W=`# Parallel orchestration
121
+ `;var B=`# Parallel orchestration
122
122
 
123
123
  Use fan-out when Flow work is broad enough that independent workers can gather
124
124
  evidence faster than one linear pass. The manager still owns the Flow session:
@@ -247,7 +247,7 @@ Start a follow-up wave when first-wave handoffs reveal:
247
247
 
248
248
  Do not recurse by default. If a worker says it needs another worker, the manager
249
249
  decides whether that is a second wave and writes the next bounded prompt.
250
- `;var O='# 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- `Completion requires a passing featureReview`: run or request a real review and include a passing `featureReview` only when there are no blocking findings.\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';var z=`# Verification gates
250
+ `;var W='# 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- `Completion requires a passing featureReview`: run or request a real review and include a passing `featureReview` only when there are no blocking findings.\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';var S=`# Verification gates
251
251
 
252
252
  Verification is how Flow keeps parallel work from turning into parallel
253
253
  guesswork. Worker handoffs are candidate evidence; the manager decides what can
@@ -337,9 +337,9 @@ Before presenting or recording the result:
337
337
 
338
338
  \`Status: success\` only says the worker believes its slice is done. The manager
339
339
  still checks coverage and evidence before trusting the result.
340
- `;var B=`---
340
+ `;var z=`---
341
341
  name: flow
342
- description: Main Flow loop for skills-first OpenCode work. Use when a user asks for Flow-guided planning, autonomous execution, resumable implementation, session status, or end-to-end delivery with validation and review gates.
342
+ description: Run the end-to-end Flow loop for skills-first OpenCode work. Use when a user asks for Flow-guided planning through implementation, resumable autonomous delivery, session status, or completion with validation and review gates.
343
343
  ---
344
344
 
345
345
  # Flow
@@ -353,13 +353,17 @@ Use Flow as a minimal state ledger, not as a framework. Skills provide judgment;
353
353
  load Flow skills in this startup. A just-synced skill can be on disk while
354
354
  unavailable to the running OpenCode process.
355
355
  2. 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.
356
- 3. Load \`flow-run\`, call \`flow_run_start\`, implement exactly one feature, validate it, and prepare a \`flow_feature_complete\` payload.
356
+ 3. 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, or browser/UI work, use \`flow-test\` to choose and summarize evidence before completion.
357
357
  4. Load \`flow-review\` for the required feature review. The reviewer reports a \`featureReview\` payload; the manager records it inside \`flow_feature_complete\`.
358
358
  5. 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\`.
359
359
  6. After all features are complete, archive the session with \`flow_session_close\` using \`kind: "completed"\`.
360
360
 
361
361
  Use \`references/parallel-orchestration.md\` for broad read-only discovery, audit, validation, review, verification, or candidate implementation waves. Hidden Flow workers are injected by plugin config; invoke the named worker when it is available. Its \`references/handoff-format.md\` and \`references/verification-gates.md\` companions define the worker contracts. The manager owns every \`flow_*\` state change.
362
362
 
363
+ Do not commit, push, amend, rebase, publish, or mutate releases during the
364
+ autonomous Flow loop. Load \`flow-commit\` only when the user explicitly asks for
365
+ commit preparation or commit creation.
366
+
363
367
  ## Skill Availability
364
368
 
365
369
  If \`flow_status\` returns \`setup.skills\`, report that setup status and stop
@@ -367,9 +371,10 @@ loading Flow skills in the current OpenCode startup. Missing, incomplete, or
367
371
  outdated managed skills require a sync/restart cycle before their instructions
368
372
  can be trusted by the running process.
369
373
 
370
- If optional helper skills such as \`flow-deslop\` or \`flow-ui-quality\` are
371
- unavailable, continue only with explicit coverage gaps. Do not copy their
372
- rubrics into another skill and do not claim their quality checks were completed.
374
+ If optional helper skills such as \`flow-test\`, \`flow-deslop\`, or
375
+ \`flow-ui-quality\` are unavailable, continue only with explicit coverage gaps. Do
376
+ not copy their rubrics into another skill and do not claim their quality checks
377
+ were completed.
373
378
 
374
379
  ## Runtime Surface
375
380
 
@@ -404,7 +409,121 @@ Planning and running require loaded Flow tools; do not simulate plan approval or
404
409
  - Unknown runtime error: read \`summary\` and \`recovery\`; see \`references/recovery-playbook.md\` for common cases.
405
410
 
406
411
  Never fabricate validation output, backfill review approval you did not perform, or close as \`deferred\`/\`abandoned\` merely to avoid an unfinished-work blocker.
407
- `;var N=`# Safe refactor workflow
412
+ `;var O=`---
413
+ name: flow-commit
414
+ 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.
415
+ ---
416
+
417
+ # Flow Commit
418
+
419
+ Use this skill only when the user asks to prepare or create a commit, write a
420
+ commit message, stage intended work, or validate staged changes before
421
+ committing. It is not part of the autonomous Flow loop and must not be loaded
422
+ automatically by \`flow\`, \`flow-run\`, or \`flow_feature_complete\`.
423
+
424
+ When a Flow session exists, a commit never substitutes for Flow completion. The
425
+ manager still records validation and review evidence through
426
+ \`flow_feature_complete\` before claiming a Flow feature is done. Default to commit
427
+ preparation only after \`flow_feature_complete\` has recorded the relevant
428
+ completion evidence. If the user explicitly asks for a WIP commit, preserve
429
+ failing or incomplete validation context in the message.
430
+
431
+ ## Boundaries
432
+
433
+ - Preserve unrelated user work.
434
+ - Stage explicit paths or hunks only. Do not default to \`git add .\` or
435
+ \`git add -A\`.
436
+ - Do not commit \`.flow/**\` state unless the maintainer explicitly asks to
437
+ archive those exact files.
438
+ - Do not push, amend, rebase, squash, reset, force-push, tag, release, publish,
439
+ or mutate remote state unless the user explicitly authorizes that exact
440
+ operation.
441
+ - Stop before committing secrets, local config, credentials, private keys,
442
+ generated release artifacts, or suspicious environment files.
443
+ - Stop when validation fails unless the user explicitly wants an unfinished WIP
444
+ commit and the commit message says so.
445
+
446
+ ## Inspect
447
+
448
+ Start with the worktree and intent:
449
+
450
+ 1. Run \`git status --short\`.
451
+ 2. Inspect unstaged and staged changes separately with \`git diff\` and
452
+ \`git diff --cached\`.
453
+ 3. Inspect untracked files before deciding whether they belong.
454
+ 4. Group changes by intent, feature, and risk. Prefer one coherent commit over
455
+ one large mixed commit.
456
+ 5. Identify exclusions: unrelated files, local notes, \`.flow/**\`, generated
457
+ artifacts, logs, caches, credentials, and temporary outputs.
458
+
459
+ If the commit boundary is unclear, propose the boundary and ask before staging.
460
+
461
+ ## Stage
462
+
463
+ Stage only the intended boundary:
464
+
465
+ - Use explicit file paths for whole-file staging.
466
+ - Use patch staging for mixed-intent files.
467
+ - Re-run \`git status --short\` and \`git diff --cached --stat\` after staging.
468
+ - Review the full staged diff before validation and commit.
469
+
470
+ Never undo or rewrite user changes to make staging easier. If a file contains
471
+ mixed user and agent work, either stage selected hunks or ask for direction.
472
+
473
+ ## Screen and Validate
474
+
475
+ Before commit creation, check the staged diff for:
476
+
477
+ - Secrets, tokens, private keys, credentials, cookies, and unredacted personal
478
+ data.
479
+ - \`.env\`, local config, machine-specific paths, and editor files.
480
+ - \`.flow/**\` state.
481
+ - Generated artifacts that are not normally versioned.
482
+ - Package or version metadata drift unrelated to the requested change.
483
+
484
+ When this repository-local contribution preflight exists, defer to it for staged
485
+ and outgoing validation instead of duplicating its checks:
486
+
487
+ \`\`\`bash
488
+ .agents/skills/flow-contribution-check/scripts/preflight.sh commit
489
+ \`\`\`
490
+
491
+ Run it after staging and rerun it after any staging change. The preflight
492
+ validates staged or outgoing work; it does not choose commit boundaries or write
493
+ commit messages. If the script is absent, use the repository's documented commit
494
+ preflight from package scripts, AGENTS/docs, or CI guidance.
495
+
496
+ Use the repository's documented broad validation gate when a full local check is
497
+ appropriate, such as package scripts, AGENTS/docs, or CI guidance. Use narrower
498
+ tests only when the user has asked for a lighter pass or when the change is
499
+ intentionally not ready for the broad gate.
500
+
501
+ ## Message
502
+
503
+ Propose a commit message that reflects the staged diff:
504
+
505
+ - Subject: imperative, specific, and scoped.
506
+ - Body when useful: context, changed areas, validation run, and remaining risk.
507
+ - Do not mention unstaged or excluded work as if it were included.
508
+ - Include WIP or failing-validation context only when the user explicitly chose
509
+ that path.
510
+
511
+ ## Create Commit
512
+
513
+ Create the commit only after the user explicitly asks for commit creation or has
514
+ already authorized it in the current request.
515
+
516
+ Before running \`git commit\`, report:
517
+
518
+ - Staged paths.
519
+ - Excluded dirty or untracked paths.
520
+ - Validation command and result.
521
+ - Proposed message.
522
+ - Any risks or gaps.
523
+
524
+ After a successful commit, report the commit hash and leave push or release
525
+ actions for a separate explicit request.
526
+ `;var E=`# Safe refactor workflow
408
527
 
409
528
  Refactoring is a behavior-preserving sequence of small changes. This workflow keeps cleanup from becoming an unreviewable rewrite.
410
529
 
@@ -446,7 +565,7 @@ Weak evidence includes:
446
565
  - Public contracts and compatibility shims remain intact or were explicitly planned.
447
566
  - Deleted code is actually unreachable or obsolete.
448
567
  - Validation can catch a realistic mistake in the refactor.
449
- `;var V=`# Deslop smell rubric
568
+ `;var N=`# Deslop smell rubric
450
569
 
451
570
  Use this rubric to turn vague cleanup instincts into reviewable findings.
452
571
 
@@ -480,9 +599,9 @@ class; severity; location; evidence read; refutation checked; why it matters; sa
480
599
  \`\`\`
481
600
 
482
601
  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.
483
- `;var E=`---
602
+ `;var V=`---
484
603
  name: flow-deslop
485
- description: Flow guidance for evidence-backed code smell cleanup, AI-slop removal, overengineering reduction, maintainability refactors, and behavior-preserving cleanup. Use when planning, executing, or reviewing broad cleanup/refactor work, code smell findings, duplicated or bloated code, speculative abstractions, dead code, or agent-introduced mess.
604
+ 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, dead code, or broad cleanup/refactor review.
486
605
  ---
487
606
 
488
607
  # Flow deslop
@@ -522,7 +641,7 @@ For each claimed smell removal, verify:
522
641
  - **blast radius** — public contracts and downstream callers still work.
523
642
 
524
643
  Never approve cleanup because it "looks cleaner" without evidence. Tests passing is necessary but not sufficient when the refactor changes structure across files.
525
- `;var S=`# Parallel discovery
644
+ `;var G=`# Parallel discovery
526
645
 
527
646
  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.
528
647
 
@@ -588,7 +707,7 @@ Convert only evidence-backed work into plan fields:
588
707
  - feature \`validation\`: checks expected to prove the feature.
589
708
 
590
709
  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.
591
- `;var G=`# Planning examples
710
+ `;var L=`# Planning examples
592
711
 
593
712
  ## Rate limiting feature set
594
713
 
@@ -688,6 +807,9 @@ If \`flow_plan_save\` or \`flow_plan_approve\` is unavailable, stop and tell the
688
807
 
689
808
  - Read the files, docs, tests, package scripts, and local conventions that determine the work.
690
809
  - 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 apply its coverage gate before fan-out.
810
+ - For complex validation, regression-sensitive changes, browser/UI workflows,
811
+ or uncertain test strategy, load \`flow-test\`. If it is unavailable, record a
812
+ planning gap and keep validation claims conservative.
691
813
  - For cleanup/refactor goals, load \`flow-deslop\`. If it is unavailable, record
692
814
  a planning gap and keep cleanup claims conservative.
693
815
  - For UI/frontend goals, load \`flow-ui-quality\`. If it is unavailable, record a
@@ -730,14 +852,17 @@ Use only \`finalReviewPolicy: "broad"\` or \`"detailed"\`. These are the canonic
730
852
  - Split by dependency order: foundations before callers, schema before consumers, implementation before docs when docs depend on behavior.
731
853
  - Avoid "misc cleanup" features. Tie cleanup to evidence and targets.
732
854
  - Keep feature ids stable once the plan is approved.
733
- - Put scope boundaries in \`targets\` and expected checks in \`validation\`.
855
+ - Put scope boundaries in \`targets\` and expected checks in \`validation\`. Each
856
+ validation entry should name the expected test level, such as targeted unit,
857
+ integration, browser/e2e, package/build, docs/static, cleanup preservation, or
858
+ broad project gate.
734
859
 
735
860
  ## Approval
736
861
 
737
862
  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.
738
863
 
739
864
  See \`references/planning-examples.md\` for payload examples and decomposition anti-patterns.
740
- `;var L=`# Review rubric
865
+ `;var K=`# Review rubric
741
866
 
742
867
  Use this to decide whether a \`featureReview\` or \`finalReview\` payload may pass.
743
868
 
@@ -844,6 +969,9 @@ recorded.
844
969
  - Identify whether this is a feature review or final review.
845
970
  - Read the approved plan fields relevant to the work: \`requirements\`, \`decisions\`, feature \`targets\`, feature \`validation\`, and dependencies.
846
971
  - Inspect the actual diff, changed files, tests, and validation output. Do not review only the completion summary.
972
+ - Load \`flow-test\` for validation-heavy, regression-sensitive, browser/UI, or
973
+ unclear coverage reviews. If it is unavailable, record a coverage gap and
974
+ treat missing validation evidence as a gap or blocker based on user impact.
847
975
  - Load \`references/review-rubric.md\` for severity, depth, and payload shape.
848
976
 
849
977
  ## Feature Review Depth
@@ -892,7 +1020,7 @@ Use \`status: "failed"\` when any blocking finding remains. Advisory findings ma
892
1020
  \`finalReview\` payload.
893
1021
 
894
1022
  Never approve to unblock completion, fix findings in the review pass, or vouch for validation you did not inspect.
895
- `;var K=`# Audit findings rubric
1023
+ `;var Q=`# Audit findings rubric
896
1024
 
897
1025
  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.
898
1026
 
@@ -1028,9 +1156,18 @@ If \`flow_run_start\` is unavailable, stop and tell the user to check that \`ope
1028
1156
  - Keep edits scoped to the active feature. If new scope appears, stop and replan or defer it to another feature.
1029
1157
  - Preserve unrelated user changes in the worktree.
1030
1158
  - When a wrong assumption invalidates the feature, use \`flow_feature_reset\`; do not pile patches onto a bad path.
1159
+ - Do not stage, commit, push, amend, rebase, publish, or mutate releases as part
1160
+ of feature execution. If the user explicitly asks for commit preparation, load
1161
+ \`flow-commit\` only after \`flow_feature_complete\` has been recorded, unless the
1162
+ user explicitly asks for a WIP commit path. Keep Git boundaries separate from
1163
+ Flow state recording.
1031
1164
 
1032
1165
  ## Validate
1033
1166
 
1167
+ - For complex validation, regression-sensitive changes, browser/UI workflows,
1168
+ failure-prone checks, unclear coverage, route QA, exploratory QA, or
1169
+ \`validationRun\` summarization, load \`flow-test\`. If it is unavailable, record
1170
+ the coverage gap and keep validation claims conservative.
1034
1171
  - Read \`references/validation-rubric.md\` before completing.
1035
1172
  - Run the strongest practical checks for the changed behavior.
1036
1173
  - Record concrete command names, status, and observed results. "Tests pass" is not evidence.
@@ -1057,8 +1194,9 @@ and records it.
1057
1194
 
1058
1195
  If \`flow_status\` reports \`setup.skills\` or \`flow-review\` cannot be loaded, do
1059
1196
  not record a Flow-gated \`featureReview\` or \`finalReview\`. You may perform an
1060
- advisory review using available context or bundled reviewer fallback text, then
1061
- complete with \`status: "needs_input"\` if review evidence is required to proceed.
1197
+ advisory review using available context or the bundled review fallback provided
1198
+ by plugin config, then complete with \`status: "needs_input"\` if review evidence
1199
+ is required to proceed.
1062
1200
 
1063
1201
  For the final feature, also obtain a \`finalReview\` payload whose \`reviewDepth\` equals the approved plan's \`finalReviewPolicy\`.
1064
1202
 
@@ -1079,7 +1217,131 @@ Complete with:
1079
1217
  \`\`\`
1080
1218
 
1081
1219
  If genuinely blocked, call \`flow_feature_complete\` with \`status: "needs_input"\` and an \`outcome\` that explains the blocker and next step. Never fabricate validation or review evidence to force progress.
1082
- `;var J=`# UI quality rubric
1220
+ `;var J=`---
1221
+ name: flow-test
1222
+ description: Test, validate, make test plans, triage failures, and gather Flow validation evidence. Use when selecting checks, running tests, running browser QA for UI changes, classifying failures, or preparing validationRun evidence for flow_feature_complete.
1223
+ ---
1224
+
1225
+ # Flow Test
1226
+
1227
+ Use this skill to decide and gather validation evidence. It produces validation
1228
+ evidence only: the manager still owns \`flow_feature_complete\`, review payloads,
1229
+ plan approval, session closure, and every other Flow state change.
1230
+
1231
+ Do not mutate \`.flow/**\`, approve plans, complete features, close sessions, or
1232
+ substitute for \`flow-review\`. If Flow tools are unavailable, this skill can still
1233
+ produce an advisory validation plan or test summary, but it cannot record Flow
1234
+ state.
1235
+
1236
+ ## Inputs
1237
+
1238
+ Start from the smallest concrete surface:
1239
+
1240
+ - The approved feature \`summary\`, \`targets\`, and \`validation\` entries when a
1241
+ Flow session exists.
1242
+ - The actual diff, changed files, package scripts, docs, and test conventions.
1243
+ - Recent command output from this session or from a trusted worker handoff.
1244
+ - Any user-stated acceptance criteria, browser target, fixture, or environment
1245
+ constraint.
1246
+
1247
+ Prefer repository scripts and local conventions over invented commands. If a
1248
+ command has not been run in this session or directly reported by a trusted
1249
+ worker with raw outcome, recommend it instead of claiming it passed.
1250
+
1251
+ ## Select Coverage
1252
+
1253
+ Choose checks from changed-surface risk, not from habit:
1254
+
1255
+ - **Targeted behavior**: unit, integration, CLI, route, or component tests that
1256
+ exercise the changed behavior and would fail without the fix.
1257
+ - **Integration and persistence**: database, filesystem, API, adapter, lock, or
1258
+ serialization paths touched by the feature.
1259
+ - **Browser or e2e**: user-visible workflows, responsive states, accessibility
1260
+ basics, form flows, and screenshots when a local target and browser tooling
1261
+ are available.
1262
+ - **Package and build shape**: typecheck, lint, build, generated distribution,
1263
+ or schema checks when public contracts, bundling, or package exports changed.
1264
+ - **Docs and mechanical edits**: markdown rendering, link/path sanity, spelling
1265
+ of commands, or the narrowest project check when behavior is unchanged.
1266
+ - **Cleanup/refactor**: behavior-preservation tests plus the relevant broad
1267
+ check; formatting alone is not evidence of preserved behavior.
1268
+ - **Final feature**: the repository's broad gate, full relevant suite, build, or
1269
+ equivalent release gate before \`validationScope: "broad"\` is recorded.
1270
+
1271
+ If the planned coverage is weaker than the risk, say so explicitly and list the
1272
+ missing evidence.
1273
+
1274
+ ## Run Discipline
1275
+
1276
+ For each check:
1277
+
1278
+ 1. State the hypothesis: what behavior or contract the check is expected to
1279
+ prove.
1280
+ 2. Run the command or manual workflow when the environment allows it.
1281
+ 3. Record exact command, status, and observed result.
1282
+ 4. If it fails, classify the failure before editing:
1283
+ - product failure
1284
+ - test failure
1285
+ - environment failure
1286
+ - pre-existing failure
1287
+ - flake
1288
+ - unrelated failure
1289
+ 5. Before a fix attempt, write a short failure hypothesis that names the likely
1290
+ cause and the file or behavior to inspect.
1291
+ 6. After a fix, rerun the failing check and one appropriate regression check.
1292
+
1293
+ Do not trim failure output so far that the manager cannot understand the
1294
+ failure. Do redact secrets and credentials.
1295
+
1296
+ ## Browser and Exploratory QA
1297
+
1298
+ For meaningful UI or browser workflow changes, browser evidence is expected when
1299
+ a local target can run:
1300
+
1301
+ - Open the relevant route or story with the available browser tooling.
1302
+ - Exercise the main changed workflow, not only page load.
1303
+ - Check desktop and mobile breakpoints when responsive behavior is in scope.
1304
+ - Capture screenshots or describe the viewport, route, steps, and observed
1305
+ result.
1306
+ - Inspect visible error states, empty states, long labels, focus behavior, and
1307
+ console or network failures when the tooling exposes them.
1308
+
1309
+ Browser claims are evidence requirements, not guaranteed coverage. If browser
1310
+ tooling, credentials, seed data, or a local server is unavailable, record the
1311
+ gap and provide the next-best evidence such as component tests, build output, or
1312
+ static inspection.
1313
+
1314
+ Exploratory QA should be scenario-based. Name the user path, the state varied,
1315
+ and the expected outcome. Do not replace automated evidence with exploratory QA
1316
+ when a practical automated check exists.
1317
+
1318
+ ## Output
1319
+
1320
+ Return a concise validation summary and a \`validationRun\` array that the manager
1321
+ can record through \`flow_feature_complete\` if it accepts the evidence:
1322
+
1323
+ \`\`\`json
1324
+ {
1325
+ "validationRun": [
1326
+ {
1327
+ "command": "bun test tests/foo.test.ts",
1328
+ "status": "passed",
1329
+ "summary": "3 pass; covered foo creation, duplicate rejection, and reset behavior"
1330
+ }
1331
+ ],
1332
+ "testSummary": "Targeted behavior and package shape passed. Browser evidence was not applicable.",
1333
+ "gaps": []
1334
+ }
1335
+ \`\`\`
1336
+
1337
+ Only passing checks belong in \`validationRun\` for completion. Failed, skipped,
1338
+ or unavailable checks belong in \`testSummary\`, \`gaps\`, or a blocker outcome.
1339
+ Each summary must state what behavior, file set, route, command, or state was
1340
+ covered. Static inspection alone is a gap for behavioral changes.
1341
+
1342
+ Never relabel a failed command as passed, invent output, or use "not run" as
1343
+ completion evidence.
1344
+ `;var Z=`# UI quality rubric
1083
1345
 
1084
1346
  Use this rubric for frontend planning, implementation, and review.
1085
1347
 
@@ -1123,7 +1385,7 @@ class; severity; location or screenshot area; evidence inspected; user impact; f
1123
1385
  \`\`\`
1124
1386
 
1125
1387
  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.
1126
- `;var Z=`# Visual verification workflow
1388
+ `;var H=`# Visual verification workflow
1127
1389
 
1128
1390
  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.
1129
1391
 
@@ -1163,9 +1425,9 @@ Record the reason and use the strongest available substitute:
1163
1425
  - code inspection against existing component patterns.
1164
1426
 
1165
1427
  Do not claim visual polish was verified if no visual artifact was inspected.
1166
- `;var Q=`---
1428
+ `;var ee=`---
1167
1429
  name: flow-ui-quality
1168
- description: Flow guidance for UX/UI design, frontend polish, visual quality review, responsive and accessible interfaces, and avoiding generic AI-generated UI. Use when planning, executing, or reviewing frontend pages, components, dashboards, visual redesigns, interaction states, screenshots, or browser-verified UI work.
1430
+ 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, screenshots, browser-verified UI work, and avoiding generic AI-generated UI.
1169
1431
  ---
1170
1432
 
1171
1433
  # Flow UI quality
@@ -1191,6 +1453,9 @@ Use this skill when Flow work changes what a user sees or how they interact with
1191
1453
  ## Verify visually
1192
1454
 
1193
1455
  - For meaningful UI changes, run the app and capture screenshots when a local browser target is available.
1456
+ - For browser-driven QA, route selection, failure classification, and
1457
+ \`validationRun\` summaries, load \`flow-test\`. Keep visual judgment, design
1458
+ quality, and screenshot assessment in \`flow-ui-quality\`.
1194
1459
  - Check desktop and mobile breakpoints, not only the viewport you developed in.
1195
1460
  - Verify text does not overlap, truncate unintentionally, or escape controls; long labels and empty/error states must fit.
1196
1461
  - Compare against provided screenshots, design references, or the stated product intent. List meaningful differences and fix the ones that violate the goal.
@@ -1208,16 +1473,16 @@ Approve only when the interface is both useful and inspectable:
1208
1473
  - Screenshot/browser evidence supports the claim whenever feasible.
1209
1474
 
1210
1475
  Never approve a UI change based only on code shape. If users will judge it visually, Flow evidence should include visual inspection.
1211
- `;var w=[{name:"flow",files:[{relativePath:"SKILL.md",content:B},{relativePath:"references/recovery-playbook.md",content:O},{relativePath:"references/parallel-orchestration.md",content:W},{relativePath:"references/handoff-format.md",content:j},{relativePath:"references/verification-gates.md",content:z}]},{name:"flow-plan",files:[{relativePath:"SKILL.md",content:M},{relativePath:"references/planning-examples.md",content:G},{relativePath:"references/parallel-discovery.md",content:S}]},{name:"flow-run",files:[{relativePath:"SKILL.md",content:Y},{relativePath:"references/validation-rubric.md",content:X},{relativePath:"references/audit-rubric.md",content:K}]},{name:"flow-review",files:[{relativePath:"SKILL.md",content:$},{relativePath:"references/review-rubric.md",content:L}]},{name:"flow-deslop",files:[{relativePath:"SKILL.md",content:E},{relativePath:"references/smell-rubric.md",content:V},{relativePath:"references/refactor-workflow.md",content:N}]},{name:"flow-ui-quality",files:[{relativePath:"SKILL.md",content:Q},{relativePath:"references/ui-rubric.md",content:J},{relativePath:"references/visual-verification.md",content:Z}]}];var U=".flow-skill-version";function x(){return process.env.HOME??process.env.USERPROFILE??""}function q(e=x()){return l(e,".config","opencode","skills")}function _(e){return Fe("sha256").update(e).digest("hex")}function b(e,a){return[`version=${a}`,...e.files.map((t)=>`file=${t.relativePath} sha256=${_(t.content)}`),""].join(`
1212
- `)}async function f(e){try{return await Ue(e,"utf8")}catch(a){if(a.code==="ENOENT")return null;throw a}}function A(e){let a=new Map;if(!e)return a;for(let t of e.split(/\r?\n/)){let r=/^file=(.+) sha256=([a-f0-9]{64})$/.exec(t)??/^file=(.+)=sha256:([a-f0-9]{64})$/.exec(t);if(r?.[1]&&r[2])a.set(r[1],r[2]);let n=/^hash=sha256:([a-f0-9]{64})$/.exec(t);if(n?.[1]&&!a.has("SKILL.md"))a.set("SKILL.md",n[1])}return a}function je(e){if(!e)return null;for(let a of e.split(/\r?\n/)){let t=/^version=(.+)$/.exec(a);if(t?.[1])return t[1]}return null}function k(e,a){let t=Pe(l(e,...a.split("/")));if(t!==e&&t.startsWith(`${e}${De}`))return t;throw Error(`Unsafe skill file path '${a}'.`)}async function We(e,a,t){let r=l(t,e.name),n=l(r,U),s=await f(n),d=A(s);if(await f(l(r,"SKILL.md"))!==null&&s===null)return{name:e.name,action:"skipped_foreign"};let p=!1,m=!1;for(let o of e.files){let i=k(r,o.relativePath),u=await f(i);if(u===o.content)continue;p=!0;let v=d.get(o.relativePath);if(u!==null&&(v?_(u)!==v:s!==null))await y(`${i}.backup`,u,"utf8"),m=!0}if(!p&&s===b(e,a))return{name:e.name,action:"unchanged"};if(!p)return await y(n,b(e,a),"utf8"),{name:e.name,action:"marker_updated"};let g=s!==null;for(let o of e.files){let i=k(r,o.relativePath);await Ce(Te(i),{recursive:!0}),await y(i,o.content,"utf8")}return await y(n,b(e,a),"utf8"),{name:e.name,action:m?"updated_with_backup":g?"updated":"installed"}}function Oe(){return w.map((e)=>e.name)}function ze(e){return`npx -y opencode-plugin-flow@${e} doctor`}function T(){if(process.env.npm_package_version)return process.env.npm_package_version;try{let e=Ae(import.meta.url);for(let a of["../package.json","../../package.json"])try{let t=e(a);if(t.version)return t.version}catch{}}catch{}return"0.0.0"}async function ae(e,a=x()){let t=q(a);return Promise.all(w.map((r)=>We(r,e,t)))}async function te(e=T(),a=x()){let t=q(a),r=new Set(Oe()),n=await Promise.all(w.map(async(o)=>{let i=l(t,o.name),u=await f(l(i,U)),v=je(u),P=A(u);if(await f(l(i,"SKILL.md"))===null)return{name:o.name,path:i,status:"missing",markerVersion:v,missingFiles:o.files.map((h)=>h.relativePath),editedFiles:[],outdatedFiles:[]};if(u===null)return{name:o.name,path:i,status:"foreign",markerVersion:v,missingFiles:[],editedFiles:[],outdatedFiles:[]};let I=[],R=[],F=[];for(let h of o.files){let C=await f(k(i,h.relativePath));if(C===null){I.push(h.relativePath);continue}if(C===h.content)continue;let D=P.get(h.relativePath);if(D&&_(C)!==D){R.push(h.relativePath);continue}F.push(h.relativePath)}let ne=u!==b(o,e),se=I.length>0?"incomplete":R.length>0?"edited":ne||F.length>0?"outdated":"ok";return{name:o.name,path:i,status:se,markerVersion:v,missingFiles:I,editedFiles:R,outdatedFiles:F}})),s=[];try{s=await ee(t)}catch(o){if(o.code!=="ENOENT")throw o}let d=s.filter((o)=>(o==="flow"||o.startsWith("flow-"))&&!r.has(o)).map((o)=>l(t,o)),c=n.filter((o)=>["missing","incomplete","outdated"].includes(o.status)).map((o)=>o.name),p=n.filter((o)=>["foreign","edited"].includes(o.status)).map((o)=>o.name),m=p.length>0,g=c.length>0;return{status:m?"action_required":g?"sync_required":"ok",version:e,root:t,expectedSkills:[...r],skills:n,syncRequiredSkills:c,actionRequiredSkills:p,unmanagedFlowSkills:d}}function H(e,a,t){if(t.length===0)return;e.push(`- ${a}: ${t.join(", ")}`)}function oe(e){let a=["Flow doctor",`- status: ${e.status}`,`- plugin version: ${e.version}`,`- skills root: ${e.root}`,`- expected skills: ${e.expectedSkills.join(", ")}`];H(a,"startup sync can install/update",e.syncRequiredSkills),H(a,"needs user decision",e.actionRequiredSkills),a.push("","Skills:");for(let t of e.skills){if(a.push(`- ${t.name}: ${t.status} (${t.path})${t.markerVersion?` marker=${t.markerVersion}`:""}`),t.missingFiles.length>0)a.push(` missing: ${t.missingFiles.join(", ")}`);if(t.editedFiles.length>0)a.push(` edited: ${t.editedFiles.join(", ")}`);if(t.outdatedFiles.length>0)a.push(` outdated: ${t.outdatedFiles.join(", ")}`)}if(e.unmanagedFlowSkills.length>0){a.push("","Unmanaged Flow-like skill folders:");for(let t of e.unmanagedFlowSkills)a.push(`- ${t}`)}if(a.push("","Recommendation:"),e.status==="ok")a.push("- Flow skills are present and current.");else if(e.status==="sync_required")a.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.");else a.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.");return a.push(`- Details command: ${ze(e.version)}`),`${a.join(`
1476
+ `;var w=[{name:"flow",files:[{relativePath:"SKILL.md",content:z},{relativePath:"references/recovery-playbook.md",content:W},{relativePath:"references/parallel-orchestration.md",content:B},{relativePath:"references/handoff-format.md",content:j},{relativePath:"references/verification-gates.md",content:S}]},{name:"flow-plan",files:[{relativePath:"SKILL.md",content:M},{relativePath:"references/planning-examples.md",content:L},{relativePath:"references/parallel-discovery.md",content:G}]},{name:"flow-run",files:[{relativePath:"SKILL.md",content:Y},{relativePath:"references/validation-rubric.md",content:X},{relativePath:"references/audit-rubric.md",content:Q}]},{name:"flow-test",files:[{relativePath:"SKILL.md",content:J}]},{name:"flow-review",files:[{relativePath:"SKILL.md",content:$},{relativePath:"references/review-rubric.md",content:K}]},{name:"flow-deslop",files:[{relativePath:"SKILL.md",content:V},{relativePath:"references/smell-rubric.md",content:N},{relativePath:"references/refactor-workflow.md",content:E}]},{name:"flow-ui-quality",files:[{relativePath:"SKILL.md",content:ee},{relativePath:"references/ui-rubric.md",content:Z},{relativePath:"references/visual-verification.md",content:H}]},{name:"flow-commit",files:[{relativePath:"SKILL.md",content:O}]}];var C=".flow-skill-version";function x(){return process.env.HOME??process.env.USERPROFILE??""}function A(e=x()){return l(e,".config","opencode","skills")}function _(e){return qe("sha256").update(e).digest("hex")}function b(e,a){return[`version=${a}`,...e.files.map((t)=>`file=${t.relativePath} sha256=${_(t.content)}`),""].join(`
1477
+ `)}async function f(e){try{return await Te(e,"utf8")}catch(a){if(a.code==="ENOENT")return null;throw a}}function q(e){let a=new Map;if(!e)return a;for(let t of e.split(/\r?\n/)){let r=/^file=(.+) sha256=([a-f0-9]{64})$/.exec(t)??/^file=(.+)=sha256:([a-f0-9]{64})$/.exec(t);if(r?.[1]&&r[2])a.set(r[1],r[2]);let s=/^hash=sha256:([a-f0-9]{64})$/.exec(t);if(s?.[1]&&!a.has("SKILL.md"))a.set("SKILL.md",s[1])}return a}function ze(e){if(!e)return null;for(let a of e.split(/\r?\n/)){let t=/^version=(.+)$/.exec(a);if(t?.[1])return t[1]}return null}function k(e,a){let t=We(l(e,...a.split("/")));if(t!==e&&t.startsWith(`${e}${Se}`))return t;throw Error(`Unsafe skill file path '${a}'.`)}async function Oe(e,a,t){let r=l(t,e.name),s=l(r,C),n=await f(s),d=q(n);if(await f(l(r,"SKILL.md"))!==null&&n===null)return{name:e.name,action:"skipped_foreign"};let p=!1,m=!1;for(let o of e.files){let i=k(r,o.relativePath),u=await f(i);if(u===o.content)continue;p=!0;let v=d.get(o.relativePath);if(u!==null&&(v?_(u)!==v:n!==null))await y(`${i}.backup`,u,"utf8"),m=!0}if(!p&&n===b(e,a))return{name:e.name,action:"unchanged"};if(!p)return await y(s,b(e,a),"utf8"),{name:e.name,action:"marker_updated"};let g=n!==null;for(let o of e.files){let i=k(r,o.relativePath);await Pe(Be(i),{recursive:!0}),await y(i,o.content,"utf8")}return await y(s,b(e,a),"utf8"),{name:e.name,action:m?"updated_with_backup":g?"updated":"installed"}}function Ee(){return w.map((e)=>e.name)}function Ne(e){return`npx -y opencode-plugin-flow@${e} doctor`}function P(){if(process.env.npm_package_version)return process.env.npm_package_version;try{let e=je(import.meta.url);for(let a of["../package.json","../../package.json"])try{let t=e(a);if(t.version)return t.version}catch{}}catch{}return"0.0.0"}async function oe(e,a=x()){let t=A(a);return Promise.all(w.map((r)=>Oe(r,e,t)))}async function re(e=P(),a=x()){let t=A(a),r=new Set(Ee()),s=await Promise.all(w.map(async(o)=>{let i=l(t,o.name),u=await f(l(i,C)),v=ze(u),T=q(u);if(await f(l(i,"SKILL.md"))===null)return{name:o.name,path:i,status:"missing",markerVersion:v,missingFiles:o.files.map((h)=>h.relativePath),editedFiles:[],outdatedFiles:[]};if(u===null)return{name:o.name,path:i,status:"foreign",markerVersion:v,missingFiles:[],editedFiles:[],outdatedFiles:[]};let I=[],R=[],F=[];for(let h of o.files){let U=await f(k(i,h.relativePath));if(U===null){I.push(h.relativePath);continue}if(U===h.content)continue;let D=T.get(h.relativePath);if(D&&_(U)!==D){R.push(h.relativePath);continue}F.push(h.relativePath)}let ie=u!==b(o,e),ce=I.length>0?"incomplete":R.length>0?"edited":ie||F.length>0?"outdated":"ok";return{name:o.name,path:i,status:ce,markerVersion:v,missingFiles:I,editedFiles:R,outdatedFiles:F}})),n=[];try{n=await te(t)}catch(o){if(o.code!=="ENOENT")throw o}let d=n.filter((o)=>(o==="flow"||o.startsWith("flow-"))&&!r.has(o)).map((o)=>l(t,o)),c=s.filter((o)=>["missing","incomplete","outdated"].includes(o.status)).map((o)=>o.name),p=s.filter((o)=>["foreign","edited"].includes(o.status)).map((o)=>o.name),m=p.length>0,g=c.length>0;return{status:m?"action_required":g?"sync_required":"ok",version:e,root:t,expectedSkills:[...r],skills:s,syncRequiredSkills:c,actionRequiredSkills:p,unmanagedFlowSkills:d}}function ae(e,a,t){if(t.length===0)return;e.push(`- ${a}: ${t.join(", ")}`)}function se(e){let a=["Flow doctor",`- status: ${e.status}`,`- plugin version: ${e.version}`,`- skills root: ${e.root}`,`- expected skills: ${e.expectedSkills.join(", ")}`];ae(a,"startup sync can install/update",e.syncRequiredSkills),ae(a,"needs user decision",e.actionRequiredSkills),a.push("","Skills:");for(let t of e.skills){if(a.push(`- ${t.name}: ${t.status} (${t.path})${t.markerVersion?` marker=${t.markerVersion}`:""}`),t.missingFiles.length>0)a.push(` missing: ${t.missingFiles.join(", ")}`);if(t.editedFiles.length>0)a.push(` edited: ${t.editedFiles.join(", ")}`);if(t.outdatedFiles.length>0)a.push(` outdated: ${t.outdatedFiles.join(", ")}`)}if(e.unmanagedFlowSkills.length>0){a.push("","Unmanaged Flow-like skill folders:");for(let t of e.unmanagedFlowSkills)a.push(`- ${t}`)}if(a.push("","Recommendation:"),e.status==="ok")a.push("- Flow skills are present and current.");else if(e.status==="sync_required")a.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.");else a.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.");return a.push(`- Details command: ${Ne(e.version)}`),`${a.join(`
1213
1478
  `)}
1214
- `}async function re(e=x()){let a=q(e),t=[],r=[],n;try{n=await ee(a)}catch(s){if(s.code==="ENOENT")return{removed:t,kept:r};throw s}for(let s of n){if(s!=="flow"&&!s.startsWith("flow-"))continue;let d=l(a,s),c=await f(l(d,U));if(c===null){r.push(d);continue}let p=A(c),m=!1;for(let[g,o]of p){let i=await f(k(d,g));if(i!==null&&_(i)!==o){m=!0;break}}if(m){r.push(d);continue}await qe(d,{recursive:!0,force:!0}),t.push(d)}return{removed:t,kept:r}}async function Be(e){let a=e[2];if(a!=="uninstall"&&a!=="doctor"&&a!=="sync"){process.stderr.write(`usage: opencode-plugin-flow <doctor|sync|uninstall>
1215
- `),process.exitCode=2;return}if(a==="doctor"){process.stdout.write(oe(await te()));return}if(a==="sync"){let r=T(),n=await ae(r),s=n.filter((c)=>["installed","updated","updated_with_backup"].includes(c.action)),d=n.filter((c)=>c.action==="skipped_foreign");process.stdout.write(`Flow skill sync (${r})
1216
- `);for(let c of n)process.stdout.write(`- ${c.name}: ${c.action}
1217
- `);if(s.length>0)process.stdout.write(`Restart OpenCode so the refreshed skill registry is used.
1479
+ `}async function ne(e=x()){let a=A(e),t=[],r=[],s;try{s=await te(a)}catch(n){if(n.code==="ENOENT")return{removed:t,kept:r};throw n}for(let n of s){if(n!=="flow"&&!n.startsWith("flow-"))continue;let d=l(a,n),c=await f(l(d,C));if(c===null){r.push(d);continue}let p=q(c),m=!1;for(let[g,o]of p){let i=await f(k(d,g));if(i!==null&&_(i)!==o){m=!0;break}}if(m){r.push(d);continue}await De(d,{recursive:!0,force:!0}),t.push(d)}return{removed:t,kept:r}}async function Ve(e){let a=e[2];if(a!=="uninstall"&&a!=="doctor"&&a!=="sync"){process.stderr.write(`usage: opencode-plugin-flow <doctor|sync|uninstall>
1480
+ `),process.exitCode=2;return}if(a==="doctor"){process.stdout.write(se(await re()));return}if(a==="sync"){let r=P(),s=await oe(r),n=s.filter((c)=>["installed","updated","updated_with_backup"].includes(c.action)),d=s.filter((c)=>c.action==="skipped_foreign");process.stdout.write(`Flow skill sync (${r})
1481
+ `);for(let c of s)process.stdout.write(`- ${c.name}: ${c.action}
1482
+ `);if(n.length>0)process.stdout.write(`Restart OpenCode so the refreshed skill registry is used.
1218
1483
  `);if(d.length>0)process.stdout.write(`Some managed skill folders are user-owned or edited; run doctor for repair guidance.
1219
- `);return}let t=await re();for(let r of t.removed)process.stdout.write(`Removed Flow skill: ${r}
1484
+ `);return}let t=await ne();for(let r of t.removed)process.stdout.write(`Removed Flow skill: ${r}
1220
1485
  `);for(let r of t.kept)process.stdout.write(`Kept non-Flow or user-edited skill: ${r}
1221
1486
  `);process.stdout.write(`Remove opencode-plugin-flow from your OpenCode plugin config and restart OpenCode.
1222
- `)}Be(process.argv).catch((e)=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}
1487
+ `)}Ve(process.argv).catch((e)=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}
1223
1488
  `),process.exitCode=1});