Skip to content

Commit 8d6520f

Browse files
committed
feat: initial release of opencode-pty plugin
- Add PTY session management (spawn, write, read, list, kill) - Support background process execution with interactive input - Implement rolling line buffer with regex pattern filtering - Respect OpenCode bash permission settings - Auto-cleanup PTYs on session deletion - Add comprehensive tool descriptions for AI agent
0 parents  commit 8d6520f

30 files changed

Lines changed: 1797 additions & 0 deletions

‎.gitattributes‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
name: Bug Report
3+
about: Report a bug with the opencode-pty plugin
4+
title: "[Bug]: "
5+
labels: ["bug"]
6+
assignees: ""
7+
---
8+
9+
## Description
10+
11+
A clear and concise description of what the bug is.
12+
13+
## Reproduction Steps
14+
15+
Steps to reproduce the behavior:
16+
17+
1. Configure plugin in opencode.json
18+
2. Run opencode
19+
3. Use pty_spawn with '...'
20+
4. See error
21+
22+
## Expected Behavior
23+
24+
A clear and concise description of what you expected to happen.
25+
26+
## Actual Behavior
27+
28+
A clear and concise description of what actually happens.
29+
30+
## Environment
31+
32+
- OS: [e.g. macOS 14, Ubuntu 22.04, Windows 11]
33+
- OpenCode Version: [Output of `opencode --version`]
34+
- Plugin Version: [e.g. 0.1.0]
35+
- Bun Version: [Output of `bun --version`]
36+
37+
## OpenCode Configuration
38+
39+
<details>
40+
<summary>opencode.json (sanitized)</summary>
41+
42+
```json
43+
{
44+
"$schema": "https://opencode.ai/config.json",
45+
"plugin": ["opencode-pty"],
46+
"permission": {
47+
// your permission config
48+
}
49+
}
50+
```
51+
52+
</details>
53+
54+
## Debug Logs
55+
56+
<details>
57+
<summary>Click to expand debug logs</summary>
58+
59+
To get debug logs, run OpenCode with debug logging enabled:
60+
61+
```bash
62+
opencode --log-level DEBUG --print-logs
63+
```
64+
65+
Or check log files in `~/.local/share/opencode/logs/`.
66+
67+
```
68+
[Paste relevant log output here]
69+
```
70+
71+
</details>
72+
73+
## Additional Context
74+
75+
Add any other context about the problem here.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
name: Feature Request
3+
about: Suggest a new feature or enhancement
4+
title: "[Feature]: "
5+
labels: ["enhancement"]
6+
assignees: ""
7+
---
8+
9+
## Problem Statement
10+
11+
A clear and concise description of what problem this feature would solve.
12+
13+
Example: "I'm always frustrated when..."
14+
15+
## Proposed Solution
16+
17+
A clear and concise description of what you want to happen.
18+
19+
## Alternatives Considered
20+
21+
A clear and concise description of any alternative solutions or features you've considered.
22+
23+
## Use Case
24+
25+
Describe the use case(s) this feature would enable:
26+
27+
1. ...
28+
2. ...
29+
30+
## Additional Context
31+
32+
Add any other context, screenshots, or examples about the feature request here.

