lazyopencode 0.1.0__tar.gz
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.
- lazyopencode-0.1.0/.github/release-drafter.yml +13 -0
- lazyopencode-0.1.0/.github/workflows/ci.yml +24 -0
- lazyopencode-0.1.0/.github/workflows/publish.yml +23 -0
- lazyopencode-0.1.0/.github/workflows/release-drafter.yml +16 -0
- lazyopencode-0.1.0/.gitignore +73 -0
- lazyopencode-0.1.0/.opencode/command/commit.md +36 -0
- lazyopencode-0.1.0/.opencode/command/run-quality-gates.md +6 -0
- lazyopencode-0.1.0/.opencode/plugin/compaction.ts +21 -0
- lazyopencode-0.1.0/.opencode/plugin/custom-tools.ts +31 -0
- lazyopencode-0.1.0/.opencode/plugin/env-protection.ts +21 -0
- lazyopencode-0.1.0/.opencode/plugin/notification.ts +24 -0
- lazyopencode-0.1.0/.opencode/skill/quality-gates/SKILL.md +42 -0
- lazyopencode-0.1.0/.opencode/tool/database.ts +12 -0
- lazyopencode-0.1.0/.opencode/tool/math.ts +39 -0
- lazyopencode-0.1.0/.opencode/tool/project-info.ts +11 -0
- lazyopencode-0.1.0/.opencode/tool/python-runner.ts +17 -0
- lazyopencode-0.1.0/.pre-commit-config.yaml +16 -0
- lazyopencode-0.1.0/AGENTS.md +173 -0
- lazyopencode-0.1.0/LICENSE +21 -0
- lazyopencode-0.1.0/PKG-INFO +118 -0
- lazyopencode-0.1.0/README.md +86 -0
- lazyopencode-0.1.0/artifacts/lazyclaude-reference.png +0 -0
- lazyopencode-0.1.0/opencode.json +33 -0
- lazyopencode-0.1.0/pyproject.toml +112 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/agent/researcher.md +12 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/command/verify.md +11 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/plugin/compaction.ts +21 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/plugin/custom-tools.ts +31 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/plugin/env-protection.ts +21 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/plugin/notification.ts +24 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/skill/architecture-audit/SKILL.md +15 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/skill/architecture-audit/references/patterns.md +10 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/skill/simple-formatter/SKILL.md +10 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/tool/database.ts +12 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/tool/math.ts +39 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/tool/project-info.ts +11 -0
- lazyopencode-0.1.0/reference-customizations/.opencode/tool/python-runner.ts +17 -0
- lazyopencode-0.1.0/reference-customizations/AGENTS.md +12 -0
- lazyopencode-0.1.0/reference-customizations/TODO.md +10 -0
- lazyopencode-0.1.0/reference-customizations/docs/api-standards.md +82 -0
- lazyopencode-0.1.0/reference-customizations/docs/testing-guidelines.md +70 -0
- lazyopencode-0.1.0/reference-customizations/docs/typescript-guidelines.md +56 -0
- lazyopencode-0.1.0/reference-customizations/opencode.json +68 -0
- lazyopencode-0.1.0/reference-customizations/prompts/security-audit.txt +8 -0
- lazyopencode-0.1.0/reference-customizations/scripts/fake-lint.sh +4 -0
- lazyopencode-0.1.0/scripts/check_quality.sh +82 -0
- lazyopencode-0.1.0/src/lazyopencode/__init__.py +48 -0
- lazyopencode-0.1.0/src/lazyopencode/__main__.py +6 -0
- lazyopencode-0.1.0/src/lazyopencode/_version.py +34 -0
- lazyopencode-0.1.0/src/lazyopencode/app.py +310 -0
- lazyopencode-0.1.0/src/lazyopencode/bindings.py +27 -0
- lazyopencode-0.1.0/src/lazyopencode/mixins/filtering.py +33 -0
- lazyopencode-0.1.0/src/lazyopencode/mixins/help.py +74 -0
- lazyopencode-0.1.0/src/lazyopencode/mixins/navigation.py +184 -0
- lazyopencode-0.1.0/src/lazyopencode/models/__init__.py +17 -0
- lazyopencode-0.1.0/src/lazyopencode/models/customization.py +120 -0
- lazyopencode-0.1.0/src/lazyopencode/services/__init__.py +7 -0
- lazyopencode-0.1.0/src/lazyopencode/services/discovery.py +350 -0
- lazyopencode-0.1.0/src/lazyopencode/services/gitignore_filter.py +123 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/__init__.py +152 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/agent.py +93 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/command.py +94 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/mcp.py +67 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/plugin.py +127 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/rules.py +65 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/skill.py +138 -0
- lazyopencode-0.1.0/src/lazyopencode/services/parsers/tool.py +67 -0
- lazyopencode-0.1.0/src/lazyopencode/styles/app.tcss +173 -0
- lazyopencode-0.1.0/src/lazyopencode/themes.py +30 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/__init__.py +17 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/app_footer.py +71 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/combined_panel.py +345 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/detail_pane.py +338 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/filter_input.py +88 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/helpers/__init__.py +5 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/helpers/rendering.py +17 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/status_panel.py +70 -0
- lazyopencode-0.1.0/src/lazyopencode/widgets/type_panel.py +501 -0
- lazyopencode-0.1.0/tests/AGENTS.md +308 -0
- lazyopencode-0.1.0/tests/conftest.py +164 -0
- lazyopencode-0.1.0/tests/integration/__init__.py +1 -0
- lazyopencode-0.1.0/tests/integration/discovery/__init__.py +1 -0
- lazyopencode-0.1.0/tests/integration/discovery/test_agents.py +126 -0
- lazyopencode-0.1.0/tests/integration/discovery/test_commands.py +103 -0
- lazyopencode-0.1.0/tests/integration/discovery/test_full_discovery.py +209 -0
- lazyopencode-0.1.0/tests/integration/discovery/test_mcps.py +121 -0
- lazyopencode-0.1.0/tests/integration/discovery/test_rules.py +192 -0
- lazyopencode-0.1.0/tests/integration/discovery/test_skills.py +172 -0
- lazyopencode-0.1.0/tests/integration/fixtures/agent/explorer.md +9 -0
- lazyopencode-0.1.0/tests/integration/fixtures/command/greet.md +8 -0
- lazyopencode-0.1.0/tests/integration/fixtures/mcp/project-opencode.json +9 -0
- lazyopencode-0.1.0/tests/integration/fixtures/mcp/user-opencode.json +8 -0
- lazyopencode-0.1.0/tests/integration/fixtures/memory/AGENTS.md +6 -0
- lazyopencode-0.1.0/tests/integration/fixtures/project/AGENTS.md +6 -0
- lazyopencode-0.1.0/tests/integration/fixtures/project/agent/reviewer.md +9 -0
- lazyopencode-0.1.0/tests/integration/fixtures/project/command/project-cmd.md +6 -0
- lazyopencode-0.1.0/tests/integration/fixtures/project/docs/guidelines.md +21 -0
- lazyopencode-0.1.0/tests/integration/fixtures/project/skill/project-skill/SKILL.md +7 -0
- lazyopencode-0.1.0/tests/integration/fixtures/project/skill/project-skill/src/helper.py +6 -0
- lazyopencode-0.1.0/tests/integration/fixtures/skill/task-tracker/SKILL.md +7 -0
- lazyopencode-0.1.0/tests/integration/fixtures/skill/task-tracker/reference.md +11 -0
- lazyopencode-0.1.0/tests/integration/fixtures/skill/task-tracker/scripts/run.sh +6 -0
- lazyopencode-0.1.0/tests/test_inline.py +261 -0
- lazyopencode-0.1.0/tests/test_version.py +5 -0
- lazyopencode-0.1.0/tests/unit/__init__.py +1 -0
- lazyopencode-0.1.0/uv.lock +647 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: astral-sh/setup-uv@v4
|
|
15
|
+
- name: Install dependencies
|
|
16
|
+
run: uv sync --all-extras
|
|
17
|
+
- name: Lint
|
|
18
|
+
run: uv run ruff check src tests
|
|
19
|
+
- name: Format check
|
|
20
|
+
run: uv run ruff format --check src tests
|
|
21
|
+
- name: Type check
|
|
22
|
+
run: uv run mypy src
|
|
23
|
+
- name: Test
|
|
24
|
+
run: uv run pytest
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
name: Build and publish to PyPI
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
with:
|
|
14
|
+
fetch-depth: 0 # Important for hatch-vcs versioning
|
|
15
|
+
- uses: astral-sh/setup-uv@v4
|
|
16
|
+
with:
|
|
17
|
+
enable-cache: true
|
|
18
|
+
- name: Build
|
|
19
|
+
run: uv build
|
|
20
|
+
- name: Publish to PyPI
|
|
21
|
+
run: uv publish
|
|
22
|
+
env:
|
|
23
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_KEY }}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: Release Drafter
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
update_release_draft:
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: release-drafter/release-drafter@v6
|
|
15
|
+
env:
|
|
16
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
ENV/
|
|
27
|
+
env/
|
|
28
|
+
|
|
29
|
+
# uv
|
|
30
|
+
.uv/
|
|
31
|
+
|
|
32
|
+
# IDE
|
|
33
|
+
.idea/
|
|
34
|
+
.vscode/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
*~
|
|
38
|
+
|
|
39
|
+
# Testing
|
|
40
|
+
.pytest_cache/
|
|
41
|
+
.coverage
|
|
42
|
+
htmlcov/
|
|
43
|
+
.tox/
|
|
44
|
+
.nox/
|
|
45
|
+
|
|
46
|
+
# Type checking
|
|
47
|
+
.mypy_cache/
|
|
48
|
+
.dmypy.json
|
|
49
|
+
dmypy.json
|
|
50
|
+
|
|
51
|
+
# OS
|
|
52
|
+
.DS_Store
|
|
53
|
+
Thumbs.db
|
|
54
|
+
|
|
55
|
+
# Environment
|
|
56
|
+
.env
|
|
57
|
+
.env.local
|
|
58
|
+
*.env
|
|
59
|
+
|
|
60
|
+
# Logs
|
|
61
|
+
*.log
|
|
62
|
+
|
|
63
|
+
# Textual snapshots (keep in repo but ignore local changes during dev)
|
|
64
|
+
# tests/snapshots/*.svg
|
|
65
|
+
|
|
66
|
+
# backlog.md special folder
|
|
67
|
+
backlog
|
|
68
|
+
|
|
69
|
+
# Plans folder (keep in filesystem, don't track)
|
|
70
|
+
_plans/
|
|
71
|
+
|
|
72
|
+
# hatch-vcs generated version file
|
|
73
|
+
src/lazyopencode/_version.py
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a git commit
|
|
3
|
+
---
|
|
4
|
+
Create a git commit $ARGUMENTS.
|
|
5
|
+
|
|
6
|
+
Process:
|
|
7
|
+
1. Check for staged changes (!`git status`)
|
|
8
|
+
2. If no staged changes, review and stage appropriate files
|
|
9
|
+
3. Run pre-commit checks (unless --no-verify is in $ARGUMENTS)
|
|
10
|
+
4. Analyze changes to determine commit type
|
|
11
|
+
5. Generate descriptive commit message
|
|
12
|
+
6. Include scope if applicable: `type(scope): description`
|
|
13
|
+
7. Add body for complex changes explaining why
|
|
14
|
+
8. NOTE: Exclude Claude co-authorship footer from commits
|
|
15
|
+
9. Execute commit
|
|
16
|
+
|
|
17
|
+
Commit Types:
|
|
18
|
+
- ✨ feat: New features
|
|
19
|
+
- 🐛 fix: Bug fixes
|
|
20
|
+
- 📝 docs: Documentation changes
|
|
21
|
+
- ♻️ refactor: Code restructuring without changing functionality
|
|
22
|
+
- 🎨 style: Code formatting, missing semicolons, etc.
|
|
23
|
+
- ⚡️ perf: Performance improvements
|
|
24
|
+
- ✅ test: Adding or correcting tests
|
|
25
|
+
- 🧑💻 chore: Tooling, configuration, maintenance
|
|
26
|
+
- 🚧 wip: Work in progress
|
|
27
|
+
- 🔥 remove: Removing code or files
|
|
28
|
+
- 🚑 hotfix: Critical fixes
|
|
29
|
+
- 🔒 security: Security improvements
|
|
30
|
+
|
|
31
|
+
Best Practices:
|
|
32
|
+
- Keep commits atomic and focused
|
|
33
|
+
- Write in imperative mood ("Add feature" not "Added feature")
|
|
34
|
+
- Explain why, not just what
|
|
35
|
+
- Reference issues/PRs when relevant
|
|
36
|
+
- Split unrelated changes into separate commits
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compaction Plugin - customizes context during session compaction.
|
|
3
|
+
*
|
|
4
|
+
* This plugin demonstrates using the 'experimental.session.compacting' hook
|
|
5
|
+
* to inject additional context when a session is compacted.
|
|
6
|
+
*/
|
|
7
|
+
import type { Plugin } from "@opencode-ai/plugin"
|
|
8
|
+
|
|
9
|
+
export const CompactionPlugin: Plugin = async (ctx) => {
|
|
10
|
+
return {
|
|
11
|
+
"experimental.session.compacting": async (input, output) => {
|
|
12
|
+
// Inject additional context into the compaction prompt
|
|
13
|
+
output.context.push(`## Custom Context
|
|
14
|
+
|
|
15
|
+
Include any state that should persist across compaction:
|
|
16
|
+
- Current task status
|
|
17
|
+
- Important decisions made
|
|
18
|
+
- Files being actively worked on`)
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Tools Plugin - demonstrates adding custom tools via plugin.
|
|
3
|
+
*
|
|
4
|
+
* Plugins can define their own tools that OpenCode can call,
|
|
5
|
+
* alongside the built-in tools.
|
|
6
|
+
*/
|
|
7
|
+
import { type Plugin, tool } from "@opencode-ai/plugin"
|
|
8
|
+
|
|
9
|
+
export const CustomToolsPlugin: Plugin = async (ctx) => {
|
|
10
|
+
return {
|
|
11
|
+
tool: {
|
|
12
|
+
greet: tool({
|
|
13
|
+
description: "Greets a user by name",
|
|
14
|
+
args: {
|
|
15
|
+
name: tool.schema.string(),
|
|
16
|
+
},
|
|
17
|
+
async execute(args, ctx) {
|
|
18
|
+
return `Hello ${args.name}! Welcome to OpenCode.`
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
timestamp: tool({
|
|
23
|
+
description: "Returns the current timestamp",
|
|
24
|
+
args: {},
|
|
25
|
+
async execute(args, ctx) {
|
|
26
|
+
return new Date().toISOString()
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Protection Plugin - prevents reading .env files.
|
|
3
|
+
*
|
|
4
|
+
* This plugin demonstrates using the 'tool.execute.before' hook
|
|
5
|
+
* to intercept and block certain tool operations.
|
|
6
|
+
*/
|
|
7
|
+
export const EnvProtection = async ({
|
|
8
|
+
project,
|
|
9
|
+
client,
|
|
10
|
+
$,
|
|
11
|
+
directory,
|
|
12
|
+
worktree,
|
|
13
|
+
}) => {
|
|
14
|
+
return {
|
|
15
|
+
"tool.execute.before": async (input, output) => {
|
|
16
|
+
if (input.tool === "read" && output.args.filePath.includes(".env")) {
|
|
17
|
+
throw new Error("Do not read .env files")
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification Plugin - sends system notifications on session events.
|
|
3
|
+
*
|
|
4
|
+
* This plugin demonstrates using the 'event' handler to respond
|
|
5
|
+
* to OpenCode events like session.idle.
|
|
6
|
+
*/
|
|
7
|
+
export const NotificationPlugin = async ({
|
|
8
|
+
project,
|
|
9
|
+
client,
|
|
10
|
+
$,
|
|
11
|
+
directory,
|
|
12
|
+
worktree,
|
|
13
|
+
}) => {
|
|
14
|
+
console.log("NotificationPlugin initialized!")
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
event: async ({ event }) => {
|
|
18
|
+
// Send notification on session completion
|
|
19
|
+
if (event.type === "session.idle") {
|
|
20
|
+
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quality-gates
|
|
3
|
+
description: This skill should be used when the user wants to run code quality checks (linting, formatting, type checking, tests) on the lazyopencode project. Use this skill when asked to "run quality gates", "check the code", "run tests", "lint the code", or verify code quality before committing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Quality Gates
|
|
7
|
+
|
|
8
|
+
Run code quality checks for the lazyopencode project. This skill executes the same checks used in pre-commit hooks plus tests.
|
|
9
|
+
|
|
10
|
+
## Quality Checks
|
|
11
|
+
|
|
12
|
+
The following checks are run in order:
|
|
13
|
+
|
|
14
|
+
| Check | Command | Purpose |
|
|
15
|
+
|-------|---------|---------|
|
|
16
|
+
| **Ruff Lint** | `uv run ruff check src tests --fix` | Lint code and auto-fix issues |
|
|
17
|
+
| **Ruff Format** | `uv run ruff format src tests` | Format code consistently |
|
|
18
|
+
| **Mypy** | `uv run mypy src` | Static type checking |
|
|
19
|
+
| **Pytest** | `uv run pytest tests/ -q` | Run test suite |
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
To run all quality gates:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
scripts/check_quality.sh
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or run individual checks as needed using the commands above.
|
|
30
|
+
|
|
31
|
+
## Workflow
|
|
32
|
+
|
|
33
|
+
1. Run the `scripts/check_quality.sh` script from the project root
|
|
34
|
+
2. Review any failures and fix issues
|
|
35
|
+
3. Re-run until all checks pass
|
|
36
|
+
4. Present user with concise summary of results in markdown table format
|
|
37
|
+
|
|
38
|
+
## Common Issues
|
|
39
|
+
|
|
40
|
+
- **Ruff lint failures**: Usually auto-fixed. If not, check the error message for manual fixes needed.
|
|
41
|
+
- **Mypy errors**: Type annotation issues. Add or fix type hints as indicated.
|
|
42
|
+
- **Test failures**: Review test output, fix failing tests or underlying code.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
|
|
3
|
+
export default tool({
|
|
4
|
+
description: "Query the project database",
|
|
5
|
+
args: {
|
|
6
|
+
query: tool.schema.string().describe("SQL query to execute"),
|
|
7
|
+
},
|
|
8
|
+
async execute(args) {
|
|
9
|
+
// Your database logic here
|
|
10
|
+
return `Executed query: ${args.query}`
|
|
11
|
+
},
|
|
12
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
|
|
3
|
+
// Multiple exports create separate tools: math_add, math_multiply, math_divide
|
|
4
|
+
|
|
5
|
+
export const add = tool({
|
|
6
|
+
description: "Add two numbers",
|
|
7
|
+
args: {
|
|
8
|
+
a: tool.schema.number().describe("First number"),
|
|
9
|
+
b: tool.schema.number().describe("Second number"),
|
|
10
|
+
},
|
|
11
|
+
async execute(args) {
|
|
12
|
+
return args.a + args.b
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export const multiply = tool({
|
|
17
|
+
description: "Multiply two numbers",
|
|
18
|
+
args: {
|
|
19
|
+
a: tool.schema.number().describe("First number"),
|
|
20
|
+
b: tool.schema.number().describe("Second number"),
|
|
21
|
+
},
|
|
22
|
+
async execute(args) {
|
|
23
|
+
return args.a * args.b
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const divide = tool({
|
|
28
|
+
description: "Divide two numbers",
|
|
29
|
+
args: {
|
|
30
|
+
a: tool.schema.number().describe("Dividend"),
|
|
31
|
+
b: tool.schema.number().describe("Divisor"),
|
|
32
|
+
},
|
|
33
|
+
async execute(args) {
|
|
34
|
+
if (args.b === 0) {
|
|
35
|
+
throw new Error("Cannot divide by zero")
|
|
36
|
+
}
|
|
37
|
+
return args.a / args.b
|
|
38
|
+
},
|
|
39
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
|
|
3
|
+
export default tool({
|
|
4
|
+
description: "Get project information from context",
|
|
5
|
+
args: {},
|
|
6
|
+
async execute(args, context) {
|
|
7
|
+
// Access context information
|
|
8
|
+
const { agent, sessionID, messageID } = context
|
|
9
|
+
return `Agent: ${agent}, Session: ${sessionID}, Message: ${messageID}`
|
|
10
|
+
},
|
|
11
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
|
|
3
|
+
// Example: Tool that invokes a Python script
|
|
4
|
+
// The tool definition is TypeScript, but execution can use any language
|
|
5
|
+
|
|
6
|
+
export default tool({
|
|
7
|
+
description: "Run a Python script with arguments",
|
|
8
|
+
args: {
|
|
9
|
+
script: tool.schema.string().describe("Path to Python script"),
|
|
10
|
+
args: tool.schema.array(tool.schema.string()).describe("Arguments to pass"),
|
|
11
|
+
},
|
|
12
|
+
async execute(args) {
|
|
13
|
+
const scriptArgs = args.args.join(" ")
|
|
14
|
+
const result = await Bun.$`python3 ${args.script} ${scriptArgs}`.text()
|
|
15
|
+
return result.trim()
|
|
16
|
+
},
|
|
17
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.8.6
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: local
|
|
10
|
+
hooks:
|
|
11
|
+
- id: mypy
|
|
12
|
+
name: mypy
|
|
13
|
+
entry: uv run mypy src
|
|
14
|
+
language: system
|
|
15
|
+
types: [python]
|
|
16
|
+
pass_filenames: false
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# LazyOpenCode
|
|
2
|
+
|
|
3
|
+
A keyboard-driven TUI for visualizing and managing OpenCode customizations.
|
|
4
|
+
|
|
5
|
+
## Environment Rules
|
|
6
|
+
- **OS**: Windows (Git Bash). Use forward slashes `/` and `/c/` prefix for absolute paths.
|
|
7
|
+
- **Search**: `rg` and `fd` are installed. Use them for fast searching.
|
|
8
|
+
- **Quality Gates**: Always run quality gates before asking the user to commit changes. Use the `quality-gates` skill by calling the Skill tool. Do NOT run `uv run ruff`, `uv run mypy`, or other individual linting tools directly - always use the skill instead.
|
|
9
|
+
- **TUI Verification**: Do NOT run `uv run lazyopencode` to verify the application. It is a TUI and output cannot be captured effectively. Use unit tests or static analysis instead.
|
|
10
|
+
|
|
11
|
+
## Project Overview
|
|
12
|
+
|
|
13
|
+
- **Language**: Python 3.11+
|
|
14
|
+
- **Framework**: Textual (TUI), Rich (terminal formatting)
|
|
15
|
+
- **Package Manager**: uv
|
|
16
|
+
- **Architecture**: Mixin-based Textual app with service layer
|
|
17
|
+
- **Inspired by**: LazyClaude, Lazygit
|
|
18
|
+
|
|
19
|
+
## Implementation Status (Phases 0-5 Completed)
|
|
20
|
+
|
|
21
|
+
- [x] **Foundation**: Project structure, dependencies, CLI entry point
|
|
22
|
+
- [x] **Models**: Customization types, data classes
|
|
23
|
+
- [x] **Widgets**: Type panels, combined panel, detail pane, status bar, footer
|
|
24
|
+
- [x] **Parsers**: Full support for Commands, Agents, Skills, Rules, MCPs, Tools, Plugins
|
|
25
|
+
- [x] **Navigation**: Vim-like navigation (j/k), tab switching, number shortcuts
|
|
26
|
+
- [x] **Filtering**: Filter by Global/Project, Search overlay
|
|
27
|
+
- [x] **Theme**: Gruvbox theme (default) matching LazyClaude style
|
|
28
|
+
- [ ] **Polish**: Settings persistence, comprehensive tests (In Progress)
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# Run the application
|
|
34
|
+
uv run lazyopencode
|
|
35
|
+
|
|
36
|
+
# Run tests
|
|
37
|
+
uv run pytest
|
|
38
|
+
|
|
39
|
+
# Run quality gates (linting, formatting, type checking, tests)
|
|
40
|
+
bash scripts/check_quality.sh
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Directory Structure
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
src/lazyopencode/
|
|
47
|
+
├── app.py # Main Textual application
|
|
48
|
+
├── bindings.py # Keyboard bindings
|
|
49
|
+
├── themes.py # Theme definitions
|
|
50
|
+
├── models/ # Data models (Customization, ConfigLevel, etc.)
|
|
51
|
+
├── services/ # Business logic
|
|
52
|
+
│ ├── discovery.py # Finds customizations on disk
|
|
53
|
+
│ ├── filter.py # Filters by level/query
|
|
54
|
+
│ └── parsers/ # Type-specific parsers
|
|
55
|
+
├── widgets/ # Textual UI components
|
|
56
|
+
├── mixins/ # App functionality mixins
|
|
57
|
+
└── styles/ # TCSS stylesheets
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Code Standards
|
|
61
|
+
|
|
62
|
+
### Python Style
|
|
63
|
+
- Use type hints for all function parameters and return values
|
|
64
|
+
- Use `dataclasses` for data models
|
|
65
|
+
- Follow PEP 8 naming conventions
|
|
66
|
+
- Maximum line length: 88 characters (ruff default)
|
|
67
|
+
|
|
68
|
+
### Textual Patterns
|
|
69
|
+
- Use `reactive` for state that should trigger UI updates
|
|
70
|
+
- Use `Message` classes for widget communication
|
|
71
|
+
- Use mixins to organize app functionality
|
|
72
|
+
- Keep widgets focused and single-purpose
|
|
73
|
+
|
|
74
|
+
### Imports
|
|
75
|
+
- Group imports: stdlib, third-party, local
|
|
76
|
+
- Use absolute imports within the package
|
|
77
|
+
- Re-export public APIs from `__init__.py`
|
|
78
|
+
|
|
79
|
+
## OpenCode Configuration Paths
|
|
80
|
+
|
|
81
|
+
The application discovers customizations from these locations:
|
|
82
|
+
|
|
83
|
+
| Type | Global Path | Project Path |
|
|
84
|
+
|------|-------------|--------------|
|
|
85
|
+
| Commands | `~/.config/opencode/command/*.md` | `.opencode/command/*.md` |
|
|
86
|
+
| Agents | `~/.config/opencode/agent/*.md` | `.opencode/agent/*.md` |
|
|
87
|
+
| Skills | `~/.config/opencode/skill/*/SKILL.md` | `.opencode/skill/*/SKILL.md` |
|
|
88
|
+
| Rules | `~/.config/opencode/AGENTS.md` | `AGENTS.md` |
|
|
89
|
+
| MCPs | `~/.config/opencode/opencode.json` | `opencode.json` |
|
|
90
|
+
| Tools | `~/.config/opencode/tool/*.ts` | `.opencode/tool/*.ts` |
|
|
91
|
+
| Plugins | `~/.config/opencode/plugin/` | `.opencode/plugin/` |
|
|
92
|
+
|
|
93
|
+
## Key Components
|
|
94
|
+
|
|
95
|
+
### Models (`models/customization.py`)
|
|
96
|
+
- `Customization` - Core data object for any customization
|
|
97
|
+
- `ConfigLevel` - Enum: GLOBAL, PROJECT
|
|
98
|
+
- `CustomizationType` - Enum: COMMAND, AGENT, SKILL, RULES, MCP, TOOL, PLUGIN
|
|
99
|
+
|
|
100
|
+
### Services
|
|
101
|
+
- `ConfigDiscoveryService` - Scans filesystem, uses parsers
|
|
102
|
+
- `FilterService` - Filters by level and search query
|
|
103
|
+
- `ICustomizationParser` - Protocol for type-specific parsers
|
|
104
|
+
|
|
105
|
+
### Widgets
|
|
106
|
+
- `TypePanel` - List panel with selection
|
|
107
|
+
- `CombinedPanel` - Tabbed panel for multiple types
|
|
108
|
+
- `DetailPane` - Content display with syntax highlighting
|
|
109
|
+
- `StatusPanel` - Shows current path and filter
|
|
110
|
+
- `AppFooter` - Keyboard shortcuts
|
|
111
|
+
|
|
112
|
+
### Mixins
|
|
113
|
+
- `NavigationMixin` - Panel focus, cursor movement
|
|
114
|
+
- `FilterMixin` - Level filters, search
|
|
115
|
+
- `HelpMixin` - Help overlay
|
|
116
|
+
|
|
117
|
+
## Testing
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
# Run all tests
|
|
121
|
+
uv run pytest
|
|
122
|
+
|
|
123
|
+
# Run with coverage
|
|
124
|
+
uv run pytest --cov=lazyopencode
|
|
125
|
+
|
|
126
|
+
# Run specific test file
|
|
127
|
+
uv run pytest tests/unit/test_parsers.py
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Test Structure
|
|
131
|
+
- `tests/unit/` - Unit tests for models, services, parsers
|
|
132
|
+
- `tests/integration/` - App integration tests
|
|
133
|
+
- `tests/conftest.py` - Shared fixtures
|
|
134
|
+
|
|
135
|
+
## Dependencies
|
|
136
|
+
|
|
137
|
+
### Runtime
|
|
138
|
+
- `textual>=0.89.0` - TUI framework
|
|
139
|
+
- `rich>=13.0.0` - Terminal formatting
|
|
140
|
+
- `pyyaml>=6.0` - YAML/frontmatter parsing
|
|
141
|
+
|
|
142
|
+
### Development
|
|
143
|
+
- `pytest` - Testing
|
|
144
|
+
- `pytest-asyncio` - Async test support
|
|
145
|
+
- `ruff` - Linting and formatting
|
|
146
|
+
|
|
147
|
+
## Adding New Features
|
|
148
|
+
|
|
149
|
+
### Adding a new customization type
|
|
150
|
+
1. Add enum value to `CustomizationType`
|
|
151
|
+
2. Create parser in `services/parsers/`
|
|
152
|
+
3. Register parser in `ConfigDiscoveryService`
|
|
153
|
+
4. Add panel or tab in widgets
|
|
154
|
+
|
|
155
|
+
### Adding a new keybinding
|
|
156
|
+
1. Add binding to `bindings.py`
|
|
157
|
+
2. Implement `action_*` method in appropriate mixin
|
|
158
|
+
3. Update help text
|
|
159
|
+
|
|
160
|
+
### Adding a new widget
|
|
161
|
+
1. Create widget in `widgets/`
|
|
162
|
+
2. Add styles to `styles/app.tcss`
|
|
163
|
+
3. Compose in `app.py`
|
|
164
|
+
|
|
165
|
+
## Planning Documents
|
|
166
|
+
|
|
167
|
+
See `_plans/` directory for detailed specifications:
|
|
168
|
+
- `00-overview.md` - Project overview
|
|
169
|
+
- `01-architecture.md` - Architecture decisions
|
|
170
|
+
- `02-customization-types.md` - OpenCode customization mapping
|
|
171
|
+
- `03-implementation-phases.md` - Implementation plan
|
|
172
|
+
- `04-file-structure.md` - File structure
|
|
173
|
+
- `05-agents-md-template.md` - This template
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 nikiforovall
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|