opencode-plugin-flow 3.3.4 → 3.3.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
@@ -2,6 +2,29 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.3.5] - 2026-06-13
6
+
7
+ Make the source ownership map executable
8
+
9
+ Flow's current maintainer docs already described a simple architecture: skills carry judgment, runtime owns safe session state, distribution owns install and sync, and the OpenCode adapter binds host surfaces to those internals. The existing architecture guardrail did not fully enforce that map. It still watched the older `core` / `workflow` / `runtime` / `adapters` graph, which left current owners such as `src/distribution`, `src/config-shared.ts`, and root package entrypoints outside the hard check.
10
+
11
+ This release broadens the seam guardrail to match the living codebase. `scripts/cross-area/architecture-seams.mjs` now scans `src/**`, classifies shared config, runtime, distribution, adapters, root entrypoints, core protocols, and the reserved workflow bucket, and rejects the dependency shortcuts that would blur those owners. Runtime can no longer import distribution, adapters, or root entrypoint facades; distribution cannot import runtime or adapters; shared config must stay implementation-free; adapters can compose runtime, distribution, shared config, and core without importing root entrypoint facades. The default `bun run check` now runs the enforced seam gate.
12
+
13
+ The code was adjusted to satisfy that stricter contract instead of documenting an exception. Flow's config projection moved into `src/config-shared.ts`, leaving the OpenCode config adapter as thin hook wiring. Runtime readiness no longer reaches into distribution install-sync helpers directly; the OpenCode status tool injects the install-check provider when it asks runtime for workspace readiness. The seam checker also resolves common TypeScript/JavaScript extensions and directory `index.*` imports before classifying edges, so the guardrail is harder to bypass by import spelling.
14
+
15
+ No commands, tools, state paths, schemas, synced file ownership rules, runtime transitions, completion gates, review policy defaults, validation strictness, package exports, public payloads, or skill guidance changed.
16
+
17
+ Constraint: Make the documented source ownership map executable without widening Flow's public workflow surface
18
+ Constraint: Keep distribution and adapter facts injected into runtime instead of imported from runtime code
19
+ Rejected: Leave the guardrail scoped to historical layer buckets | that would keep the current distribution and shared-config owners unenforced
20
+ Rejected: Add a new runtime exception for install readiness | the cleaner boundary is adapter-provided install diagnostics
21
+ Confidence: high
22
+ Scope-risk: low
23
+ Reversibility: clean - the refactor preserves public imports and can be reverted with the seam rules if needed
24
+ Directive: Future source-owner changes must update the ADR, seam checker, and cross-area seam tests together
25
+ Tested: `bun run check` (typecheck, lint, build, full test suite, architecture seam enforcement, npm-tarball install smoke asserting the 3.3.5 README pin, bundle sanity); `bun run smoke:release` (packed candidate tarball install smoke and release evidence bundle)
26
+ Not-tested: Live OpenCode UI restart against the release candidate; this release changes internal source boundaries, maintainer guardrails, docs, tests, and release metadata only.
27
+
5
28
  ## [3.3.4] - 2026-06-13
6
29
 
7
30
  Prune the historical maze and promote the living contracts
