opencode-plugin-flow 3.3.9 → 3.3.10

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
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.3.10] - 2026-06-14
6
+
7
+ Teach Flow to fan out discovery without making execution parallel
8
+
9
+ Flow's planning and review skills already ask for strong context, but broad audits and research-heavy goals still pushed one agent through every module, risk lens, or API stream serially. That made good context expensive, and it left no Flow-native guidance for borrowing host subagents safely when the work naturally splits into independent read-only slices.
10
+
11
+ This release adds a parallel discovery reference to the planning skill. It teaches the manager agent to profile the repository first, split only independent read-only discovery slices, require structured worker handoffs, and synthesize the evidence into existing Flow fields such as `planning.research`, `planning.reviewFindings`, requirements, architecture decisions, feature targets, review scopes, and notes. The review skill can use the same pattern for very large reviews while keeping severity, deduplication, refutation, and `flow_review_record` in the main reviewer. The run skill now states the boundary explicitly: parallel discovery may inform a feature, but Flow execution remains one active feature at a time.
12
+
13
+ The release intentionally keeps the runtime small. No commands, tools, agents, state paths, persisted schemas, runtime transitions, completion gates, review policy defaults, validation strictness, package exports, public payloads, or Flow-owned subagent roles changed. The only code change is distribution sync registration so the new reference file ships and updates like the existing skill references.
14
+
15
+ Constraint: Allow broad planning and review discovery to use host-native parallel workers without making Flow's state machine parallel
16
+ Constraint: Preserve existing context-pack fields instead of adding worker result state or a new runtime payload
17
+ Rejected: Add a dedicated `/flow-discover` command or new tool | the pattern is judgment-heavy guidance, and the existing skills already own planning and review orchestration
18
+ Rejected: Let workers call state-changing Flow tools | the manager must remain the single owner of plan, review, execution, and session mutations
19
+ Confidence: high
20
+ Scope-risk: low
21
+ Reversibility: clean - the reference file, skill wording, sync registration, docs, and release metadata can be reverted without migrating sessions
22
+ Directive: Use parallel discovery only for independent read-only planning or review slices; synthesize worker handoffs before saving Flow state, then execute one active feature at a time
23
+ Tested: `bun run check` (typecheck, lint, build, full test suite, architecture seam enforcement, npm-tarball install smoke asserting the 3.3.10 README pin, bundle sanity); `bun run smoke:release` (packed candidate tarball retained under release-smoke evidence, install smoke run against that tarball, manual live OpenCode checklist generated with the retained tarball install spec); focused skill sync/config tests; `bun run lint`; `.agents/skills/flow-contribution-check/scripts/preflight.sh commit`; `.agents/skills/flow-contribution-check/scripts/preflight.sh push`
24
+ Not-tested: Live OpenCode UI restart against the release candidate; this release changes skill guidance, synced reference content, maintainer docs, and release metadata only.
25
+
5
26
  ## [3.3.9] - 2026-06-14
6
27
 
7
28
  Make context handoff inspectable without bloating session docs
