Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
versionable:
- 'hooks/**'
- 'commands/**'
- 'opencode/**'
- 'GitVersion.yml'

- name: Check for +semver in commit message
Expand Down Expand Up @@ -456,11 +457,23 @@ jobs:
json.dump(data, f, indent=2)
"

- name: Update opencode package version
run: |
python -c "
import json
with open('opencode/package.json', 'r') as f:
data = json.load(f)
data['version'] = '${{ needs.version.outputs.majorMinorPatch }}'
with open('opencode/package.json', 'w') as f:
json.dump(data, f, indent=2)
f.write('\n')
"

- name: Commit and tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .claude-plugin/plugin.json
git add .claude-plugin/plugin.json opencode/package.json
git commit -m "Bump version to ${{ needs.version.outputs.majorMinorPatch }}"
git push origin main
git tag -a "v${{ needs.version.outputs.majorMinorPatch }}" -m "Release v${{ needs.version.outputs.majorMinorPatch }}"
Expand Down Expand Up @@ -510,3 +523,34 @@ jobs:
git commit -m "Update block plugin to v${{ needs.version.outputs.majorMinorPatch }}"
git push origin main
)

publish-npm:
name: Publish to npm
runs-on: ubuntu-latest
needs: [version, tag]
if: github.ref == 'refs/heads/main'
permissions:
contents: read
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: main

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Update package version
run: |
cd opencode
npm version ${{ needs.version.outputs.majorMinorPatch }} --no-git-tag-version
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

- name: Publish to npm
run: |
cd opencode
npm publish --access public

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd -g 'package.json' opencode/ --exec cat {}

Repository: kodroi/block

Length of output: 720


🌐 Web query:

npm version bundled with Node.js 20 LTS

💡 Result:

For the current Node.js 20 LTS (20.20.0, released Jan 12, 2026), the bundled npm version is npm 10.8.2. [1][2]

Note: The bundled npm version can vary across Node 20.x releases; the Node.js v20 download archive lists the npm version per release. [1]

Sources: [1] [2]


🌐 Web query:

npm trusted publishing OIDC registry-url conflict Node.js actions/setup-node

💡 Result:

When you set registry-url in actions/setup-node, it writes a project-local .npmrc (including an auth line like //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}), which can override/conflict with other npm-auth flows in the same job (notably tools like semantic-release) and can also “stick” if you switch registries multiple times in one workflow/job. [2], [3]

What to do (depending on your setup)

  1. If you’re using npm Trusted Publishing (OIDC) + semantic-release: don’t set registry-url
    semantic-release explicitly warns that registry-url can cause .npmrc conflicts and EINVALIDNPMTOKEN. Configure registry via your repo .npmrc (if needed) and let semantic-release handle auth. [3]

  2. If you’re using npm Trusted Publishing (OIDC) without semantic-release: keep registry-url on npm’s registry and don’t provide a publish token
    npm’s own Trusted Publishing example uses registry-url: 'https://registry.npmjs.org' and then runs npm publish with id-token: write permissions (no NODE_AUTH_TOKEN for publish). [1]

  3. If you must use a token for installs (private deps), scope it to the install step only
    Trusted Publishing only covers npm publish; installs may still need a (read-only) token. Use NODE_AUTH_TOKEN only on npm ci, not globally. [1]

permissions:
  contents: read
  id-token: write

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-node@v4
    with:
      node-version: 24
      registry-url: https://registry.npmjs.org

  - run: npm ci
    env:
      NODE_AUTH_TOKEN: ${{ secrets.NPM_READ_TOKEN }} # install only

  - run: npm publish # OIDC is used here (no NODE_AUTH_TOKEN)
  1. If your issue is “registry switching” within one job
    There are known cases where changing registry-url across multiple setup-node invocations doesn’t take effect as expected; a practical workaround is to avoid switching registries in the same job (split into separate jobs) or explicitly manage the .npmrc you want for each publish. [4]

Sources: npm Trusted Publishing docs [1]; GitHub docs on setup-node creating .npmrc from registry-url/NODE_AUTH_TOKEN [2]; semantic-release guidance to avoid registry-url [3]; setup-node registry switching issue [4].


🌐 Web query:

npm CLI version requirement trusted publishing npm 11.5.1

💡 Result:

npm Trusted Publishing (OIDC) requires:

  • npm CLI: v11.5.1 or later
  • Node.js: v22.14.0 or later [1]

To verify your CLI version:

npm -v

To upgrade npm (example):

npm i -g npm@^11.5.1

Sources: npm Trusted Publishing docs [1].


publish-npm job has one critical issue and several gaps to address

1. npm CLI version is below the Trusted Publishing requirement (critical)

Trusted Publishing requires npm CLI v11.5.1 or later, but Node.js 20 bundles npm 10.8.2. Add npm install -g npm@latest (or pin to ≥11.5.1) before the publish step. Without this upgrade, the OIDC token exchange will fail.

2. npm ci before publish is recommended practice

The workflow lacks npm ci before npm publish. While opencode/package.json has no prepare or prepublishOnly scripts, running npm ci ensures prepack lifecycle scripts execute reliably (this package copies files via prepack). Add a build/install step for robustness.

3. Consider adding --provenance explicitly

Even though Trusted Publishing doesn't strictly require --provenance, several users report that adding the flag made the initial publish succeed and produces clearer error messages. Add npm publish --access public --provenance or set NPM_CONFIG_PROVENANCE=true.

4. Trusted Publisher must be pre-configured on npmjs.com

npm requires the package to exist before a Trusted Publisher can be configured; the first publish must use a traditional token. After that initial publish, OIDC can be enabled. Ensure this setup is complete before merging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml around lines 527 - 556, The publish-npm job
currently uses Node 20 which ships npm 10.x and will fail Trusted Publishing
OIDC; before publishing update npm to at least 11.5.1 (e.g., run npm install -g
npm@^11.5.1 or npm@latest in the Setup Node.js step), run npm ci inside opencode
to install/build so prepack/prepublish scripts run (add an Install/Build step
before Update package version or before Publish to npm), and add the provenance
flag to the publish command (use npm publish --access public --provenance or set
NPM_CONFIG_PROVENANCE=true) in the Publish to npm step; also ensure the
first-time publish uses a traditional npm token (Trusted Publisher must be
configured afterward on npmjs.com) so the OIDC flow succeeds later.

16 changes: 10 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

This is a Claude Code plugin that provides file and directory protection using `.block` configuration files. When installed, the plugin intercepts file modification operations (Edit, Write, NotebookEdit, Bash) and blocks them based on protection rules.
This plugin provides file and directory protection using `.block` configuration files. It supports both **Claude Code** and **OpenCode**. When installed, the plugin intercepts file modification operations and blocks them based on protection rules.

## Architecture

The plugin uses Claude Code's hook system:
- **PreToolUse hook**: Runs `protect_directories.py` to check if the target file is protected before allowing Edit, Write, NotebookEdit, or Bash operations
The core protection logic lives in `hooks/protect_directories.py` (Python, no external dependencies). Both Claude Code and OpenCode integrations call this script.

Key files:
- `hooks/hooks.json` - Hook configuration that triggers protection checks
- `hooks/protect_directories.py` - Main protection logic (Python, no external dependencies)
### Claude Code integration
- **PreToolUse hook**: Runs `protect_directories.py` to check if the target file is protected before allowing Edit, Write, NotebookEdit, or Bash operations
- `hooks/hooks.json` - Hook configuration
- `hooks/run-hook.cmd` - Cross-platform entry point (polyglot script)
- `commands/create.md` - Interactive command for creating `.block` files
- `.claude-plugin/plugin.json` - Plugin metadata

### OpenCode integration
- **tool.execute.before hook**: TypeScript plugin that calls `protect_directories.py` before edit, write, bash, or patch operations
- `opencode/index.ts` - Plugin entry point
- `opencode/package.json` - npm package metadata

## Dependencies

- **Python 3.8+** - Required for the protection hook (no external packages needed)
Expand Down
53 changes: 46 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Block

**A Claude Code plugin to protect files from unwanted modifications.**
**Protect files from unwanted AI modifications in [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and [OpenCode](https://opencode.ai).**

Drop a `.block` file in any directory to control what Claude can and cannot edit. Protect configs, lock files, migrations, or entire directories with simple pattern rules.
Drop a `.block` file in any directory to control what AI agents can and cannot edit. Protect configs, lock files, migrations, or entire directories with simple pattern rules.

## Why use this?

Expand All @@ -17,6 +17,8 @@ Drop a `.block` file in any directory to control what Claude can and cannot edit

## Installation

### Claude Code

1. Register the marketplace:

```
Expand All @@ -29,6 +31,37 @@ Drop a `.block` file in any directory to control what Claude can and cannot edit
/plugin install block@block-marketplace
```

### OpenCode

Add the plugin to your `opencode.json` config:

```json
{
"plugins": ["opencode-block"]
}
```
Comment on lines +38 to +42

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

OpenCode configuration schema opencode.json plugin key

💡 Result:

In OpenCode’s opencode.json / opencode.jsonc config, the key for plugins is:

  • "plugin": an array of plugin identifiers (npm package names, including scoped packages; you can also pin versions like name@x.y.z). (opencode.ai)

Example:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
}

(opencode.ai)

Schema URL (for editor validation/autocomplete):

  • "$schema": "https://opencode.ai/config.json" (opencode.ai)

Citations:


🏁 Script executed:

grep -n "plugins" README.md | head -20

Repository: kodroi/block

Length of output: 150


opencode.json config key should be "plugin" (singular), not "plugins" (plural).

OpenCode's configuration schema uses "plugin" for the plugins array. The README incorrectly shows "plugins" (plural) in two places (lines 40 and 48), which won't be recognized and the plugin won't load.

Proposed fixes

Line 40:

 {
-  "plugins": ["opencode-block"]
+  "plugin": ["opencode-block"]
 }

Line 48:

 {
-  "plugins": ["file:///path/to/block/opencode/index.ts"]
+  "plugin": ["file:///path/to/block/opencode/index.ts"]
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 38 - 42, The README shows the opencode.json key as
"plugins" (plural) but OpenCode expects "plugin" (singular); update both
occurrences of the key in the README examples so the JSON uses "plugin" and
keeps the array value intact (i.e., replace "plugins" with "plugin" in the
opencode.json sample blocks and any other examples referencing that key).


Or for local development, clone this repo and reference the plugin directly:

```json
{
"plugins": ["file:///path/to/block/opencode/index.ts"]
}
```

You can also set up the plugin manually by copying files into your project. The plugin expects `hooks/protect_directories.py` to be a sibling of the directory containing `index.ts`:

```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a language specifier to the fenced code block (MD040).

The directory-tree code block on line 54 is missing a language tag; use text or plaintext.

📝 Proposed fix
-```
+```text
 your-project/
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 54-54: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 54, The README's fenced code block containing the
directory-tree snippet (the block showing "your-project/") lacks a language
specifier; update that fence to include a language tag such as text or plaintext
(e.g., change the opening ``` to ```text) so the directory-tree code block
satisfies MD040 and renders as plain text.

your-project/
├── .opencode/
│ └── plugin/
│ └── index.ts # copied from opencode/index.ts
├── hooks/
│ └── protect_directories.py # copied from hooks/protect_directories.py
```

> **Note:** The `tool.execute.before` hook protects tools called by the primary agent. Tools invoked by subagents spawned via the `task` tool may not be intercepted.

## Usage

Use the `/block:create` command to interactively create a `.block` file:
Expand Down Expand Up @@ -144,7 +177,10 @@ When both files exist in the same directory:

## How It Works

The plugin hooks into Claude's file operations. When Claude tries to modify a file, it checks for `.block` files in the target directory and all parent directories, then combines their rules.
The plugin hooks into file operations from Claude Code and OpenCode. When the AI agent tries to modify a file, the plugin checks for `.block` files in the target directory and all parent directories, then combines their rules.

- **Claude Code**: Uses a PreToolUse hook to intercept Edit, Write, NotebookEdit, and Bash tools
- **OpenCode**: Uses a `tool.execute.before` hook to intercept edit, write, bash, and patch tools

- `.block` files themselves are always protected
- Protection cascades to all subdirectories
Expand Down Expand Up @@ -194,8 +230,11 @@ pytest tests/ -v --cov=hooks --cov-report=term-missing
```
block/
├── hooks/
│ ├── protect_directories.py # Main protection logic
│ └── run-hook.cmd # Cross-platform entry point
│ ├── protect_directories.py # Main protection logic (Python)
│ └── run-hook.cmd # Cross-platform entry point (Claude Code)
├── opencode/
│ ├── index.ts # OpenCode plugin entry point
│ └── package.json # npm package metadata
├── tests/
│ ├── conftest.py # Shared fixtures
│ ├── test_basic_protection.py
Expand All @@ -210,9 +249,9 @@ block/
│ ├── test_wildcards.py
│ └── test_edge_cases.py
├── commands/
│ └── create.md # Interactive command
│ └── create.md # Interactive command (Claude Code)
├── .claude-plugin/
│ └── plugin.json # Plugin metadata
│ └── plugin.json # Plugin metadata (Claude Code)
└── pyproject.toml # Python project config
```

Expand Down
134 changes: 134 additions & 0 deletions opencode/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/**
* Block plugin for OpenCode
*
* Provides file and directory protection using .block configuration files.
* Intercepts file modification tools (edit, write, bash, patch) and blocks
* them based on protection rules defined in .block files.
*
* This is the OpenCode equivalent of the Claude Code PreToolUse hook.
*/
import type { Plugin } from "@opencode-ai/plugin";
import { resolve } from "path";

/** Tools that modify files and should be checked against .block rules. */
const PROTECTED_TOOLS = new Set(["edit", "write", "bash", "patch"]);

/**
* Maps OpenCode tool names to the names expected by protect_directories.py.
* The Python script was originally written for Claude Code's tool naming.
*/
const TOOL_NAME_MAP: Record<string, string> = {
edit: "Edit",
write: "Write",
bash: "Bash",
patch: "Write",
};

/**
* Build the JSON input that protect_directories.py expects on stdin.
*
* Claude Code hook input format:
* { "tool_name": "Edit", "tool_input": { "file_path": "..." } }
* { "tool_name": "Bash", "tool_input": { "command": "..." } }
*
* OpenCode uses camelCase args: filePath for edit/write/patch, command for bash.
*/
function buildHookInput(
tool: string,
args: Record<string, unknown>,
): string | null {
const toolName = TOOL_NAME_MAP[tool];
if (!toolName) return null;

const toolInput: Record<string, unknown> = {};

if (tool === "bash") {
if (!args.command) return null;
toolInput.command = args.command;
} else {
// edit, write, patch — OpenCode provides the path as "filePath"
if (!args.filePath) return null;
toolInput.file_path = args.filePath;
}

return JSON.stringify({ tool_name: toolName, tool_input: toolInput });
}

/**
* Locate protect_directories.py relative to this plugin file.
*
* NOTE: import.meta.dir is a Bun-specific API. OpenCode runs plugins via Bun,
* so this is safe. Packages installed via npm are cached under
* ~/.cache/opencode/node_modules/.
*
* When installed via npm the layout is:
* node_modules/opencode-block/protect_directories.py (copied by prepack)
* node_modules/opencode-block/index.ts
*
* When used from the repo directly:
* opencode/index.ts
* hooks/protect_directories.py
*/
function findScript(): string {
const pluginDir = import.meta.dir;
// npm-installed: protect_directories.py is copied alongside index.ts
const colocated = resolve(pluginDir, "protect_directories.py");
try {
const fs = require("fs");
if (fs.existsSync(colocated)) return colocated;
} catch {
// Fall through to repo layout
}
// Repo layout: ../hooks/protect_directories.py
return resolve(pluginDir, "..", "hooks", "protect_directories.py");
}

export const BlockPlugin: Plugin = async ({ $ }) => {
const scriptPath = findScript();

return {
"tool.execute.before": async (input, output) => {
if (!PROTECTED_TOOLS.has(input.tool)) return;

const hookInput = buildHookInput(
input.tool,
output.args as Record<string, unknown>,
);
if (!hookInput) return;

try {
const result =
await $`echo ${hookInput} | python3 ${scriptPath}`.quiet();
const stdout = result.stdout.toString().trim();
if (!stdout) return;

const decision = JSON.parse(stdout);
if (decision.decision === "block") {
throw new Error(decision.reason);
}
} catch (err: unknown) {
if (err instanceof SyntaxError) {
// Python output wasn't JSON — not a block, ignore
return;
}
// Block errors from our own throw above — re-throw
if (err instanceof Error && err.message) {
const msg = err.message;
// Infrastructure failures (python3 not found, spawn errors) should
// not prevent the operation — log a warning and let it proceed.
if (
(err as NodeJS.ErrnoException).code === "ENOENT" ||
msg.includes("not found") ||
msg.includes("No such file") ||
msg.includes("python3")
) {
console.warn(`[block] Protection check skipped: ${msg}`);
return;
}
}
// Re-throw actual block errors and other unexpected failures
throw err;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
};
};
28 changes: 28 additions & 0 deletions opencode/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "opencode-block",
"version": "1.1.14",
"description": "File and directory protection for OpenCode using .block marker files with pattern matching",
"main": "index.ts",
"scripts": {
"prepack": "cp ../hooks/protect_directories.py protect_directories.py",
"postpack": "rm -f protect_directories.py"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
},
"keywords": [
"opencode",
"opencode-plugin",
"protection",
"security",
"file-blocking",
"directory-lock"
],
"author": "Iiro Rahkonen",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/kodroi/block"
},
"files": [
"index.ts",
"protect_directories.py"
]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Comment on lines +1 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's verify the package.json location and content
find . -name "package.json" -path "*/opencode/*" | head -20

Repository: kodroi/block

Length of output: 79


🏁 Script executed:

# Also, let's look for the index.ts file
find . -name "index.ts" -path "*/opencode/*" | head -20

Repository: kodroi/block

Length of output: 75


🏁 Script executed:

# Check the repository structure to understand the layout
git ls-files | grep -E "(opencode|package\.json|index\.ts)" | head -30

Repository: kodroi/block

Length of output: 95


🏁 Script executed:

# Read the index.ts file to verify imports
cat -n ./opencode/index.ts

Repository: kodroi/block

Length of output: 5285


🏁 Script executed:

# Read package.json to verify its current state
cat -n ./opencode/package.json

Repository: kodroi/block

Length of output: 916


🏁 Script executed:

# Search for any OpenCode documentation or examples about plugin dependencies
find . -type f -name "*.md" -o -name "*.txt" | xargs grep -l "opencode-ai/plugin\|plugin.*dependency" 2>/dev/null | head -10

Repository: kodroi/block

Length of output: 38


🏁 Script executed:

# Check if there are other plugin examples in the repository
find . -type f -name "package.json" | xargs grep -l "@opencode-ai/plugin\|opencode-plugin" | head -10

Repository: kodroi/block

Length of output: 79


🏁 Script executed:

# Look for any tsconfig or build configuration that might indicate how plugins are compiled
find . -name "tsconfig.json" -o -name "bunfig.toml" -o -name ".bun*" | head -10

Repository: kodroi/block

Length of output: 38


🏁 Script executed:

# Check if `@opencode-ai/plugin` is used elsewhere in the repo
rg "@opencode-ai/plugin" --type ts --type json

Repository: kodroi/block

Length of output: 124


🌐 Web query:

OpenCode plugin dependencies @opencode-ai/plugin how to declare

💡 Result:

To declare dependencies for an OpenCode plugin (using @opencode-ai/plugin), you do it via package.json—where you put that package.json depends on whether your plugin is local or an npm package.

1) Local plugin (.opencode/plugins/*)

Create a package.json in your OpenCode config directory (commonly .opencode/package.json in the project), and list the npm deps you want your plugin to import:

{
  "dependencies": {
    "@opencode-ai/plugin": "^1.1.34",
    "zod": "^4.1.8"
  }
}

OpenCode will run bun install at startup, and your plugin can then import those packages. (opencode.ai)

Example TypeScript usage:

import type { Plugin } from "@opencode-ai/plugin"

(opencode.ai)

2) Plugin published to npm (loaded via opencode.json)

You publish your plugin as a normal npm package with its own package.json dependencies, then load it in opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["@my-org/custom-plugin"]
}

(opencode.ai)

Citations:


🌐 Web query:

OpenCode npm plugin installation Bun dependency resolution

💡 Result:

Installing OpenCode plugins from npm

  1. Add the package name(s) to plugin in your opencode.json:
    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
    }
  2. Restart OpenCode. It installs npm plugins automatically using Bun at startup and caches them under ~/.cache/opencode/node_modules/. [1]

If you’re writing a local plugin and need dependencies

  1. Put your plugin in .opencode/plugins/ (project) or ~/.config/opencode/plugins/ (global). [1]
  2. Add a package.json in the OpenCode config directory (commonly .opencode/package.json) with your dependencies, e.g.:
    { "dependencies": { "shescape": "^2.1.0" } }
    OpenCode will run bun install at startup so your plugin can import them. [1]

Bun dependency resolution knobs (when something won’t resolve / wrong transitive version)

  • Use overrides (npm) or resolutions (Yarn-style) in that same package.json to force transitive (“metadependency”) versions; Bun supports both. [2][3]
    {
      "dependencies": { "your-dep": "^1" },
      "overrides": { "problem-transitive": "1.2.3" }
    }

If installs fail due to lifecycle scripts (postinstall/native builds)

  • Bun may block lifecycle scripts by default; allow them by adding the package to trustedDependencies (or run bun pm trust <pkg>), then reinstall. [4]

Sources: OpenCode plugin docs [1]; Bun overrides/resolutions docs [2][3]; Bun trusted dependencies docs [4].


🏁 Script executed:

# Check the README for any setup or installation instructions
cat -n README.md 2>/dev/null || echo "No README.md found"

Repository: kodroi/block

Length of output: 8663


🏁 Script executed:

# Look for any GitHub workflow or CI configuration that might show how plugins are tested
find . -type f \( -name "*.yml" -o -name "*.yaml" \) | head -5 | xargs cat 2>/dev/null

Repository: kodroi/block

Length of output: 17569


Add missing @opencode-ai/plugin dependency declaration.

The package has no dependencies field. index.ts imports from @opencode-ai/plugin (line 10), but it isn't declared in package.json. When Bun installs this plugin from npm, it won't install @opencode-ai/plugin alongside it, causing a Cannot find module "@opencode-ai/plugin" error at runtime.

For npm-published plugins, dependencies must be declared in the plugin's own package.json. Add:

📦 Proposed fix
+  "dependencies": {
+    "@opencode-ai/plugin": "latest"
+  },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
"name": "opencode-block",
"version": "1.1.14",
"description": "File and directory protection for OpenCode using .block marker files with pattern matching",
"main": "index.ts",
"scripts": {
"prepack": "cp ../hooks/protect_directories.py protect_directories.py",
"postpack": "rm -f protect_directories.py"
},
"keywords": [
"opencode",
"opencode-plugin",
"protection",
"security",
"file-blocking",
"directory-lock"
],
"author": "Iiro Rahkonen",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/kodroi/block"
},
"files": [
"index.ts",
"protect_directories.py"
]
}
{
"name": "opencode-block",
"version": "1.1.14",
"description": "File and directory protection for OpenCode using .block marker files with pattern matching",
"main": "index.ts",
"scripts": {
"prepack": "cp ../hooks/protect_directories.py protect_directories.py",
"postpack": "rm -f protect_directories.py"
},
"dependencies": {
"@opencode-ai/plugin": "latest"
},
"keywords": [
"opencode",
"opencode-plugin",
"protection",
"security",
"file-blocking",
"directory-lock"
],
"author": "Iiro Rahkonen",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/kodroi/block"
},
"files": [
"index.ts",
"protect_directories.py"
]
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@opencode/package.json` around lines 1 - 28, The package.json is missing a
dependencies section for the runtime import used in index.ts; add a
"dependencies" object to package.json and declare "@opencode-ai/plugin" with an
appropriate semver (e.g., a caret-range matching the plugin API you built
against) so that when Bun/npm installs this package it also installs
`@opencode-ai/plugin`; update the "files" or other metadata only if necessary, but
the main fix is adding the dependencies entry referencing "@opencode-ai/plugin"
so the import in index.ts resolves at runtime.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "block"
version = "1.1.6"
description = "File and directory protection for Claude Code"
description = "File and directory protection for Claude Code and OpenCode"
readme = "README.md"
license = "MIT"
authors = [
Expand Down