@snarkipus/opencode-beads 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +150 -0
- package/dist/init/artifacts/beads/SKILL.md +16 -0
- package/dist/init/artifacts/beads/references/DEPENDENCIES.md +5 -0
- package/dist/init/artifacts/beads/references/ISSUE_CREATION.md +5 -0
- package/dist/init/artifacts/beads/references/RESUMABILITY.md +5 -0
- package/dist/init/manifest.json +54 -0
- package/package.json +82 -0
- package/src/init-cli.ts +172 -0
- package/src/init.ts +700 -0
- package/src/plugin-core.ts +290 -0
- package/src/plugin.ts +150 -0
- package/src/prime.ts +88 -0
- package/src/skill-collision-policy.ts +133 -0
- package/src/vendor-adaptations.ts +146 -0
- package/src/vendor-provenance.ts +252 -0
- package/src/vendor.ts +297 -0
- package/vendor/agents/task-agent.md +61 -0
- package/vendor/commands/audit.md +28 -0
- package/vendor/commands/blocked.md +15 -0
- package/vendor/commands/close.md +18 -0
- package/vendor/commands/comments.md +30 -0
- package/vendor/commands/compact.md +31 -0
- package/vendor/commands/create.md +19 -0
- package/vendor/commands/decision.md +111 -0
- package/vendor/commands/delete.md +32 -0
- package/vendor/commands/dep.md +101 -0
- package/vendor/commands/epic.md +27 -0
- package/vendor/commands/export.md +25 -0
- package/vendor/commands/import.md +18 -0
- package/vendor/commands/init.md +18 -0
- package/vendor/commands/label.md +33 -0
- package/vendor/commands/list.md +64 -0
- package/vendor/commands/prime.md +10 -0
- package/vendor/commands/quickstart.md +13 -0
- package/vendor/commands/ready.md +15 -0
- package/vendor/commands/rename-prefix.md +24 -0
- package/vendor/commands/reopen.md +22 -0
- package/vendor/commands/restore.md +27 -0
- package/vendor/commands/search.md +103 -0
- package/vendor/commands/show.md +17 -0
- package/vendor/commands/stats.md +17 -0
- package/vendor/commands/sync.md +17 -0
- package/vendor/commands/template.md +337 -0
- package/vendor/commands/update.md +24 -0
- package/vendor/commands/version.md +26 -0
- package/vendor/commands/workflow.md +58 -0
- package/vendor/manifest.json +168 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Josh Thomas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# opencode-beads
|
|
2
|
+
|
|
3
|
+
[Beads](https://github.com/gastownhall/beads) issue tracker integration for [OpenCode](https://opencode.ai).
|
|
4
|
+
|
|
5
|
+
This maintained fork provides the OpenCode-facing product layer around Beads: full `bd prime` context injection, vendored workflows, an autonomous task agent, project-scoped runtime integration, and an explicit managed companion skill lifecycle. It is deliberately an adapter rather than a second issue tracker: the `bd` CLI remains authoritative for issues, Dolt synchronization, migrations, and general Beads behavior.
|
|
6
|
+
|
|
7
|
+
The project originated as [Josh Thomas's `opencode-beads`](https://github.com/joshuadavidthomas/opencode-beads) and continues under the MIT license. This fork is maintained by Matt Jackson and tracks reviewed upstream Beads releases while adapting their plugin artifacts to OpenCode's CLI-only execution model.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Install the beads CLI:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
curl -fsSL https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh | bash
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
See the [Beads installation guide](https://github.com/gastownhall/beads/blob/main/docs/getting-started/installation.md) for alternative methods (Homebrew, Windows, AUR, etc.).
|
|
18
|
+
|
|
19
|
+
Add the version-pinned plugin to your OpenCode config (`~/.config/opencode/opencode.json`):
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"plugin": ["@snarkipus/opencode-beads@0.8.0"]
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Restart OpenCode. OpenCode caches pinned plugins, so update this version explicitly when upgrading. An unpinned `@snarkipus/opencode-beads` entry follows npm updates on startup but is less reproducible.
|
|
28
|
+
|
|
29
|
+
In a project without a Beads database, run `/beads:init` or `bd init` before using issue commands. This initializes Beads data only; it does not install the companion OpenCode skill.
|
|
30
|
+
|
|
31
|
+
### Optional skill
|
|
32
|
+
|
|
33
|
+
Install the companion OpenCode skill for durable Beads guidance in the current Git worktree:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bunx @snarkipus/opencode-beads@0.8.0 init
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The project target is `<worktree>/.opencode/skills/beads`, even when the command runs from a nested directory. Use `init --global` for `$XDG_CONFIG_HOME/opencode/skills/beads` when `XDG_CONFIG_HOME` is absolute, otherwise `~/.config/opencode/skills/beads`.
|
|
40
|
+
|
|
41
|
+
The package CLI is the canonical lifecycle because OpenCode does not guarantee that plugin npm bins are on `PATH`:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bunx @snarkipus/opencode-beads@0.8.0 init [--global]
|
|
45
|
+
bunx @snarkipus/opencode-beads@0.8.0 check [--global]
|
|
46
|
+
bunx @snarkipus/opencode-beads@0.8.0 update [--global]
|
|
47
|
+
bunx @snarkipus/opencode-beads@0.8.0 remove [--global]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Every command supports `--dry-run` for an exact non-mutating plan and `--json` for one deterministic result object. Add `--global` to select the global scope. `/beads:setup` prints commands for the running package version; it does not write files. `/beads:init` remains DB-only.
|
|
51
|
+
|
|
52
|
+
Lifecycle states are:
|
|
53
|
+
|
|
54
|
+
| State | Meaning |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `missing` | The selected target does not exist. |
|
|
57
|
+
| `current` | The ownership manifest, package metadata, inventory, and file hashes match. |
|
|
58
|
+
| `stale` | The target is recognized and unmodified, but its managed package or provenance metadata differs from the running package. |
|
|
59
|
+
| `modified` | The target has a recognized manifest, but a managed file, hash, symlink, or inventory differs. |
|
|
60
|
+
| `conflicting` | The target is unmanaged or differently managed, another discovered Beads skill blocks the operation, or stale transaction residue exists. |
|
|
61
|
+
|
|
62
|
+
`init` installs a missing target or safely refreshes a recognized stale target. `update` changes only a recognized stale target whose old managed hashes still match. `init` and `update` are no-ops for current targets. `remove` deletes only a recognized, unmodified current or stale target. Modified and conflicting targets are never overwritten or removed, and there is no force option.
|
|
63
|
+
|
|
64
|
+
Before `init` or `update`, discovery checks `.opencode/skills/beads`, `.agents/skills/beads`, and `.claude/skills/beads` from the current directory through the Git worktree root, plus their global equivalents. Unrelated discovered skills block writes. `remove` may remove the selected verified-owned target despite an unrelated skill elsewhere, but stale transaction residue still blocks it.
|
|
65
|
+
|
|
66
|
+
The lifecycle is fully offline from immutable package artifacts. Updates use sibling staging, backup, and recovery directories so caught filesystem errors restore the prior installation; this does not claim crash-proof atomicity across multiple renames. OpenCode does not discover skills inside npm packages, so passive npm discovery is unsupported. Plugin startup is read-only and never installs, updates, or removes skill files automatically.
|
|
67
|
+
|
|
68
|
+
CLI exit codes are stable:
|
|
69
|
+
|
|
70
|
+
| Exit | Meaning |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `0` | Lifecycle command succeeded, or `check` found the current managed skill. |
|
|
73
|
+
| `1` | `check` found a missing, stale, modified, or conflicting skill. |
|
|
74
|
+
| `2` | Invalid usage, lifecycle refusal, package validation failure, git discovery failure, or operational error. |
|
|
75
|
+
|
|
76
|
+
With `--json`, every exit writes exactly one JSON object plus a trailing newline to stdout and writes nothing to stderr. The stable `code` and `message` fields classify success, non-current checks, refusals, usage errors, discovery failures, package failures, and other operational failures.
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
- **Context injection** - Loads the canonical Beads workflow and persistent memories on session start and after compaction
|
|
81
|
+
- **Commands** - Vendored Beads workflows plus native `/beads:setup`, available under the `/beads:*` namespace
|
|
82
|
+
- **Task agent** - Autonomous issue completion via `beads-task-agent` subagent
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
This plugin is a thin OpenCode adapter. For Beads workflows, CLI commands, Dolt operations, migrations, backups, and issue-tracking concepts, use the [upstream documentation](https://github.com/gastownhall/beads) or run `bd prime`.
|
|
87
|
+
|
|
88
|
+
### Context behavior
|
|
89
|
+
|
|
90
|
+
The plugin runs full `bd prime` when a primary-agent session first receives a message and after compaction, matching the canonical workflow pattern used by the upstream Claude Code and Codex integrations. The prime output supplies the current workflow, command guidance, and persistent memories; a compact shared layer adds only OpenCode-specific CLI safety and primary-agent delegation. Regular task subagents such as `explore` and `general` are deliberately skipped, while the included `beads-task-agent` remains explicitly eligible.
|
|
91
|
+
|
|
92
|
+
If `bd` is unavailable, the project is not initialized, or prime fails or returns no content, context injection is silently skipped and remains retryable. Vendored commands remain visible, the runtime does not initialize Beads or write startup files, and the task agent retains a bounded standalone quick reference for `ready`, `show`, atomic claim, discovered follow-up, and close. That fallback tells the agent to run `bd prime` when injected context is missing or stale; it does not duplicate the full live workflow.
|
|
93
|
+
|
|
94
|
+
## Commands
|
|
95
|
+
|
|
96
|
+
Commands are available as `/beads:<name>`, for example `/beads:ready`, `/beads:create`, and `/beads:show`. The plugin vendors every command template published by the upstream Beads plugin; it does not generate an OpenCode command for every `bd` subcommand. Use the `bd` CLI for the complete command surface and consult the generated [CLI reference](https://beads.gascity.com/cli-reference/index).
|
|
97
|
+
|
|
98
|
+
Explicit command and agent definitions in your OpenCode configuration take precedence over plugin-provided definitions with the same name. The plugin emits a grouped, rate-limited warning for exact `beads:*` or `beads-task-agent` collisions while continuing to register every non-conflicting definition.
|
|
99
|
+
|
|
100
|
+
This configuration precedence is separate from skill-file collision safety. User-defined commands and agents win without blocking plugin startup; unmanaged, differently managed, or modified skill files instead cause the explicit companion CLI operation to refuse without mutation.
|
|
101
|
+
|
|
102
|
+
## Agent
|
|
103
|
+
|
|
104
|
+
### beads-task-agent
|
|
105
|
+
|
|
106
|
+
A subagent for read-only status and graph analysis or one-bead task completion. Analysis requests never mutate beads; completion requests inspect and process one caller-selected or highest-priority ready bead, quarantine work created during that invocation, and return after closing or blocking the selected bead. Its configured prompt is role-specific; session injection supplies the shared CLI and lifecycle safety rules once.
|
|
107
|
+
|
|
108
|
+
## Compatibility
|
|
109
|
+
|
|
110
|
+
The compatibility ranges and validated baselines for this release are:
|
|
111
|
+
|
|
112
|
+
| Component | Expected range | Validated baseline |
|
|
113
|
+
| --- | --- | --- |
|
|
114
|
+
| OpenCode | 1.18.3 through 1.x | 1.18.4 |
|
|
115
|
+
| `bd` CLI | 1.0.5 through 1.x | 1.1.0 |
|
|
116
|
+
| Bun | >=1.3.14 | 1.3.14 |
|
|
117
|
+
|
|
118
|
+
The OpenCode adapter builds against the exact paired `@opencode-ai/plugin` and `@opencode-ai/sdk` `1.18.4` releases and declares compatible optional peers from `1.18.3` through the stable `1.x` line. Both imports are type-only; the package does not install a second OpenCode runtime. The command, agent, and managed-skill provenance is currently synced from Beads v1.1.0. Newer compatible releases may work but are not guaranteed until validated; when diagnosing a regression, reproduce it with the baselines above.
|
|
119
|
+
|
|
120
|
+
## Vendored Content
|
|
121
|
+
|
|
122
|
+
Files under `vendor/` are copied from the upstream Beads plugin by [`scripts/sync-beads.sh`](scripts/sync-beads.sh). The current inventory includes the complete upstream command-template directory and task agent, rather than a duplicate of the much larger `bd` CLI. [`vendor/manifest.json`](vendor/manifest.json) records the stable upstream tag and commit, source paths, sorted inventory, byte lengths, and SHA-256 checksums. A deterministic adaptation layer translates known MCP- or Claude-specific instructions to OpenCode's CLI-only model when prompts load; sync fails if provenance, checksums, inventory, or reviewed transformations differ. Do not edit vendored files directly: the next sync replaces them. Adapter behavior lives in `src/`, while general Beads behavior and documentation remain upstream.
|
|
123
|
+
|
|
124
|
+
The vendor manifest, task agent, and every recorded command file are required package content. The separately reviewed skill fork records exact upstream source paths and hashes mapped to each adapted output in `dist/init/manifest.json`; these mappings, the output inventory, and output hashes are all strict package inputs. Initialization fails with the artifact path and validation reason if required content is missing or malformed. Command frontmatter supports `description`, `argument-hint`, `agent`, `model`, and `subtask`; task-agent frontmatter supports `description`, `mode: subagent`, `model`, `temperature`, `top_p`, `disable`, `color`, and `maxSteps`. Unsupported fields or shapes fail validation so upstream changes receive explicit review. Reinstall the package or rerun the sync script from a source checkout rather than repairing generated files by hand.
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
- **No Beads context:** Run `bd prime` in the project. Install `bd` if the command is missing, or run `bd init` if the project has no Beads workspace.
|
|
129
|
+
- **Managed skill is missing:** Run `bunx @snarkipus/opencode-beads@0.8.0 init [--global]`. Use the same scope for later lifecycle commands.
|
|
130
|
+
- **Managed skill is stale:** Run `bunx @snarkipus/opencode-beads@0.8.0 update [--global]`. The command proceeds only if every old managed hash still matches.
|
|
131
|
+
- **Managed skill is modified:** Preserve or revert local edits before retrying. To discard an installation deliberately, move the entire target out of every OpenCode discovery root, then run `init`; no force mode exists.
|
|
132
|
+
- **Managed skill is conflicting:** Run `check --json` with the intended scope and inspect `target` and `collisions`. Move or remove unmanaged or differently managed Beads skills deliberately, then retry. Do not treat another discovery root as the selected target.
|
|
133
|
+
- **Stale transaction residue:** Preserve and inspect sibling `.beads.opencode-beads-stage-*`, `-backup-*`, or `-recovery-*` directories before manual recovery. The CLI refuses to guess which residue is authoritative.
|
|
134
|
+
- **Global target is unexpected:** Use an absolute `XDG_CONFIG_HOME` for `$XDG_CONFIG_HOME/opencode/skills/beads`; relative or absent values intentionally fall back to `~/.config/opencode/skills/beads`. Global `.agents` and `.claude` roots remain under the home directory.
|
|
135
|
+
- **Lifecycle reports package validation failure:** Reinstall the exact scoped package version. The CLI will not install from missing, unexpected, or checksum-invalid packaged artifacts.
|
|
136
|
+
- **Lifecycle cannot discover Git:** Run the command inside the intended Git worktree. Project and global lifecycle operations both require a worktree boundary for collision discovery.
|
|
137
|
+
- **Vendor artifact initialization error:** Reinstall the package. If using a source checkout, rerun the vendor sync and validation scripts; the error names the missing or malformed manifest, command, or task-agent file.
|
|
138
|
+
- **Unexpected command or agent definition:** Check the OpenCode configuration for a colliding `beads:*` or `beads-task-agent` entry. Your explicit configuration wins on an exact name collision; OpenCode logs a rate-limited warning naming the collision.
|
|
139
|
+
- **A regular subagent has no Beads context:** This is intentional. Delegate Beads work to `beads-task-agent`, or run the required `bd` command explicitly.
|
|
140
|
+
- **Behavior changed after an upgrade:** Compare `opencode --version`, `bd version`, and `bun --version` with the compatibility table, then check the [Beads releases](https://github.com/gastownhall/beads/releases) and this project's changelog.
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
opencode-beads is licensed under the MIT license. See the [`LICENSE`](LICENSE) file for more information.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
opencode-beads is not built by, or affiliated with, the OpenCode team.
|
|
149
|
+
|
|
150
|
+
OpenCode is ©2025 Anomaly.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: beads
|
|
3
|
+
description: Use when managing work with the bd CLI, especially "create task", "what's ready", "track this work", dependencies, blockers, multi-session work, or recovery after compaction.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Beads
|
|
7
|
+
|
|
8
|
+
Use `bd` through the shell for issue tracking. Run `bd prime` for the current project workflow and `bd <command> --help` for current command syntax.
|
|
9
|
+
|
|
10
|
+
Keep issue state in Beads rather than parallel TODO files. Claim work before implementation, validate before closing it, and record discovered follow-up with its dependency relationship.
|
|
11
|
+
|
|
12
|
+
## References
|
|
13
|
+
|
|
14
|
+
- [Dependencies](references/DEPENDENCIES.md)
|
|
15
|
+
- [Issue creation](references/ISSUE_CREATION.md)
|
|
16
|
+
- [Resumability](references/RESUMABILITY.md)
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
|
|
3
|
+
Model ordering and discovery relationships in Beads so `bd ready` reflects genuinely unblocked work. Use `bd dep --help` for current dependency commands and types; do not infer direction from prose alone.
|
|
4
|
+
|
|
5
|
+
When implementation reveals separate follow-up, create it with a `discovered-from` relationship to the issue that exposed it. Avoid dependencies between work that can proceed independently.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Issue Creation
|
|
2
|
+
|
|
3
|
+
Create durable work with enough context, acceptance criteria, and priority for another session to act without reconstructing intent. Select the issue type that describes the work, not the current activity.
|
|
4
|
+
|
|
5
|
+
Use `bd create --help` for current flags and `--json` when structured output improves reliability. Search existing issues before creating a duplicate.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Resumability
|
|
2
|
+
|
|
3
|
+
Keep issue state useful across sessions: claim before changing code, record material findings and blockers, and close only after validation. Leave concise notes when the next step is not evident from the issue itself.
|
|
4
|
+
|
|
5
|
+
Use `bd prime` for the current lifecycle policy and `bd <command> --help` for syntax. Do not make automatic commit, push, or sync behavior part of issue completion.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"owner": "opencode-beads",
|
|
4
|
+
"upstream": {
|
|
5
|
+
"repository": "https://github.com/gastownhall/beads.git",
|
|
6
|
+
"tag": "v1.1.0",
|
|
7
|
+
"commit": "8e4e59d39f3459a43cf21a3236a13eca4dd874f7"
|
|
8
|
+
},
|
|
9
|
+
"adaptationRevision": 1,
|
|
10
|
+
"sources": [
|
|
11
|
+
{
|
|
12
|
+
"source": "plugins/beads/skills/beads/SKILL.md",
|
|
13
|
+
"sourceSha256": "01555fe65d19be401d820d9dec029cd048fb0791d433b4b575374477d6f1d827",
|
|
14
|
+
"target": "SKILL.md"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"source": "plugins/beads/skills/beads/resources/DEPENDENCIES.md",
|
|
18
|
+
"sourceSha256": "9c3327611bfbdc47124736dd0cc928bfeff1c135d4ae79d4ea46cba1900df335",
|
|
19
|
+
"target": "references/DEPENDENCIES.md"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"source": "plugins/beads/skills/beads/resources/ISSUE_CREATION.md",
|
|
23
|
+
"sourceSha256": "ff465ed1fb13fbb6c42b42ec15c1bd8fd677c4661237e4fc1675c179f7fca460",
|
|
24
|
+
"target": "references/ISSUE_CREATION.md"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"source": "plugins/beads/skills/beads/resources/RESUMABILITY.md",
|
|
28
|
+
"sourceSha256": "8a7db4e967ace1b4f60dc85e3fb2d02f70749a18056fe90c61b2685bb172d7df",
|
|
29
|
+
"target": "references/RESUMABILITY.md"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"files": [
|
|
33
|
+
{
|
|
34
|
+
"path": "SKILL.md",
|
|
35
|
+
"bytes": 710,
|
|
36
|
+
"sha256": "55a99d3f7bbfdd8dbf71097905086260455d7e14c7d133304b6645b930d16df3"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"path": "references/DEPENDENCIES.md",
|
|
40
|
+
"bytes": 412,
|
|
41
|
+
"sha256": "4befbc8d17df863d3f8af7af934f7c503e66af2e3893d9fadd8c7ef156271e77"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "references/ISSUE_CREATION.md",
|
|
45
|
+
"bytes": 376,
|
|
46
|
+
"sha256": "5f7e2c73a2d206478c469a8777071a99c8a83f0a2970da3e8af56b2bcfcabb75"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"path": "references/RESUMABILITY.md",
|
|
50
|
+
"bytes": 400,
|
|
51
|
+
"sha256": "782053cb6c091d3a87c1e4dc6b0cf3777bd1321b8a92ad38fe6351116b6fa363"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@snarkipus/opencode-beads",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A maintained OpenCode integration for the Beads issue tracker, including context injection, vendored workflows, a task agent, and managed skill lifecycle tooling.",
|
|
6
|
+
"author": "Matt Jackson",
|
|
7
|
+
"contributors": [
|
|
8
|
+
{
|
|
9
|
+
"name": "Josh Thomas",
|
|
10
|
+
"url": "https://github.com/joshuadavidthomas"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/snarkipus/opencode-beads.git"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/snarkipus/opencode-beads#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/snarkipus/opencode-beads/issues"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"opencode",
|
|
27
|
+
"plugin",
|
|
28
|
+
"beads",
|
|
29
|
+
"agent",
|
|
30
|
+
"ai"
|
|
31
|
+
],
|
|
32
|
+
"main": "./src/plugin.ts",
|
|
33
|
+
"types": "./src/plugin.ts",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./src/plugin.ts",
|
|
37
|
+
"import": "./src/plugin.ts"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"src",
|
|
42
|
+
"vendor",
|
|
43
|
+
"dist",
|
|
44
|
+
"README.md",
|
|
45
|
+
"LICENSE"
|
|
46
|
+
],
|
|
47
|
+
"bin": {
|
|
48
|
+
"opencode-beads": "src/init-cli.ts"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"test": "bun test",
|
|
52
|
+
"test:docs": "bun test tests/docs.test.ts",
|
|
53
|
+
"test:package": "bun scripts/test-package.ts",
|
|
54
|
+
"test:provenance": "bun test tests/provenance.test.ts",
|
|
55
|
+
"test:release": "bun test tests/release.test.ts",
|
|
56
|
+
"test:vendor": "bun scripts/validate-vendor.ts vendor",
|
|
57
|
+
"typecheck": "tsc --noEmit"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@opencode-ai/plugin": ">=1.18.3 <2",
|
|
61
|
+
"@opencode-ai/sdk": ">=1.18.3 <2"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"@opencode-ai/plugin": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"@opencode-ai/sdk": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@opencode-ai/plugin": "1.18.4",
|
|
73
|
+
"@opencode-ai/sdk": "1.18.4",
|
|
74
|
+
"@types/bun": "1.3.4",
|
|
75
|
+
"@types/node": "^22.0.0",
|
|
76
|
+
"typescript": "5.9.3"
|
|
77
|
+
},
|
|
78
|
+
"packageManager": "bun@1.3.14",
|
|
79
|
+
"engines": {
|
|
80
|
+
"bun": ">=1.3.14"
|
|
81
|
+
}
|
|
82
|
+
}
|
package/src/init-cli.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { runInitCommand, type InitCommand, type InitScope } from "./init";
|
|
7
|
+
|
|
8
|
+
const USAGE = "Usage: opencode-beads <init|check|update|remove> [--global] [--dry-run] [--json]";
|
|
9
|
+
const VALID_COMMANDS: InitCommand[] = ["init", "check", "update", "remove"];
|
|
10
|
+
const VALID_FLAGS = new Set(["--global", "--dry-run", "--json"]);
|
|
11
|
+
|
|
12
|
+
interface CliOptions {
|
|
13
|
+
command: InitCommand;
|
|
14
|
+
scope: InitScope;
|
|
15
|
+
dryRun: boolean;
|
|
16
|
+
json: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type CliErrorCode =
|
|
20
|
+
| "GIT_DISCOVERY_FAILED"
|
|
21
|
+
| "OPERATION_FAILED"
|
|
22
|
+
| "PACKAGED_ARTIFACT_INVALID"
|
|
23
|
+
| "USAGE";
|
|
24
|
+
|
|
25
|
+
class CliFailure extends Error {
|
|
26
|
+
constructor(readonly code: CliErrorCode, message: string, readonly humanMessage = message) {
|
|
27
|
+
super(message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function writeJson(value: unknown): void {
|
|
32
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parseArgs(args: string[]): CliOptions {
|
|
36
|
+
const commands = args.filter((arg) => !arg.startsWith("--"));
|
|
37
|
+
const flags = args.filter((arg) => arg.startsWith("--"));
|
|
38
|
+
const command = commands[0];
|
|
39
|
+
if (
|
|
40
|
+
commands.length !== 1 ||
|
|
41
|
+
!VALID_COMMANDS.includes(command as InitCommand) ||
|
|
42
|
+
flags.some((flag) => !VALID_FLAGS.has(flag)) ||
|
|
43
|
+
new Set(flags).size !== flags.length
|
|
44
|
+
) {
|
|
45
|
+
throw new Error(USAGE);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
command: command as InitCommand,
|
|
49
|
+
scope: flags.includes("--global") ? "global" : "project",
|
|
50
|
+
dryRun: flags.includes("--dry-run"),
|
|
51
|
+
json: flags.includes("--json"),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function discoverWorktree(cwd: string): Promise<string> {
|
|
56
|
+
try {
|
|
57
|
+
const process = Bun.spawn(["git", "rev-parse", "--show-toplevel"], {
|
|
58
|
+
cwd,
|
|
59
|
+
stdout: "pipe",
|
|
60
|
+
stderr: "ignore",
|
|
61
|
+
});
|
|
62
|
+
const output = await new Response(process.stdout).text();
|
|
63
|
+
if ((await process.exited) !== 0 || !output.trim()) throw new Error("git failed");
|
|
64
|
+
return resolve(output.trim());
|
|
65
|
+
} catch {
|
|
66
|
+
throw new CliFailure("GIT_DISCOVERY_FAILED", "Unable to discover git worktree from cwd");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Run the companion lifecycle CLI and return its process exit code. */
|
|
71
|
+
export async function runCli(
|
|
72
|
+
args = process.argv.slice(2),
|
|
73
|
+
environment: {
|
|
74
|
+
cwd?: string;
|
|
75
|
+
home?: string;
|
|
76
|
+
packageRoot?: string;
|
|
77
|
+
xdgConfigHome?: string;
|
|
78
|
+
} = {}
|
|
79
|
+
): Promise<number> {
|
|
80
|
+
const jsonRequested = args.includes("--json");
|
|
81
|
+
let options: CliOptions;
|
|
82
|
+
try {
|
|
83
|
+
options = parseArgs(args);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (jsonRequested) writeJson({ ok: false, code: "USAGE", message: USAGE });
|
|
86
|
+
else console.error(error instanceof Error ? error.message : String(error));
|
|
87
|
+
return 2;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const packageRoot = environment.packageRoot ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
92
|
+
let packageJson: { version?: unknown };
|
|
93
|
+
try {
|
|
94
|
+
packageJson = (await Bun.file(resolve(packageRoot, "package.json")).json()) as { version?: unknown };
|
|
95
|
+
if (typeof packageJson.version !== "string") throw new Error("Package version is missing");
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new CliFailure(
|
|
98
|
+
"PACKAGED_ARTIFACT_INVALID",
|
|
99
|
+
"Packaged artifacts failed validation",
|
|
100
|
+
error instanceof Error ? error.message : String(error)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
const cwd = resolve(environment.cwd ?? process.cwd());
|
|
104
|
+
const home = resolve(environment.home ?? homedir());
|
|
105
|
+
const xdgConfigHome = environment.xdgConfigHome ?? process.env.XDG_CONFIG_HOME;
|
|
106
|
+
const opencodeConfigDirectory =
|
|
107
|
+
xdgConfigHome && isAbsolute(xdgConfigHome)
|
|
108
|
+
? resolve(xdgConfigHome, "opencode")
|
|
109
|
+
: join(home, ".config", "opencode");
|
|
110
|
+
let result;
|
|
111
|
+
try {
|
|
112
|
+
result = await runInitCommand(options.command, {
|
|
113
|
+
cwd,
|
|
114
|
+
worktree: await discoverWorktree(cwd),
|
|
115
|
+
home,
|
|
116
|
+
opencodeConfigDirectory,
|
|
117
|
+
packageRoot,
|
|
118
|
+
packageVersion: packageJson.version,
|
|
119
|
+
scope: options.scope,
|
|
120
|
+
dryRun: options.dryRun,
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error instanceof CliFailure) throw error;
|
|
124
|
+
const humanMessage = error instanceof Error ? error.message : String(error);
|
|
125
|
+
const packaged = humanMessage.startsWith("Invalid packaged artifact");
|
|
126
|
+
throw new CliFailure(
|
|
127
|
+
packaged ? "PACKAGED_ARTIFACT_INVALID" : "OPERATION_FAILED",
|
|
128
|
+
packaged ? "Packaged artifacts failed validation" : "Lifecycle operation failed",
|
|
129
|
+
humanMessage
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
let exitCode: number;
|
|
133
|
+
let code: "CHECK_NOT_CURRENT" | "LIFECYCLE_REFUSED" | "OK";
|
|
134
|
+
let message: string;
|
|
135
|
+
if (!result.ok) {
|
|
136
|
+
exitCode = 2;
|
|
137
|
+
code = "LIFECYCLE_REFUSED";
|
|
138
|
+
message = result.error ?? "Lifecycle command refused";
|
|
139
|
+
} else if (options.command === "check" && result.state !== "current") {
|
|
140
|
+
exitCode = 1;
|
|
141
|
+
code = "CHECK_NOT_CURRENT";
|
|
142
|
+
message = "Managed skill is not current";
|
|
143
|
+
} else {
|
|
144
|
+
exitCode = 0;
|
|
145
|
+
code = "OK";
|
|
146
|
+
message = "Lifecycle command completed";
|
|
147
|
+
}
|
|
148
|
+
if (options.json) {
|
|
149
|
+
writeJson({ ...result, code, message });
|
|
150
|
+
} else if (result.ok) {
|
|
151
|
+
const verb = result.changed ? (result.dryRun ? "Would change" : "Changed") : "No change";
|
|
152
|
+
console.log(`${verb}: ${result.target} (${result.state})`);
|
|
153
|
+
} else {
|
|
154
|
+
console.error(`${result.error}: ${result.target}`);
|
|
155
|
+
}
|
|
156
|
+
return exitCode;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
const failure =
|
|
159
|
+
error instanceof CliFailure
|
|
160
|
+
? error
|
|
161
|
+
: new CliFailure(
|
|
162
|
+
"OPERATION_FAILED",
|
|
163
|
+
"Lifecycle operation failed",
|
|
164
|
+
error instanceof Error ? error.message : String(error)
|
|
165
|
+
);
|
|
166
|
+
if (options.json) writeJson({ ok: false, code: failure.code, message: failure.message });
|
|
167
|
+
else console.error(failure.humanMessage);
|
|
168
|
+
return 2;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (import.meta.main) process.exitCode = await runCli();
|