package/README.md CHANGED
@@ -31,7 +31,7 @@ Add Flow to the `plugin` array in your `opencode.json` (global `~/.config/openco
31
31
 
32
32
  ```json
33
33
  {
34
- "plugin": ["opencode-plugin-flow@3.3.9"]
34
+ "plugin": ["opencode-plugin-flow@3.3.10"]
35
35
  }
36
36
  ```
37
37
 
package/dist/cli.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import{homedir as he}from"node:os";import{readdir as ie,readFile as ae,rm as h,rmdir as se}from"node:fs/promises";import{dirname as oe,join as c,normalize as ne,sep as re}from"node:path";var J={fast:"low",balanced:"medium",deep:"high"},j={"flow-reviewer":{mode:"all",description:"Review Flow work read-only and record a reviewer decision.",prompt:"You are the Flow reviewer. Load the `flow-review` skill, review the requested work read-only, then record your decision with flow_review_record.",reasoningEffort:J.deep,permission:{edit:"deny",bash:"deny",task:{"*":"deny"},"flow_*":"deny",flow_status:"allow",flow_review_record:"allow"}}},W={"flow-plan":{description:"Create, update, or approve a Flow plan",template:"Load the `flow-plan` skill and plan: $ARGUMENTS"},"flow-run":{description:"Run one approved Flow feature",template:"Load the `flow-run` skill and execute the next approved Flow feature. $ARGUMENTS"},"flow-auto":{description:"Drive the Flow loop autonomously until completion or a real blocker",template:"Load the `flow` skill and drive the Flow loop (status, plan, run, review) until completion or a real blocker: $ARGUMENTS"},"flow-status":{description:"Inspect the active Flow session and workspace readiness",template:"Call flow_status (detailed) and report session state, readiness checks, and the suggested next step."},"flow-review":{description:"Run a read-only Flow review with a fresh context",agent:"flow-reviewer",subtask:!0,template:"Load the `flow-review` skill and review: $ARGUMENTS"}},k=["flow-doctor","flow-history","flow-reset","flow-session"];import{createHash as Z}from"node:crypto";import{join as w}from"node:path";var x=w(".config","opencode","skills"),g=w(".config","opencode","commands"),_=w(".config","opencode","agents"),v=".flow-skill-version",N="SKILL.md.backup",A=w(".config","opencode","plugins","flow.js"),R=`// Managed by flow-opencode install/uninstall
3
- `,E="flow-opencode-generated-skill",$=`<!-- ${E} `,K=new RegExp(`^<!-- ${E} name=([a-z0-9]+(?:-[a-z0-9]+)*) version=([0-9]+) hash=sha256:([a-f0-9]{64}) -->$`,"u");function p(e){return Z("sha256").update(e,"utf8").digest("hex")}function y(e){let t=e.split(`
4
- `),a=t.flatMap((u,H)=>u.startsWith($)?[H]:[]);if(a.length===0)return{kind:"not_generated"};if(a.length>1)return{kind:"invalid_generated",reason:"duplicate_marker"};let i=a[0];if(i===void 0)return{kind:"not_generated"};let s=t[i];if(s===void 0)return{kind:"invalid_generated",reason:"malformed_marker"};let o=s.match(K);if(!o)return{kind:"invalid_generated",reason:"malformed_marker"};let[,n,r,d]=o;if(n===void 0||r===void 0||d===void 0)return{kind:"invalid_generated",reason:"malformed_marker"};let l=[...t.slice(0,i),...t.slice(i+1)].join(`
5
- `);if(p(l)!==d)return{kind:"invalid_generated",reason:"hash_mismatch"};return{kind:"valid_generated",marker:{name:n,version:r,hash:d}}}var V="opencode-plugin-flow",O="file=",B="=sha256:";function m(e){let t=new Map;for(let a of e.split(`
6
- `)){if(!a.startsWith(O))continue;let i=a.slice(O.length),s=i.lastIndexOf(B);if(s===-1)continue;let o=i.slice(0,s),n=i.slice(s+B.length);if(o.length>0&&/^[a-f0-9]{64}$/.test(n))t.set(o,n)}return t}function b(e,t,a){let i=new Map;for(let n of e.split(`
7
- `)){let r=n.indexOf("=");if(r===-1)continue;i.set(n.slice(0,r),n.slice(r+1))}let s=i.get("version"),o=i.get("hash");if(i.get("plugin")!==V||i.get("kind")!==t||i.get("name")!==a||!s||!o?.startsWith("sha256:"))return null;return{kind:t,name:a,version:s,hash:o.slice(7)}}function T(e){let t=new Map;for(let o of e.split(`
8
- `)){let n=o.indexOf("=");if(n===-1)continue;t.set(o.slice(0,n),o.slice(n+1))}let a=t.get("plugin"),i=t.get("version");if(a!==V||!i)return null;let s=t.get("hash");return{plugin:a,version:i,hash:s?.startsWith("sha256:")?s.slice(7):null}}import{mkdir as Qe,readFile as D,rm as I,writeFile as Me}from"node:fs/promises";import{dirname as He,join as z,sep as Je}from"node:path";function P(e){return`${["---",`description: ${JSON.stringify(e.description)}`,...e.agent?[`agent: ${JSON.stringify(e.agent)}`]:[],...e.subtask===void 0?[]:[`subtask: ${e.subtask}`],"---"].join(`
2
+ import{homedir as he}from"node:os";import{readdir as ae,readFile as ie,rm as h,rmdir as se}from"node:fs/promises";import{dirname as oe,join as c,normalize as ne,sep as re}from"node:path";var J={fast:"low",balanced:"medium",deep:"high"},j={"flow-reviewer":{mode:"all",description:"Review Flow work read-only and record a reviewer decision.",prompt:"You are the Flow reviewer. Load the `flow-review` skill, review the requested work read-only, then record your decision with flow_review_record.",reasoningEffort:J.deep,permission:{edit:"deny",bash:"deny",task:{"*":"deny"},"flow_*":"deny",flow_status:"allow",flow_review_record:"allow"}}},W={"flow-plan":{description:"Create, update, or approve a Flow plan",template:"Load the `flow-plan` skill and plan: $ARGUMENTS"},"flow-run":{description:"Run one approved Flow feature",template:"Load the `flow-run` skill and execute the next approved Flow feature. $ARGUMENTS"},"flow-auto":{description:"Drive the Flow loop autonomously until completion or a real blocker",template:"Load the `flow` skill and drive the Flow loop (status, plan, run, review) until completion or a real blocker: $ARGUMENTS"},"flow-status":{description:"Inspect the active Flow session and workspace readiness",template:"Call flow_status (detailed) and report session state, readiness checks, and the suggested next step."},"flow-review":{description:"Run a read-only Flow review with a fresh context",agent:"flow-reviewer",subtask:!0,template:"Load the `flow-review` skill and review: $ARGUMENTS"}},k=["flow-doctor","flow-history","flow-reset","flow-session"];import{createHash as P}from"node:crypto";import{join as v}from"node:path";var x=v(".config","opencode","skills"),g=v(".config","opencode","commands"),_=v(".config","opencode","agents"),w=".flow-skill-version",N="SKILL.md.backup",R=v(".config","opencode","plugins","flow.js"),A=`// Managed by flow-opencode install/uninstall
3
+ `,E="flow-opencode-generated-skill",K=`<!-- ${E} `,Z=new RegExp(`^<!-- ${E} name=([a-z0-9]+(?:-[a-z0-9]+)*) version=([0-9]+) hash=sha256:([a-f0-9]{64}) -->$`,"u");function p(e){return P("sha256").update(e,"utf8").digest("hex")}function m(e){let t=e.split(`
4
+ `),i=t.flatMap((u,H)=>u.startsWith(K)?[H]:[]);if(i.length===0)return{kind:"not_generated"};if(i.length>1)return{kind:"invalid_generated",reason:"duplicate_marker"};let a=i[0];if(a===void 0)return{kind:"not_generated"};let s=t[a];if(s===void 0)return{kind:"invalid_generated",reason:"malformed_marker"};let o=s.match(Z);if(!o)return{kind:"invalid_generated",reason:"malformed_marker"};let[,n,r,d]=o;if(n===void 0||r===void 0||d===void 0)return{kind:"invalid_generated",reason:"malformed_marker"};let l=[...t.slice(0,a),...t.slice(a+1)].join(`
5
+ `);if(p(l)!==d)return{kind:"invalid_generated",reason:"hash_mismatch"};return{kind:"valid_generated",marker:{name:n,version:r,hash:d}}}var z="opencode-plugin-flow",O="file=",B="=sha256:";function y(e){let t=new Map;for(let i of e.split(`
6
+ `)){if(!i.startsWith(O))continue;let a=i.slice(O.length),s=a.lastIndexOf(B);if(s===-1)continue;let o=a.slice(0,s),n=a.slice(s+B.length);if(o.length>0&&/^[a-f0-9]{64}$/.test(n))t.set(o,n)}return t}function b(e,t,i){let a=new Map;for(let n of e.split(`
7
+ `)){let r=n.indexOf("=");if(r===-1)continue;a.set(n.slice(0,r),n.slice(r+1))}let s=a.get("version"),o=a.get("hash");if(a.get("plugin")!==z||a.get("kind")!==t||a.get("name")!==i||!s||!o?.startsWith("sha256:"))return null;return{kind:t,name:i,version:s,hash:o.slice(7)}}function T(e){let t=new Map;for(let o of e.split(`
8
+ `)){let n=o.indexOf("=");if(n===-1)continue;t.set(o.slice(0,n),o.slice(n+1))}let i=t.get("plugin"),a=t.get("version");if(i!==z||!a)return null;let s=t.get("hash");return{plugin:i,version:a,hash:s?.startsWith("sha256:")?s.slice(7):null}}import{mkdir as He,readFile as $,rm as F,writeFile as Je}from"node:fs/promises";import{dirname as Ke,join as U,sep as Ze}from"node:path";function D(e){return`${["---",`description: ${JSON.stringify(e.description)}`,...e.agent?[`agent: ${JSON.stringify(e.agent)}`]:[],...e.subtask===void 0?[]:[`subtask: ${e.subtask}`],"---"].join(`
9
9
  `)}
10
10
 
11
11
  ${e.template}
@@ -13,7 +13,7 @@ ${e.template}
13
13
  `)}
14
14
 
15
15
  ${e.prompt}
16
- `}function G(){return new Map(Object.entries(W).map(([e,t])=>[e,P(t)]))}function L(){return new Map(Object.entries(j).map(([e,t])=>[e,ee(t)]))}async function Y(e){let t=[],a=[];for(let i of e.names){let s=z(e.root,`${i}.md`),o=z(e.root,`.${i}.flow-version`),n=await U(o),r=n===null?null:b(n,e.kind,i);if(r===null)continue;let d=await U(s);if(d!==null&&p(d)!==r.hash){a.push(s);continue}if(!e.dryRun)await I(s,{force:!0}),await I(o,{force:!0}),await I(`${s}.backup`,{force:!0});t.push(s)}return{removed:t,keptUserEdited:a}}async function U(e){try{return await D(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}function te(e){if(!e)return[];let t=["permission:"];for(let[a,i]of Object.entries(e)){if(typeof i==="string"){t.push(` ${JSON.stringify(a)}: ${JSON.stringify(i)}`);continue}if(i&&typeof i==="object"){t.push(` ${JSON.stringify(a)}:`);for(let[s,o]of Object.entries(i))t.push(` ${JSON.stringify(s)}: ${JSON.stringify(o)}`)}}return t}async function Q({homeDir:e,dryRun:t=!1,logger:a}){let i={removedSkills:[],keptUserEditedSkills:[],removedCommands:[],keptUserEditedCommands:[],removedAgents:[],keptUserEditedAgents:[],removedPreNpmPlugin:null,keptForeignPreNpmPlugin:null},s=c(e,x);for(let d of await le(s)){if(d!=="flow"&&!d.startsWith("flow-"))continue;let l=c(s,d),u=await de(l);if(u==="foreign")continue;if(u==="user_edited"){i.keptUserEditedSkills.push(l),a?.(`Kept user-edited Flow skill at ${l}; remove it manually if it is no longer needed.`);continue}if(!t)await ce(l);i.removedSkills.push(l),a?.(`${t?"Would remove":"Removed"} Flow skill at ${l}.`)}let o=await Y({kind:"command",root:c(e,g),names:k,dryRun:t});for(let d of o.removed)i.removedCommands.push(d),a?.(`${t?"Would remove":"Removed"} retired Flow command at ${d}.`);for(let d of o.keptUserEdited)i.keptUserEditedCommands.push(d),a?.(`Kept user-edited Flow command at ${d}; remove it manually if it is no longer needed.`);await C({homeDir:e,dryRun:t,logger:a,kind:"command",root:c(e,g),files:G(),removed:i.removedCommands,keptUserEdited:i.keptUserEditedCommands}),await C({homeDir:e,dryRun:t,logger:a,kind:"agent",root:c(e,_),files:L(),removed:i.removedAgents,keptUserEdited:i.keptUserEditedAgents});let n=c(e,A),r=await f(n);if(r!==null)if(r.startsWith(R)){if(!t)await h(n,{force:!0});i.removedPreNpmPlugin=n,a?.(`${t?"Would remove":"Removed"} pre-npm Flow plugin copy at ${n}.`)}else i.keptForeignPreNpmPlugin=n,a?.(`Kept ${n}: it is not managed by Flow. Remove it manually if it is a stale Flow copy.`);return a?.('Finally, remove "opencode-plugin-flow" from the plugin array in opencode.json and restart OpenCode.'),i}async function de(e){let t=c(e,"SKILL.md"),a=await f(t),i=await f(c(e,v)),s=i===null?null:T(i);if(s!==null&&i!==null){for(let[r,d]of m(i)){if(r==="SKILL.md")continue;let l=M(e,r);if(l===null)continue;let u=await f(l);if(u!==null&&p(u)!==d)return"user_edited"}if(a===null)return"pristine";if(s.hash!==null&&p(a)===s.hash)return"pristine";return y(a).kind==="valid_generated"?"pristine":"user_edited"}if(a===null)return"foreign";let o=y(a);if(o.kind==="valid_generated")return"pristine";if(o.kind==="invalid_generated")return"user_edited";return"foreign"}function M(e,t){let a=ne(c(e,...t.split("/")));if(a!==e&&a.startsWith(`${e}${re}`))return a;return null}async function ce(e){let t=await f(c(e,v)),a=new Set;if(t!==null)for(let i of m(t).keys()){let s=M(e,i);if(s===null)continue;await h(s,{force:!0}),await h(`${s}.backup`,{force:!0});let o=oe(s);if(o!==e)a.add(o)}await h(c(e,"SKILL.md"),{force:!0}),await h(c(e,v),{force:!0}),await h(c(e,N),{force:!0});for(let i of[...a].sort((s,o)=>o.length-s.length))await q(i);await q(e)}async function q(e){try{await se(e)}catch(t){let a=t.code;if(a!=="ENOENT"&&a!=="ENOTEMPTY")throw t}}async function le(e){try{return(await ie(e,{withFileTypes:!0})).filter((a)=>a.isDirectory()).map((a)=>a.name).sort()}catch(t){if(t.code==="ENOENT")return[];throw t}}async function f(e){try{return await ae(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}async function C(e){for(let[t,a]of e.files){let i=c(e.root,`${t}.md`),s=c(e.root,`.${t}.flow-version`),o=await f(i),n=await f(s),r=n===null?null:b(n,e.kind,t);if(o===null&&r===null)continue;if(!(r!==null||o===a))continue;if(o!==null&&r!==null&&p(o)!==r.hash){e.keptUserEdited.push(i),e.logger?.(`Kept user-edited Flow ${e.kind} at ${i}; remove it manually if it is no longer needed.`);continue}if(!e.dryRun)await h(i,{force:!0}),await h(s,{force:!0}),await h(`${i}.backup`,{force:!0});e.removed.push(i),e.logger?.(`${e.dryRun?"Would remove":"Removed"} Flow ${e.kind} at ${i}.`)}if(!e.dryRun)await q(e.root)}var F=`opencode-plugin-flow — Flow plugin lifecycle commands
16
+ `}function L(){return new Map(Object.entries(W).map(([e,t])=>[e,D(t)]))}function G(){return new Map(Object.entries(j).map(([e,t])=>[e,ee(t)]))}async function C(e){let t=[],i=[];for(let a of e.names){let s=U(e.root,`${a}.md`),o=U(e.root,`.${a}.flow-version`),n=await V(o),r=n===null?null:b(n,e.kind,a);if(r===null)continue;let d=await V(s);if(d!==null&&p(d)!==r.hash){i.push(s);continue}if(!e.dryRun)await F(s,{force:!0}),await F(o,{force:!0}),await F(`${s}.backup`,{force:!0});t.push(s)}return{removed:t,keptUserEdited:i}}async function V(e){try{return await $(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}function te(e){if(!e)return[];let t=["permission:"];for(let[i,a]of Object.entries(e)){if(typeof a==="string"){t.push(` ${JSON.stringify(i)}: ${JSON.stringify(a)}`);continue}if(a&&typeof a==="object"){t.push(` ${JSON.stringify(i)}:`);for(let[s,o]of Object.entries(a))t.push(` ${JSON.stringify(s)}: ${JSON.stringify(o)}`)}}return t}async function M({homeDir:e,dryRun:t=!1,logger:i}){let a={removedSkills:[],keptUserEditedSkills:[],removedCommands:[],keptUserEditedCommands:[],removedAgents:[],keptUserEditedAgents:[],removedPreNpmPlugin:null,keptForeignPreNpmPlugin:null},s=c(e,x);for(let d of await le(s)){if(d!=="flow"&&!d.startsWith("flow-"))continue;let l=c(s,d),u=await de(l);if(u==="foreign")continue;if(u==="user_edited"){a.keptUserEditedSkills.push(l),i?.(`Kept user-edited Flow skill at ${l}; remove it manually if it is no longer needed.`);continue}if(!t)await ce(l);a.removedSkills.push(l),i?.(`${t?"Would remove":"Removed"} Flow skill at ${l}.`)}let o=await C({kind:"command",root:c(e,g),names:k,dryRun:t});for(let d of o.removed)a.removedCommands.push(d),i?.(`${t?"Would remove":"Removed"} retired Flow command at ${d}.`);for(let d of o.keptUserEdited)a.keptUserEditedCommands.push(d),i?.(`Kept user-edited Flow command at ${d}; remove it manually if it is no longer needed.`);await Y({homeDir:e,dryRun:t,logger:i,kind:"command",root:c(e,g),files:L(),removed:a.removedCommands,keptUserEdited:a.keptUserEditedCommands}),await Y({homeDir:e,dryRun:t,logger:i,kind:"agent",root:c(e,_),files:G(),removed:a.removedAgents,keptUserEdited:a.keptUserEditedAgents});let n=c(e,R),r=await f(n);if(r!==null)if(r.startsWith(A)){if(!t)await h(n,{force:!0});a.removedPreNpmPlugin=n,i?.(`${t?"Would remove":"Removed"} pre-npm Flow plugin copy at ${n}.`)}else a.keptForeignPreNpmPlugin=n,i?.(`Kept ${n}: it is not managed by Flow. Remove it manually if it is a stale Flow copy.`);return i?.('Finally, remove "opencode-plugin-flow" from the plugin array in opencode.json and restart OpenCode.'),a}async function de(e){let t=c(e,"SKILL.md"),i=await f(t),a=await f(c(e,w)),s=a===null?null:T(a);if(s!==null&&a!==null){for(let[r,d]of y(a)){if(r==="SKILL.md")continue;let l=Q(e,r);if(l===null)continue;let u=await f(l);if(u!==null&&p(u)!==d)return"user_edited"}if(i===null)return"pristine";if(s.hash!==null&&p(i)===s.hash)return"pristine";return m(i).kind==="valid_generated"?"pristine":"user_edited"}if(i===null)return"foreign";let o=m(i);if(o.kind==="valid_generated")return"pristine";if(o.kind==="invalid_generated")return"user_edited";return"foreign"}function Q(e,t){let i=ne(c(e,...t.split("/")));if(i!==e&&i.startsWith(`${e}${re}`))return i;return null}async function ce(e){let t=await f(c(e,w)),i=new Set;if(t!==null)for(let a of y(t).keys()){let s=Q(e,a);if(s===null)continue;await h(s,{force:!0}),await h(`${s}.backup`,{force:!0});let o=oe(s);if(o!==e)i.add(o)}await h(c(e,"SKILL.md"),{force:!0}),await h(c(e,w),{force:!0}),await h(c(e,N),{force:!0});for(let a of[...i].sort((s,o)=>o.length-s.length))await I(a);await I(e)}async function I(e){try{await se(e)}catch(t){let i=t.code;if(i!=="ENOENT"&&i!=="ENOTEMPTY")throw t}}async function le(e){try{return(await ae(e,{withFileTypes:!0})).filter((i)=>i.isDirectory()).map((i)=>i.name).sort()}catch(t){if(t.code==="ENOENT")return[];throw t}}async function f(e){try{return await ie(e,"utf8")}catch(t){if(t.code==="ENOENT")return null;throw t}}async function Y(e){for(let[t,i]of e.files){let a=c(e.root,`${t}.md`),s=c(e.root,`.${t}.flow-version`),o=await f(a),n=await f(s),r=n===null?null:b(n,e.kind,t);if(o===null&&r===null)continue;if(!(r!==null||o===i))continue;if(o!==null&&r!==null&&p(o)!==r.hash){e.keptUserEdited.push(a),e.logger?.(`Kept user-edited Flow ${e.kind} at ${a}; remove it manually if it is no longer needed.`);continue}if(!e.dryRun)await h(a,{force:!0}),await h(s,{force:!0}),await h(`${a}.backup`,{force:!0});e.removed.push(a),e.logger?.(`${e.dryRun?"Would remove":"Removed"} Flow ${e.kind} at ${a}.`)}if(!e.dryRun)await I(e.root)}var q=`opencode-plugin-flow — Flow plugin lifecycle commands
17
17
 
18
18
  Usage:
19
19
  bunx opencode-plugin-flow uninstall [--dry-run]
@@ -28,8 +28,8 @@ Options:
28
28
  --dry-run Show what would be removed without deleting anything
29
29
  --help Show this message`;function X(e){process.stdout.write(`${e}
30
30
  `)}function S(e){process.stderr.write(`${e}
31
- `)}async function ue(e){let t=[...e];if(t.length===0||t.includes("--help")||t.includes("-h"))return X(F),0;let a=t.shift();if(a!=="uninstall")return S(`Unknown command: ${a}
31
+ `)}async function ue(e){let t=[...e];if(t.length===0||t.includes("--help")||t.includes("-h"))return X(q),0;let i=t.shift();if(i!=="uninstall")return S(`Unknown command: ${i}
32
32
 
33
- ${F}`),1;let i=!1;for(let s of t){if(s==="--dry-run"){i=!0;continue}return S(`Unknown argument: ${s}
33
+ ${q}`),1;let a=!1;for(let s of t){if(s==="--dry-run"){a=!0;continue}return S(`Unknown argument: ${s}
34
34
 
35
- ${F}`),1}return await Q({homeDir:process.env.HOME??he(),dryRun:i,logger:X}),0}try{process.exitCode=await ue(process.argv.slice(2))}catch(e){S(e instanceof Error?e.message:String(e)),process.exitCode=1}
35
+ ${q}`),1}return await M({homeDir:process.env.HOME??he(),dryRun:a,logger:X}),0}try{process.exitCode=await ue(process.argv.slice(2))}catch(e){S(e instanceof Error?e.message:String(e)),process.exitCode=1}