opencode-plugin-flow 4.1.4 → 4.1.5

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 CHANGED
@@ -3,6 +3,10 @@
3
3
  One short line per release. For the full rationale behind each entry, see the
4
4
  commit history and review evidence.
5
5
 
6
+ ## [4.1.5] - 2026-06-16
7
+
8
+ Make Flow installation follow OpenCode's native plugin installer, with pre-start skill sync and older-version fallback.
9
+
6
10
  ## [4.1.4] - 2026-06-16
7
11
 
8
12
  Make Flow skill loading restart-aware across every command, add manual sync repair, and treat missing optional helpers as explicit coverage gaps.
package/README.md CHANGED
@@ -16,15 +16,19 @@ The manager still owns every Flow state change. Workers gather evidence; they do
16
16
 
17
17
  ## Install
18
18
 
19
- Add Flow to your OpenCode config:
19
+ Use OpenCode's plugin installer when your OpenCode version supports it:
20
20
 
21
- ```json
22
- {
23
- "plugin": ["opencode-plugin-flow@4.1.4"]
24
- }
21
+ ```bash
22
+ opencode plugin opencode-plugin-flow@4.1.5 --global
23
+ npx -y opencode-plugin-flow@4.1.5 sync
25
24
  ```
26
25
 
27
- Restart OpenCode once. On startup, the plugin syncs its global skills into:
26
+ The first command adds Flow to your global OpenCode plugin config. The `sync`
27
+ command pre-installs Flow's managed skills so the next OpenCode startup can load
28
+ the refreshed skill registry.
29
+
30
+ Then start or restart OpenCode. On startup, the plugin syncs its global skills
31
+ into:
28
32
 
29
33
  ```text
30
34
  ~/.config/opencode/skills/flow/SKILL.md
@@ -35,6 +39,21 @@ Restart OpenCode once. On startup, the plugin syncs its global skills into:
35
39
  ~/.config/opencode/skills/flow-ui-quality/SKILL.md
36
40
  ```
37
41
 
42
+ If your OpenCode version does not have `opencode plugin`, add Flow to your
43
+ OpenCode config manually instead:
44
+
45
+ ```json
46
+ {
47
+ "plugin": ["opencode-plugin-flow@4.1.5"]
48
+ }
49
+ ```
50
+
51
+ Then run the same pre-start skill sync and start or restart OpenCode:
52
+
53
+ ```bash
54
+ npx -y opencode-plugin-flow@4.1.5 sync
55
+ ```
56
+
38
57
  Project-local skill overrides still work through OpenCode's normal lookup:
39
58
 
40
59
  ```text
@@ -47,10 +66,18 @@ the skill registry for the running process, so a just-synced skill can exist on
47
66
  disk while still being unavailable to that process. Flow reports this through
48
67
  `flow_status` as `setup.skills.status: "restart_required"`.
49
68
 
69
+ To update a pinned Flow version, replace the existing OpenCode plugin entry and
70
+ sync the matching skill bundle:
71
+
72
+ ```bash
73
+ opencode plugin opencode-plugin-flow@4.1.5 --global --force
74
+ npx -y opencode-plugin-flow@4.1.5 sync
75
+ ```
76
+
50
77
  To inspect the installed skill set:
51
78
 
52
79
  ```bash
53
- npx -y opencode-plugin-flow@4.1.4 doctor
80
+ npx -y opencode-plugin-flow@4.1.5 doctor
54
81
  ```
55
82
 
56
83
  If a command reports `Skill "flow-review" not found. Available skills...` or a
@@ -58,7 +85,7 @@ similar Flow skill-loading error, run `/flow-status` or the doctor command above
58
85
  first. Missing, incomplete, or outdated managed skills can be repaired with:
59
86
 
60
87
  ```bash
61
- npx -y opencode-plugin-flow@4.1.4 sync
88
+ npx -y opencode-plugin-flow@4.1.5 sync
62
89
  ```
63
90
 
64
91
  Then restart OpenCode so the refreshed registry is loaded. `sync` manages all
@@ -146,8 +173,12 @@ The Flow version is its own OpenCode-native design: skills-first, manager-owned
146
173
 
147
174
  ## Uninstall
148
175
 
176
+ First remove `opencode-plugin-flow` from your OpenCode plugin config so future
177
+ OpenCode startups stop loading Flow. Then remove Flow-owned synced skills:
178
+
149
179
  ```bash
150
- bunx opencode-plugin-flow uninstall
180
+ npx -y opencode-plugin-flow@4.1.5 uninstall
151
181
  ```
152
182
 
153
- This removes Flow-owned synced skills when they are pristine. User-edited or foreign skill folders are kept.
183
+ Restart OpenCode after both steps. This removes Flow-owned synced skills when
184
+ they are pristine. User-edited or foreign skill folders are kept.
package/dist/cli.js CHANGED
@@ -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 z='# 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 O=`# Verification gates
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
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
@@ -1208,8 +1208,8 @@ Approve only when the interface is both useful and inspectable:
1208
1208
  - Screenshot/browser evidence supports the claim whenever feasible.
1209
1209
 
1210
1210
  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:z},{relativePath:"references/parallel-orchestration.md",content:W},{relativePath:"references/handoff-format.md",content:j},{relativePath:"references/verification-gates.md",content:O}]},{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 ze(){return w.map((e)=>e.name)}function Oe(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(ze()),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: ${Oe(e.version)}`),`${a.join(`
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(`
1213
1213
  `)}
1214
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
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})
@@ -1218,6 +1218,6 @@ Never approve a UI change based only on code shape. If users will judge it visua
1218
1218
  `);if(d.length>0)process.stdout.write(`Some managed skill folders are user-owned or edited; run doctor for repair guidance.
1219
1219
  `);return}let t=await re();for(let r of t.removed)process.stdout.write(`Removed Flow skill: ${r}
1220
1220
  `);for(let r of t.kept)process.stdout.write(`Kept non-Flow or user-edited skill: ${r}
1221
- `);process.stdout.write(`Remove "opencode-plugin-flow" from opencode.json and restart OpenCode.
1221
+ `);process.stdout.write(`Remove opencode-plugin-flow from your OpenCode plugin config and restart OpenCode.
1222
1222
  `)}Be(process.argv).catch((e)=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}
1223
1223
  `),process.exitCode=1});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-plugin-flow",
3
- "version": "4.1.4",
3
+ "version": "4.1.5",
4
4
  "description": "Stateful planning and execution workflow plugin for OpenCode",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",