git init | first commit
This commit is contained in:
3
.env.example
Normal file
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
OPENCHAMBER_PORT=5200
|
||||||
|
UI_PASSWORD=
|
||||||
|
REPOSITORIES_PATH=./repositories
|
||||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.DS_Store
|
||||||
|
.env
|
||||||
|
repositories/
|
||||||
|
opencode-cache/
|
||||||
|
opencode-data/
|
||||||
|
opencode-state/
|
||||||
|
openchamber-config/
|
||||||
|
opencode-config/agents
|
||||||
|
opencode-config/commands
|
||||||
|
opencode-config/skills
|
||||||
|
opencode-config/plugins
|
||||||
|
opencode-config/opencode.jsonc
|
||||||
43
Dockerfile
Normal file
43
Dockerfile
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
FROM node:26-trixie-slim
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
curl \
|
||||||
|
bash \
|
||||||
|
ca-certificates \
|
||||||
|
coreutils \
|
||||||
|
findutils \
|
||||||
|
git \
|
||||||
|
grep \
|
||||||
|
openssh-client \
|
||||||
|
tar \
|
||||||
|
docker.io \
|
||||||
|
docker-compose \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
pipx \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
USER node
|
||||||
|
|
||||||
|
ENV HOME=/home/node
|
||||||
|
ENV PATH="/home/node/.local/bin:/home/node/.opencode/bin:${PATH}"
|
||||||
|
|
||||||
|
RUN npm config set prefix ~/.local
|
||||||
|
|
||||||
|
WORKDIR /home/node
|
||||||
|
|
||||||
|
# Install OpenCode CLI
|
||||||
|
RUN curl -fsSL https://opencode.ai/install | bash
|
||||||
|
|
||||||
|
# Install OpenChamber (web + PWA)
|
||||||
|
RUN curl -fsSL https://raw.githubusercontent.com/openchamber/openchamber/main/scripts/install.sh | bash
|
||||||
|
|
||||||
|
# Install Graphifyy
|
||||||
|
RUN pipx install graphifyy && graphify install opencode
|
||||||
|
|
||||||
|
CMD ["sh", "-c", "rm -f /home/node/.config/openchamber/run/openchamber-*.pid /home/node/.config/openchamber/run/openchamber-*.json && exec openchamber serve --host 0.0.0.0 --port ${OPENCHAMBER_PORT:-5200} --foreground ${UI_PASSWORD:+--ui-password $UI_PASSWORD}"]
|
||||||
132
README.md
132
README.md
@@ -1,2 +1,132 @@
|
|||||||
# my-opencode-simple
|
# OpenCode Web
|
||||||
|
|
||||||
|
Dockerized [OpenCode](https://opencode.ai) with [OpenChamber](https://github.com/openchamber/openchamber) as the browser/PWA frontend.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
This project runs OpenChamber in the container and lets OpenChamber start and keep OpenCode available in the background.
|
||||||
|
|
||||||
|
The stack inside the container:
|
||||||
|
|
||||||
|
- **OpenCode CLI** — the AI coding assistant
|
||||||
|
- **OpenChamber** — web frontend that starts and presents OpenCode
|
||||||
|
- **Node 26** — runtime
|
||||||
|
- **Graphifyy** — knowledge-graph skill for codebase understanding (installed via pipx)
|
||||||
|
|
||||||
|
## OpenCode configuration
|
||||||
|
|
||||||
|
The `opencode-config/` directory contains a full custom OpenCode agent setup, mounted at `/home/node/.config/opencode` inside the container.
|
||||||
|
|
||||||
|
### Agents
|
||||||
|
|
||||||
|
| File | Mode | Purpose |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `agents/build.md` | primary | Default agent with full permission set for implementation work |
|
||||||
|
| `agents/explore.md` | subagent | Specialized codebase file/content search |
|
||||||
|
| `agents/general.md` | subagent | General-purpose multi-step research and execution |
|
||||||
|
| `agents/plan.md` | primary | Plan mode — architecture design and implementation plans (read-only) |
|
||||||
|
| `agent/executor.md` | subagent | Runs shell commands only, no editing or file-reading |
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
| File | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `command/commit.md` | Create git commits with auto-generated conventional commit messages |
|
||||||
|
| `command/rapid.md` | Fast iteration mode — quick fixes without extensive planning |
|
||||||
|
| `commands/plan.md` | Creates detailed implementation plans |
|
||||||
|
| `commands/review.md` | Reviews code changes (commit, branch, PR, or uncommitted) |
|
||||||
|
|
||||||
|
### Plugins
|
||||||
|
|
||||||
|
| File | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `plugin/fail-fast.ts` | Converts denied permissions and missing shell utilities into explicit task failures so agents don't stall or retry blocked actions |
|
||||||
|
|
||||||
|
### Snippets
|
||||||
|
|
||||||
|
| File | Aliases | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `snippet/commit-message.md` | `cm` | Generates a commit message from current changes |
|
||||||
|
| `snippet/create-plan.md` | `plan` | Creates an implementation plan from the current session |
|
||||||
|
|
||||||
|
### Permissions
|
||||||
|
|
||||||
|
Fine-grained tool permissions are defined in `opencode.jsonc` (auto-generated, gitignored). Each agent has a tailored permission set — for example, `explore` has broad read/search access with bash allowed, while `build` has write/edit access but denies bash for safety.
|
||||||
|
|
||||||
|
## Fail-fast plugin
|
||||||
|
|
||||||
|
The fail-fast plugin (`plugin/fail-fast.ts`) hooks into OpenCode's tool lifecycle to catch three conditions:
|
||||||
|
|
||||||
|
1. **Permission denied** — if a `permission.ask` results in `deny`, the plugin throws a `FAIL_FAST_PERMISSION_DENIED` error with the permission name and next-action guidance.
|
||||||
|
2. **Invalid command** — if bash is called without a command, it throws `FAIL_FAST_INVALID_COMMAND`.
|
||||||
|
3. **Missing utility** — after every bash execution, the plugin checks stderr/stdout for "command not found", "not found", "ENOENT" patterns. If found, it throws `FAIL_FAST_MISSING_UTILITY` with the utility name.
|
||||||
|
|
||||||
|
This prevents agents from silently retrying blocked operations or looping on missing dependencies.
|
||||||
|
|
||||||
|
## How to run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `http://localhost:5200` in your browser.
|
||||||
|
|
||||||
|
To run OpenChamber on a different port, set `OPENCHAMBER_PORT` in `.env` and restart the container:
|
||||||
|
|
||||||
|
```env
|
||||||
|
OPENCHAMBER_PORT=5300
|
||||||
|
```
|
||||||
|
|
||||||
|
The container uses host networking, so OpenChamber binds directly to `OPENCHAMBER_PORT`; there is no separate Docker port mapping to update.
|
||||||
|
|
||||||
|
To protect the UI, set `UI_PASSWORD` in `.env`.
|
||||||
|
|
||||||
|
User and group IDs can be set in `.env` to match the host user:
|
||||||
|
|
||||||
|
```env
|
||||||
|
UID=1000
|
||||||
|
GID=1000
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to update
|
||||||
|
|
||||||
|
Rebuild the image to pull the latest versions of OpenCode and OpenChamber:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose build --no-cache
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Managing repositories
|
||||||
|
|
||||||
|
Set `REPOSITORIES_PATH` in `.env` to the host directory that contains repositories OpenCode should work on:
|
||||||
|
|
||||||
|
```env
|
||||||
|
REPOSITORIES_PATH=./repositories
|
||||||
|
```
|
||||||
|
|
||||||
|
The directory is mounted at `/home/repositories` inside the container.
|
||||||
|
|
||||||
|
## Container details
|
||||||
|
|
||||||
|
| Aspect | Detail |
|
||||||
|
| --- | --- |
|
||||||
|
| Network | `host` mode — no port mapping needed |
|
||||||
|
| Docker access | `/var/run/docker.sock` mounted for in-container Docker usage |
|
||||||
|
| Container user | Runs as `${UID}:${GID}` (default 1000:1000) |
|
||||||
|
| OpenChamber | Configured to allow unauthenticated LAN access (`OPENCHAMBER_ALLOW_UNAUTHENTICATED_LAN=true`) |
|
||||||
|
|
||||||
|
## Persisted data (gitignored)
|
||||||
|
|
||||||
|
| Local path | Container mount point | Purpose |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `.config/opencode-data/` | `/home/node/.local/share/opencode` | Agent state and tool outputs |
|
||||||
|
| `.config/opencode-state/` | `/home/node/.local/state/opencode` | Session and runtime state |
|
||||||
|
| `.config/opencode-cache/` | `/home/node/.cache/opencode` | Model cache and temporary data |
|
||||||
|
| `.config/openchamber-config/` | `/home/node/.config/openchamber` | OpenChamber configuration and session data |
|
||||||
|
|
||||||
|
## Browser and PWA notifications
|
||||||
|
|
||||||
|
OpenChamber can send browser notifications for prompt completion, questions, errors, and subtasks.
|
||||||
|
|
||||||
|
To receive notifications, open OpenChamber in your browser or installed PWA and allow notifications for the site/app when prompted. If notifications were previously blocked, reset the site notification permission in your browser settings.
|
||||||
|
|||||||
20
docker-compose.yml
Normal file
20
docker-compose.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
services:
|
||||||
|
my-opencode:
|
||||||
|
user: "${UID}:${GID}"
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
volumes:
|
||||||
|
- "./opencode-config:/home/node/.config/opencode"
|
||||||
|
- ".config/opencode-data:/home/node/.local/share/opencode"
|
||||||
|
- ".config/opencode-state:/home/node/.local/state/opencode"
|
||||||
|
- ".config/opencode-cache:/home/node/.cache/opencode"
|
||||||
|
- ".config/openchamber-config:/home/node/.config/openchamber"
|
||||||
|
- "${REPOSITORIES_PATH:-./repositories}:/home/node/repositories"
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||||
|
environment:
|
||||||
|
OPENCHAMBER_PORT: ${OPENCHAMBER_PORT:-5200}
|
||||||
|
OPENCODE_BINARY: /home/node/.opencode/bin/opencode
|
||||||
|
OPENCHAMBER_ALLOW_UNAUTHENTICATED_LAN: true
|
||||||
|
UI_PASSWORD: ${UI_PASSWORD:-}
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
62
opencode-config/agent/executor.md
Normal file
62
opencode-config/agent/executor.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
description: Runs shell commands and returns command results. Use this instead
|
||||||
|
of the general agent whenever a task is only to execute commands.
|
||||||
|
mode: subagent
|
||||||
|
temperature: 0.1
|
||||||
|
tools:
|
||||||
|
write: false
|
||||||
|
edit: false
|
||||||
|
bash: true
|
||||||
|
permission:
|
||||||
|
doom_loop: ask
|
||||||
|
external_directory:
|
||||||
|
"*": ask
|
||||||
|
/home/.local/share/opencode/tool-output/*: allow
|
||||||
|
/tmp/opencode/*: allow
|
||||||
|
question: deny
|
||||||
|
plan_enter: deny
|
||||||
|
plan_exit: deny
|
||||||
|
read:
|
||||||
|
"*": deny
|
||||||
|
"*.env": ask
|
||||||
|
"*.env.*": ask
|
||||||
|
"*.env.example": allow
|
||||||
|
edit: deny
|
||||||
|
bash:
|
||||||
|
rm *: deny
|
||||||
|
git push*: deny
|
||||||
|
git reset --hard*: deny
|
||||||
|
glob: deny
|
||||||
|
grep: deny
|
||||||
|
list: deny
|
||||||
|
task: deny
|
||||||
|
todowrite: deny
|
||||||
|
webfetch: deny
|
||||||
|
websearch: deny
|
||||||
|
model: openai/gpt-5.4-mini
|
||||||
|
---
|
||||||
|
|
||||||
|
You are the executor agent.
|
||||||
|
|
||||||
|
Your only responsibility is to run shell commands requested by the caller and report the results. Do not inspect files with non-shell tools, edit files, research, plan, or perform general coding work.
|
||||||
|
|
||||||
|
## Fail-Fast Capability Check
|
||||||
|
|
||||||
|
Before running a command, check whether it requires a denied permission, destructive action, or unavailable shell utility. If a command fails because a utility is missing or permission is denied, do not retry variants blindly.
|
||||||
|
|
||||||
|
Stop immediately and report:
|
||||||
|
|
||||||
|
- `FAIL_FAST_CAPABILITY_MISSING`
|
||||||
|
- Missing utility, denied permission, or blocked command
|
||||||
|
- Why it is required
|
||||||
|
- The exact command attempted or requested
|
||||||
|
- Exact next action for the caller
|
||||||
|
|
||||||
|
For each requested command:
|
||||||
|
|
||||||
|
1. Run the command exactly as needed, using the shell tool.
|
||||||
|
2. Report whether it succeeded or failed.
|
||||||
|
3. Include the relevant stdout, stderr, and exit status when available.
|
||||||
|
4. Keep analysis minimal and limited to what the command output shows.
|
||||||
|
|
||||||
|
If the request is not primarily command execution, say that it should be handled by another agent.
|
||||||
74
opencode-config/command/commit.md
Normal file
74
opencode-config/command/commit.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
description: Create git commit with auto-generated conventional commit message
|
||||||
|
agent: build
|
||||||
|
model: opencode/deepseek-v4-flash-free
|
||||||
|
---
|
||||||
|
|
||||||
|
# Git Commit Command
|
||||||
|
|
||||||
|
Create a well-structured git commit by analyzing staged changes and generating a conventional commit message.
|
||||||
|
|
||||||
|
## Phase 1: Gather Context
|
||||||
|
|
||||||
|
Run these commands in parallel to understand the current state:
|
||||||
|
|
||||||
|
1. `git status` - See all staged and unstaged changes
|
||||||
|
2. `git diff --cached` - View the actual staged changes that will be committed
|
||||||
|
3. `git log --oneline -5` - Review recent commit message style for consistency
|
||||||
|
|
||||||
|
## Phase 2: Analyze Changes
|
||||||
|
|
||||||
|
Based on the staged diff, determine:
|
||||||
|
|
||||||
|
1. **Change Type** (use conventional commits):
|
||||||
|
- `feat`: New feature
|
||||||
|
- `fix`: Bug fix
|
||||||
|
- `refactor`: Code restructuring without behavior change
|
||||||
|
- `docs`: Documentation only
|
||||||
|
- `test`: Adding or updating tests
|
||||||
|
- `chore`: Maintenance tasks
|
||||||
|
- `style`: Formatting, whitespace
|
||||||
|
- `perf`: Performance improvement
|
||||||
|
- `ci`: CI/CD changes
|
||||||
|
|
||||||
|
2. **Scope** (optional): Affected module or component
|
||||||
|
|
||||||
|
3. **Description**: Concise summary focusing on WHY, not WHAT
|
||||||
|
|
||||||
|
## Phase 3: Generate Commit Message
|
||||||
|
|
||||||
|
Format: `type(scope): description`
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Use imperative mood ("Add feature" not "Added feature")
|
||||||
|
- Keep first line under 72 characters
|
||||||
|
- Focus on the purpose and impact
|
||||||
|
- Add body for complex changes explaining reasoning
|
||||||
|
|
||||||
|
## Phase 4: Execute Commit
|
||||||
|
|
||||||
|
1. If there are unstaged changes that should be included, ask user first
|
||||||
|
2. Stage any additional files if requested
|
||||||
|
3. Execute the commit with the generated message
|
||||||
|
4. Run `git status` to verify success
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
```
|
||||||
|
Commit Analysis
|
||||||
|
---------------
|
||||||
|
Type: [type]
|
||||||
|
Scope: [scope or "none"]
|
||||||
|
Files: [number] files changed
|
||||||
|
|
||||||
|
Generated Message:
|
||||||
|
[commit message]
|
||||||
|
|
||||||
|
Commit Status: [success/failure]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Safety Checks
|
||||||
|
|
||||||
|
- NEVER commit files that appear to contain secrets (.env, credentials, API keys)
|
||||||
|
- WARN if committing lock files or large binary files
|
||||||
|
- CONFIRM before committing if there are untracked files that might be forgotten
|
||||||
57
opencode-config/command/rapid.md
Normal file
57
opencode-config/command/rapid.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
description: Fast iteration mode - quick fixes without extensive planning
|
||||||
|
agent: build
|
||||||
|
subtask: false
|
||||||
|
---
|
||||||
|
# Rapid Mode - Fast Iteration
|
||||||
|
|
||||||
|
You are in **rapid mode**. Optimize for speed and iteration velocity. Skip extensive planning and get to implementation quickly.
|
||||||
|
|
||||||
|
## Your Mission
|
||||||
|
|
||||||
|
Execute the following task with minimal ceremony:
|
||||||
|
|
||||||
|
$ARGUMENTS
|
||||||
|
|
||||||
|
## Rapid Execution Protocol
|
||||||
|
|
||||||
|
1. **Understand** (30 seconds max)
|
||||||
|
- What exactly needs to change?
|
||||||
|
- What's the fastest path to working code?
|
||||||
|
|
||||||
|
2. **Execute** (immediately)
|
||||||
|
- Make the change directly
|
||||||
|
- Use existing patterns - don't reinvent
|
||||||
|
- Keep changes minimal and focused
|
||||||
|
|
||||||
|
3. **Verify** (quick check)
|
||||||
|
- Does it work? Test it.
|
||||||
|
- Any obvious issues? Fix them.
|
||||||
|
|
||||||
|
## Rapid Mode Rules
|
||||||
|
|
||||||
|
- **No extensive planning** - Act first, refine later
|
||||||
|
- **Minimal changes** - Touch only what's necessary
|
||||||
|
- **Use existing patterns** - Copy from similar code in the codebase
|
||||||
|
- **Skip documentation** - Unless explicitly requested
|
||||||
|
- **Iterate fast** - Ship something, then improve
|
||||||
|
- **Ask only if blocked** - Make reasonable assumptions otherwise
|
||||||
|
|
||||||
|
## What Rapid Mode is NOT
|
||||||
|
|
||||||
|
- Not for complex architectural changes (use `/architect`)
|
||||||
|
- Not for learning or understanding (use `/mentor`)
|
||||||
|
- Not for critical security code (use `/review`)
|
||||||
|
- Not for large refactors (use `/refactor`)
|
||||||
|
|
||||||
|
## Output Style
|
||||||
|
|
||||||
|
Keep responses concise:
|
||||||
|
|
||||||
|
```
|
||||||
|
Changed: [what was modified]
|
||||||
|
Verified: [how it was tested]
|
||||||
|
Note: [any caveats, if critical]
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not explain decisions unless they're non-obvious. Just ship it.
|
||||||
156
opencode-config/plugin/fail-fast.ts
Normal file
156
opencode-config/plugin/fail-fast.ts
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
/**
|
||||||
|
* Fail Fast Plugin
|
||||||
|
* Converts denied permissions and missing shell utilities into explicit task
|
||||||
|
* failures so agents do not repeatedly retry or stall on unavailable actions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Plugin } from "@opencode-ai/plugin"
|
||||||
|
|
||||||
|
const MISSING_UTILITY_PATTERNS = [
|
||||||
|
/(?:^|\n)(?:sh|bash|zsh|fish):\s*(?<command>[\w./-]+):\s*command not found\b/i,
|
||||||
|
/(?:^|\n)(?<command>[\w./-]+):\s*command not found\b/i,
|
||||||
|
/(?:^|\n)(?:sh|bash|zsh|fish):\s*(?<command>[\w./-]+):\s*not found\b/i,
|
||||||
|
/(?:^|\n)(?<command>[\w./-]+):\s*not found\b/i,
|
||||||
|
/(?:^|\n)env:\s*(?<command>[\w./-]+):\s*No such file or directory\b/i,
|
||||||
|
/(?:^|\n).*spawn\s+(?<command>[\w./-]+)\s+ENOENT\b/i,
|
||||||
|
]
|
||||||
|
|
||||||
|
const SHELL_BUILTINS = new Set([
|
||||||
|
"alias",
|
||||||
|
"break",
|
||||||
|
"cd",
|
||||||
|
"command",
|
||||||
|
"continue",
|
||||||
|
"dirs",
|
||||||
|
"echo",
|
||||||
|
"eval",
|
||||||
|
"exec",
|
||||||
|
"exit",
|
||||||
|
"export",
|
||||||
|
"false",
|
||||||
|
"fg",
|
||||||
|
"hash",
|
||||||
|
"jobs",
|
||||||
|
"popd",
|
||||||
|
"printf",
|
||||||
|
"pushd",
|
||||||
|
"pwd",
|
||||||
|
"read",
|
||||||
|
"return",
|
||||||
|
"set",
|
||||||
|
"shift",
|
||||||
|
"source",
|
||||||
|
"test",
|
||||||
|
"true",
|
||||||
|
"type",
|
||||||
|
"ulimit",
|
||||||
|
"unalias",
|
||||||
|
"unset",
|
||||||
|
])
|
||||||
|
|
||||||
|
function normalizeCommand(command: string): string {
|
||||||
|
return command.replace(/^['"]|['"]$/g, "").trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function findMissingUtility(output: string): string | undefined {
|
||||||
|
for (const pattern of MISSING_UTILITY_PATTERNS) {
|
||||||
|
const match = pattern.exec(output)
|
||||||
|
const command = match?.groups?.command
|
||||||
|
|
||||||
|
if (!command) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = normalizeCommand(command)
|
||||||
|
|
||||||
|
if (normalized && !SHELL_BUILTINS.has(normalized)) {
|
||||||
|
return normalized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBashCommand(args: unknown): string | undefined {
|
||||||
|
if (!args || typeof args !== "object") {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = args as Record<string, unknown>
|
||||||
|
const command = record.command ?? record.cmd ?? record.script
|
||||||
|
|
||||||
|
return typeof command === "string" ? command : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function describePermission(input: {
|
||||||
|
type: string
|
||||||
|
pattern?: string | string[]
|
||||||
|
title: string
|
||||||
|
}): string {
|
||||||
|
const pattern = Array.isArray(input.pattern)
|
||||||
|
? input.pattern.join(", ")
|
||||||
|
: input.pattern
|
||||||
|
|
||||||
|
return [input.type, pattern].filter(Boolean).join(" ") || input.title
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FailFastPlugin = (async () => {
|
||||||
|
return {
|
||||||
|
"permission.ask": async (input, output) => {
|
||||||
|
if (output.status !== "deny") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
"FAIL_FAST_PERMISSION_DENIED: A required tool permission was denied.",
|
||||||
|
`Permission: ${describePermission(input)}`,
|
||||||
|
`Title: ${input.title}`,
|
||||||
|
"Next action: reroute to an agent with the required permission, request permission from the user, or fail the task explicitly.",
|
||||||
|
].join("\n")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
"tool.execute.before": async (input, output) => {
|
||||||
|
if (input.tool !== "bash") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = getBashCommand(output.args)
|
||||||
|
|
||||||
|
if (command === undefined || command.trim()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
"FAIL_FAST_INVALID_COMMAND: The bash tool was called without a command. Stop and report the missing command instead of retrying."
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
"tool.execute.after": async (input, output) => {
|
||||||
|
if (input.tool !== "bash") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const missingUtility = findMissingUtility(output.output ?? "")
|
||||||
|
|
||||||
|
if (!missingUtility) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = getBashCommand(input.args)
|
||||||
|
|
||||||
|
const commandLine = command ? `\nCommand: ${command}` : ""
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
`FAIL_FAST_MISSING_UTILITY: Required shell utility "${missingUtility}" is not available in this environment.`,
|
||||||
|
commandLine.trim(),
|
||||||
|
"Next action: install or mount the missing utility, choose a different validation path, or fail the task explicitly.",
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join("\n")
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}) satisfies Plugin
|
||||||
7
opencode-config/snippet/commit-message.md
Normal file
7
opencode-config/snippet/commit-message.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
aliases:
|
||||||
|
- cm
|
||||||
|
description: Creates a commit message
|
||||||
|
---
|
||||||
|
|
||||||
|
Based on only the current changes recommend me a commit message.
|
||||||
7
opencode-config/snippet/create-plan.md
Normal file
7
opencode-config/snippet/create-plan.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
aliases:
|
||||||
|
- plan
|
||||||
|
description: It creates and implementation plan from the previous interactions and chat
|
||||||
|
---
|
||||||
|
|
||||||
|
I want you to create an implementation plan based on our conversation in this session. It should contain a precise instructions so even someone with less knowledge of the system can implement the plan without going into the wrong direction.
|
||||||
Reference in New Issue
Block a user