‎.github/workflows/release.yml‎

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
id-token: write
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Use Node.js
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: 20
26+
27+
- name: Determine release state
28+
id: determine
29+
run: |
30+
set -euo pipefail
31+
CURRENT_VERSION=$(node -p "require('./package.json').version")
32+
echo "current_version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
33+
if git rev-parse HEAD^ >/dev/null 2>&1; then
34+
PREVIOUS_VERSION=$(node -e "const { execSync } = require('node:child_process'); try { const data = execSync('git show HEAD^:package.json', { stdio: ['ignore', 'pipe', 'ignore'] }); const json = JSON.parse(data.toString()); if (json && typeof json.version === 'string') { process.stdout.write(json.version); } } catch (error) {}")
35+
PREVIOUS_VERSION=${PREVIOUS_VERSION//$'\n'/}
36+
else
37+
PREVIOUS_VERSION=""
38+
fi
39+
echo "previous_version=$PREVIOUS_VERSION" >> "$GITHUB_OUTPUT"
40+
if [ "$CURRENT_VERSION" = "$PREVIOUS_VERSION" ]; then
41+
echo "changed=false" >> "$GITHUB_OUTPUT"
42+
else
43+
echo "changed=true" >> "$GITHUB_OUTPUT"
44+
fi
45+
git fetch --tags --force
46+
if git tag -l "v$CURRENT_VERSION" | grep -q "v$CURRENT_VERSION"; then
47+
echo "tag_exists=true" >> "$GITHUB_OUTPUT"
48+
else
49+
echo "tag_exists=false" >> "$GITHUB_OUTPUT"
50+
fi
51+
52+
- name: Install dependencies
53+
if: steps.determine.outputs.changed == 'true' && steps.determine.outputs.tag_exists == 'false'
54+
run: |
55+
npm install -g npm@latest
56+
npm install
57+
58+
- name: Type check
59+
if: steps.determine.outputs.changed == 'true' && steps.determine.outputs.tag_exists == 'false'
60+
run: npx tsc --noEmit
61+
62+
- name: Generate release notes
63+
if: steps.determine.outputs.changed == 'true' && steps.determine.outputs.tag_exists == 'false'
64+
id: release_notes
65+
run: |
66+
set -euo pipefail
67+
CURRENT_VERSION="${{ steps.determine.outputs.current_version }}"
68+
PREVIOUS_VERSION="${{ steps.determine.outputs.previous_version }}"
69+
RANGE=""
70+
COMPARE_URL=""
71+
LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || true)
72+
if [ -z "$LAST_TAG" ] && [ -n "$PREVIOUS_VERSION" ] && git rev-parse "refs/tags/v${PREVIOUS_VERSION}" >/dev/null 2>&1; then
73+
LAST_TAG="v${PREVIOUS_VERSION}"
74+
fi
75+
if [ -n "$LAST_TAG" ]; then
76+
RANGE="${LAST_TAG}..HEAD"
77+
COMPARE_URL="https://github.com/${GITHUB_REPOSITORY}/compare/${LAST_TAG}...v${CURRENT_VERSION}"
78+
fi
79+
if [ -n "$RANGE" ]; then
80+
CHANGELOG=$(git log --no-merges --pretty=format:'- %s (%h)' "$RANGE")
81+
else
82+
CHANGELOG=$(git log --no-merges --pretty=format:'- %s (%h)')
83+
fi
84+
if [ -z "$CHANGELOG" ]; then
85+
CHANGELOG="- Initial release"
86+
fi
87+
BODY_FILE=$(mktemp)
88+
{
89+
echo "## Release v${CURRENT_VERSION}"
90+
echo ""
91+
if [ -n "$COMPARE_URL" ]; then
92+
echo "Compare changes: $COMPARE_URL"
93+
echo ""
94+
fi
95+
printf "%s\n" "$CHANGELOG"
96+
echo ""
97+
echo "### Installation"
98+
echo ""
99+
echo "Add to your \`opencode.json\`:"
100+
echo ""
101+
printf '%s\n' '```json'
102+
printf '%s\n' '{'
103+
printf '%s\n' ' "$schema": "https://opencode.ai/config.json",'
104+
printf '%s\n' ' "plugin": ["opencode-pty"]'
105+
printf '%s\n' '}'
106+
printf '%s\n' '```'
107+
echo ""
108+
echo "### Update Instructions"
109+
echo ""
110+
echo "To get the latest version:"
111+
echo ""
112+
printf '%s\n' '```bash'
113+
printf '%s\n' 'rm -rf ~/.cache/opencode/node_modules/opencode-pty'
114+
printf '%s\n' 'opencode'
115+
printf '%s\n' '```'
116+
} >"$BODY_FILE"
117+
cat "$BODY_FILE"
118+
{
119+
echo "body<<EOF"
120+
cat "$BODY_FILE"
121+
echo "EOF"
122+
} >>"$GITHUB_OUTPUT"
123+
124+
- name: Create GitHub release
125+
if: steps.determine.outputs.changed == 'true' && steps.determine.outputs.tag_exists == 'false'
126+
uses: actions/create-release@v1
127+
env:
128+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
129+
with:
130+
tag_name: v${{ steps.determine.outputs.current_version }}
131+
release_name: v${{ steps.determine.outputs.current_version }}
132+
body: ${{ steps.release_notes.outputs.body }}
133+
generate_release_notes: false
134+
135+
- name: Publish to npm
136+
if: steps.determine.outputs.changed == 'true' && steps.determine.outputs.tag_exists == 'false'
137+
run: npm publish --access public --provenance

‎.gitignore‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# dependencies (bun install)
2+
node_modules
3+
4+
# output
5+
out
6+
dist
7+
*.tgz
8+
9+
# code coverage
10+
coverage
11+
*.lcov
12+
13+
# logs
14+
logs
15+
_.log
16+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17+
18+
# dotenv environment variable files
19+
.env
20+
.env.development.local
21+
.env.test.local
22+
.env.production.local
23+
.env.local
24+
25+
# caches
26+
.eslintcache
27+
.cache
28+
*.tsbuildinfo
29+
30+
# IntelliJ based IDEs
31+
.idea
32+
33+
# Finder (MacOS) folder config
34+
.DS_Store
35+
36+
# Log files
37+
*.log

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Jens
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.

0 commit comments

Comments
 (0)