package/README.md CHANGED
@@ -29,7 +29,7 @@ Add Flow to the `plugin` array in your `opencode.json` (global `~/.config/openco
29
29
 
30
30
  ```json
31
31
  {
32
- "plugin": ["opencode-plugin-flow@3.3.4"]
32
+ "plugin": ["opencode-plugin-flow@3.3.5"]
33
33
  }
34
34
  ```
35
35
 
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",E="SKILL.md.backup",A=w(".config","opencode","plugins","flow.js"),R=`// Managed by flow-opencode install/uninstall
3
- `,B="flow-opencode-generated-skill",$=`<!-- ${B} `,K=new RegExp(`^<!-- ${B} 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,Q)=>u.startsWith($)?[Q]:[]);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 z="opencode-plugin-flow",O="file=",N="=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(N);if(s===-1)continue;let o=i.slice(0,s),n=i.slice(s+N.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")!==z||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!==z||!i)return null;let s=t.get("hash");return{plugin:a,version:i,hash:s?.startsWith("sha256:")?s.slice(7):null}}import{mkdir as He,readFile as D,rm as I,writeFile as Ce}from"node:fs/promises";import{dirname as Qe,join as V,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 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 $={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:$.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 K}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",B="SKILL.md.backup",A=w(".config","opencode","plugins","flow.js"),R=`// Managed by flow-opencode install/uninstall
3
+ `,z="flow-opencode-generated-skill",M=`<!-- ${z} `,C=new RegExp(`^<!-- ${z} name=([a-z0-9]+(?:-[a-z0-9]+)*) version=([0-9]+) hash=sha256:([a-f0-9]{64}) -->$`,"u");function p(e){return K("sha256").update(e,"utf8").digest("hex")}function y(e){let t=e.split(`
4
+ `),a=t.flatMap((u,Z)=>u.startsWith(M)?[Z]:[]);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(C);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 E="opencode-plugin-flow",N="file=",O="=sha256:";function m(e){let t=new Map;for(let a of e.split(`
6
+ `)){if(!a.startsWith(N))continue;let i=a.slice(N.length),s=i.lastIndexOf(O);if(s===-1)continue;let o=i.slice(0,s),n=i.slice(s+O.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")!==E||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!==E||!i)return null;let s=t.get("hash");return{plugin:a,version:i,hash:s?.startsWith("sha256:")?s.slice(7):null}}import{mkdir as He,readFile as D,rm as I,writeFile as Qe}from"node:fs/promises";import{dirname as Ze,join as V,sep as $e}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(`
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 U(){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=V(e.root,`${i}.md`),o=V(e.root,`.${i}.flow-version`),n=await L(o),r=n===null?null:b(n,e.kind,i);if(r===null)continue;let d=await L(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 L(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 H({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 X({homeDir:e,dryRun:t,logger:a,kind:"command",root:c(e,g),files:G(),removed:i.removedCommands,keptUserEdited:i.keptUserEditedCommands}),await X({homeDir:e,dryRun:t,logger:a,kind:"agent",root:c(e,_),files:U(),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=C(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 C(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=C(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,E),{force:!0});for(let i of[...a].sort((s,o)=>o.length-s.length))await F(i);await F(e)}async function F(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 X(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 F(e.root)}var q=`opencode-plugin-flow — Flow plugin lifecycle commands
16
+ `}function L(){return new Map(Object.entries(W).map(([e,t])=>[e,P(t)]))}function U(){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=V(e.root,`${i}.md`),o=V(e.root,`.${i}.flow-version`),n=await G(o),r=n===null?null:b(n,e.kind,i);if(r===null)continue;let d=await G(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 G(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 H({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 X({homeDir:e,dryRun:t,logger:a,kind:"command",root:c(e,g),files:L(),removed:i.removedCommands,keptUserEdited:i.keptUserEditedCommands}),await X({homeDir:e,dryRun:t,logger:a,kind:"agent",root:c(e,_),files:U(),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=Q(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 Q(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=Q(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,B),{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 X(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
17
17
 
18
18
  Usage:
19
19
  bunx opencode-plugin-flow uninstall [--dry-run]
@@ -26,10 +26,10 @@ Commands:
26
26
 
27
27
  Options:
28
28
  --dry-run Show what would be removed without deleting anything
29
- --help Show this message`;function M(e){process.stdout.write(`${e}
29
+ --help Show this message`;function J(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 M(q),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 J(F),0;let a=t.shift();if(a!=="uninstall")return S(`Unknown command: ${a}
32
32
 
33
- ${q}`),1;let i=!1;for(let s of t){if(s==="--dry-run"){i=!0;continue}return S(`Unknown argument: ${s}
33
+ ${F}`),1;let i=!1;for(let s of t){if(s==="--dry-run"){i=!0;continue}return S(`Unknown argument: ${s}
34
34
 
35
- ${q}`),1}return await H({homeDir:process.env.HOME??he(),dryRun:i,logger:M}),0}try{process.exitCode=await ue(process.argv.slice(2))}catch(e){S(e instanceof Error?e.message:String(e)),process.exitCode=1}
35
+ ${F}`),1}return await H({homeDir:process.env.HOME??he(),dryRun:i,logger:J}),0}try{process.exitCode=await ue(process.argv.slice(2))}catch(e){S(e instanceof Error?e.message:String(e)),process.exitCode=1}