From d797704fd2543fb3df860a1a98457ab9b12e947b Mon Sep 17 00:00:00 2001 From: Matt Jackson Date: Thu, 22 Oct 2026 00:59:12 +0000 Subject: [PATCH] :bookmark: bump version 1.1.0-beta.1 -> 1.1.0-beta.2 --- CHANGELOG.md | 9 +- README.md | 30 +++--- assets/oc-beads/SKILL.md | 19 ++++ assets/oc-beads/resources/CLI_REFERENCE.md | 22 ++++ assets/oc-beads/resources/RESUMABILITY.md | 9 ++ assets/oc-beads/resources/TROUBLESHOOTING.md | 22 ++++ assets/oc-beads/resources/WORKTREES.md | 5 + .../.openspec.yaml | 2 + .../design.md | 28 +++++ .../proposal.md | 26 +++++ .../specs/workflow-access/spec.md | 102 ++++++++++++++++++ .../tasks.md | 17 +++ openspec/specs/workflow-access/spec.md | 45 +++++++- package.json | 2 +- scripts/test-package.ts | 10 +- src/host.ts | 2 +- src/workflows.ts | 19 ++-- tests/docs.test.ts | 42 ++++++++ tests/host.test.ts | 46 ++++++-- tests/workflows.test.ts | 48 +++++++-- 20 files changed, 456 insertions(+), 49 deletions(-) create mode 100644 openspec/changes/archive/2026-10-22-clarify-command-semantics/.openspec.yaml create mode 100644 openspec/changes/archive/2026-10-22-clarify-command-semantics/design.md create mode 100644 openspec/changes/archive/2026-10-22-clarify-command-semantics/proposal.md create mode 100644 openspec/changes/archive/2026-10-22-clarify-command-semantics/specs/workflow-access/spec.md create mode 100644 openspec/changes/archive/2026-10-22-clarify-command-semantics/tasks.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a66507f..04a0b31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,12 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/ ## [Unreleased] +## [1.1.0-beta.2] + +### Changed +- Replace package-owned `oc-beads:status` with `oc-beads:diagnostics` without an alias; retain stats for issue overview and leave user-owned old status overrides untouched. +- Clarify compact, restore, quickstart and sync workflow purposes and compact mode/actor authority. + ## [1.1.0-beta.1] ### Added @@ -333,7 +339,8 @@ Documentation-only release; the plugin code is unchanged from 1.0.0. It updates - Josh Thomas (maintainer) -[unreleased]: https://github.com/snarkipus/opencode-beads/compare/v1.1.0-beta.1...HEAD +[unreleased]: https://github.com/snarkipus/opencode-beads/compare/v1.1.0-beta.2...HEAD +[1.1.0-beta.2]: https://github.com/snarkipus/opencode-beads/releases/tag/v1.1.0-beta.2 [1.0.2]: https://github.com/snarkipus/opencode-beads/releases/tag/v1.0.2 [1.0.1]: https://github.com/snarkipus/opencode-beads/releases/tag/v1.0.1 [1.0.0]: https://github.com/snarkipus/opencode-beads/releases/tag/v1.0.0 diff --git a/README.md b/README.md index db7f6ba..3470800 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,21 @@ [Beads](https://github.com/gastownhall/beads) issue tracker integration for [OpenCode](https://opencode.ai). -`@snarkipus/opencode-beads` is a maintained OpenCode adapter that gives OpenCode 2 the integration `bd setup claude` gives Claude Code: `bd prime` workflow context on every request, refreshed after compaction and when a session resumes, plus a bounded task agent. Published 1.0.2 completes one Bead per invocation; the beta/next candidate below follows the authorized scope. It does not replace Beads: the installed `bd` CLI remains authoritative for issues, project initialization, skills, migrations, backups, and Dolt synchronization. +`@snarkipus/opencode-beads` is a maintained OpenCode adapter that gives OpenCode 2 the integration `bd setup claude` gives Claude Code: `bd prime` workflow context on every request, refreshed after compaction and when a session resumes, plus a bounded task agent. Published 1.0.2 completes one Bead per invocation; the published beta/next release follows the authorized scope. It does not replace Beads: the installed `bd` CLI remains authoritative for issues, project initialization, skills, migrations, backups, and Dolt synchronization. This is an independent project maintained by Matt Jackson under the MIT license. It began as a fork of [Josh Thomas's `opencode-beads`](https://github.com/joshuadavidthomas/opencode-beads), and the original work remains credited to its author. 1.0 rebuilt the plugin for OpenCode 2, and development now continues here independently. It vendors nothing from upstream Beads; instead, every Beads release is checked against the `bd` behavior the plugin relies on (see [Tracking upstream Beads](#tracking-upstream-beads)). -This branch prepares **1.1.0-beta.1**, an opt-in beta for npm dist-tag `next`; publication remains pending owner approval. The beta's normal public entrypoint enables the eleven qualified operations in the native `beads` code-mode namespace on supported hosts: find, get, edges, memories, recall, claim, note, selected-field update, close, create and remember. No wrapper, internal dependency injection, manual skill copy or activation setting is needed. The opt-in is selecting the beta artifact. The published stable 1.0.2 package is unchanged. +This release is **1.1.0-beta.2**, an opt-in beta targeting npm dist-tag `next`; its integration diagnostic command is `oc-beads:diagnostics`. Beta.1 used `oc-beads:status`; the rename is documented below. The beta's normal public entrypoint enables the eleven qualified operations in the native `beads` code-mode namespace on supported hosts: find, get, edges, memories, recall, claim, note, selected-field update, close, create and remember. No wrapper, internal dependency injection, manual skill copy or activation setting is needed. The opt-in is selecting the beta artifact. The published stable 1.0.2 package is unchanged. -The beta registers 29 `oc-beads:` workflows plus `oc-beads:status` through ordinary native command registration and owns its packaged `oc-beads` skill at the installed path, with all 15 corpus resources plus CODE_MODE and ADR (17 links). User configuration/file commands retain native precedence on load and rebuild; removing an override restores the package definition. Other plugin conflicts follow native ordering. Status reports observed registration and name/description mismatches; identical-description overrides and public owner identity remain unobservable. +Beta.2 registers 29 `oc-beads:` workflows plus `oc-beads:diagnostics` through ordinary native command registration and owns its packaged `oc-beads` skill at the installed path, with all 15 corpus resources plus CODE_MODE and ADR (17 links). User configuration/file commands retain native precedence on load and rebuild; removing an override restores the package definition. Other plugin conflicts follow native ordering. Diagnostics reports observed registration and name/description mismatches; identical-description overrides and public owner identity remain unobservable. -Typed registration requires the host tool, permission and session interfaces. Status reports unavailable interfaces honestly; actual request capabilities, catalog discovery and per-operation permissions determine which operations can run. Native shell remains direct-only and cannot be called inside execute. Structured results preserve partial, failed and uncertain outcomes, and writes retain the actual session-and-agent Beads actor. Read [CODE_MODE.md](assets/oc-beads/resources/CODE_MODE.md) for composition and recovery. +Typed registration requires the host tool, permission and session interfaces. The integration diagnostic command reports unavailable interfaces honestly; actual request capabilities, catalog discovery and per-operation permissions determine which operations can run. Native shell remains direct-only and cannot be called inside execute. Structured results preserve partial, failed and uncertain outcomes, and writes retain the actual session-and-agent Beads actor. Read [CODE_MODE.md](assets/oc-beads/resources/CODE_MODE.md) for composition and recovery. -All 16 implementation tasks have parent acceptance on exact OpenCode 2.1.1 / Beads 1.3.1. The [final acceptance record](docs/code-mode-final-acceptance-vuy9.md) and [bounded installed/model evaluation](docs/opencode-installed-model-continuation-vuy9.md) retain their historical candidates and probes; this beta adds the public entrypoint and release-channel wiring. **Known limitation:** plain decline of a nested permission request does not stop the entire composition; a later independent operation can ask again. Use explicit Stop/Cancel to stop the composition. No token-saving, cross-provider checkpoint portability or multi-hour reliability claim is made. +All 16 implementation tasks have parent acceptance on exact OpenCode 2.1.1 / Beads 1.3.1. The [final acceptance record](docs/code-mode-final-acceptance-vuy9.md) and [bounded installed/model evaluation](docs/opencode-installed-model-continuation-vuy9.md) retain their historical candidates and probes; the published beta adds the public entrypoint and release-channel wiring. **Known limitation:** plain decline of a nested permission request does not stop the entire composition; a later independent operation can ask again. Use explicit Stop/Cancel to stop the composition. No token-saving, cross-provider checkpoint portability or multi-hour reliability claim is made. ## Design -The beta/next candidate uses scope-bounded task execution: +The published beta/next release uses scope-bounded task execution: - The primary OpenCode thread retains planning context, decisions, and control. - An exact assignment or explicit one-bead mode stops with that item; read-only graph requests never authorize claims or writes. @@ -41,19 +41,19 @@ The beta requires OpenCode `>=2.1.1 <2.2` and `bd` 1.3.1 or later. Exact OpenCod `bd init` owns project initialization and creates the canonical shared Beads skill at `.agents/skills/beads`, which OpenCode discovers. It also writes a minimal Beads section to `AGENTS.md` that points to `bd prime`, the same pointer Beads gives Claude Code in `CLAUDE.md`. The published stable package relies on that shared skill. The beta additionally owns its packaged `oc-beads` skill; it does not write startup files or change `.agents/skills/beads/SKILL.md`. -2. After beta publication, add the version-pinned plugin to `~/.config/opencode/opencode.json` for every project, or to a project's `.opencode/opencode.json`: +2. Add the published, version-pinned plugin to `~/.config/opencode/opencode.json` for every project, or to a project's `.opencode/opencode.json`: ```json { - "plugins": ["@snarkipus/opencode-beads@1.1.0-beta.1"] + "plugins": ["@snarkipus/opencode-beads@1.1.0-beta.2"] } ``` - To follow the beta channel after publication, use `"plugins": ["@snarkipus/opencode-beads@next"]` instead. To stay on stable, use `"plugins": ["@snarkipus/opencode-beads@latest"]` (currently 1.0.2); do not select the beta. Stable promotion requires separate approval. + To follow the published beta channel, use `"plugins": ["@snarkipus/opencode-beads@next"]` instead. To stay on stable, use `"plugins": ["@snarkipus/opencode-beads@latest"]` (currently 1.0.2); do not select the beta. Stable promotion requires separate approval. OpenCode loads configuration changes automatically. Update the pin explicitly when upgrading; an unpinned package entry is less reproducible. OpenCode 1.x plugins are not supported; use 0.10.x or earlier there. -3. Check the install: `opencode debug agents` lists `beads-task-agent`; `/oc-beads:status` reports native registration and observed capabilities. Discover `beads` through execute on a host/agent with the required permissions. +3. Check the beta.2 install: `opencode debug agents` lists `beads-task-agent`; `/oc-beads:diagnostics` reports native registration and observed capabilities. Discover `beads` through execute on a host/agent with the required permissions. An installation still pinned to beta.1 continues to use `/oc-beads:status` until explicitly upgraded. ### Plugin options @@ -63,7 +63,7 @@ Plugin options use the object form: { "plugins": [ { - "package": "@snarkipus/opencode-beads@1.1.0-beta.1", + "package": "@snarkipus/opencode-beads@1.1.0-beta.2", "options": { "luna": true, "autoMigrate": false } } ] @@ -119,7 +119,13 @@ Before running prime, the plugin checks `bd version` and the configuration-only Published stable 1.0.2 registers no slash commands; `bd setup claude` installs none either. Ask the agent to work with Beads, have it load the canonical `beads` skill that `bd init` installs at `.agents/skills/beads` (OpenCode lists it and loads it with its `skill` tool), or use the `bd` CLI and the generated [Beads CLI reference](https://beads.gascity.com/cli-reference/index) directly. Versions before 1.0.0 shipped `/beads:*` commands adapted from upstream's Claude Code plugin; they duplicated `bd prime` and the skill. -## Removal and customization in the source candidate +The commands are workflow prompts, not exact CLI aliases. In particular, init guides human onboarding, prime reuses context or requests a guarded refresh, version reports installed versions and qualification limits, decision records rationale, template discovers formulas, and workflow guides authorized work and recovery. These purposes do not imply native `bd decision`, `bd template` or `bd workflow` commands. + +Starting with beta.2, the package-owned `oc-beads:status` is removed without an alias. Use `oc-beads:diagnostics` for integration health and `oc-beads:stats` for the issue-database overview via `bd status` (alias `bd stats`). User-defined old status overrides are untouched and are not migrated; the package does not edit configuration. + +`oc-beads:compact` guides semantic issue compaction with `bd admin compact`; `bd compact` squashes Dolt history and is a different operation. Neither is conversation compaction. A bare invocation explains the workflow; action requires explicit operation and authority. See the packaged [compact guidance](assets/oc-beads/resources/TROUBLESHOOTING.md) for mode/actor boundaries and upstream help uncertainty. `oc-beads:restore` retrieves pre-compaction issue content, displaying it by default; `--apply` requires explicit authority to write it back and does not mean database backup recovery. Quickstart uses installed help and authorized context; sync guides Dolt-remote synchronization, distinct from `bd federation sync`. + +## Removal and customization Remove the plugin's `plugins` entry to unload it. Cleanup aborts owned context/process work and its event observer, then awaits the scoped agent, skill, tool and hook disposers. It is idempotent and reports disposal failures. It never promises a final checkpoint after interruption. Reload starts with fresh session/location state. Package updates/removal belong to OpenCode's package lifecycle; this plugin has no installer or recursive asset watcher. diff --git a/assets/oc-beads/SKILL.md b/assets/oc-beads/SKILL.md index 4a4f8e0..e2bf39d 100644 --- a/assets/oc-beads/SKILL.md +++ b/assets/oc-beads/SKILL.md @@ -31,6 +31,25 @@ When typed composition is available, discover current signatures through native Follow [code-mode composition](resources/CODE_MODE.md) for bounded reads, projection, ordered writes, completeness, uncertainty and decline/Stop semantics. +## Command purposes + +The package's commands are workflow prompts, not exact CLI aliases. Use +`oc-beads:diagnostics` for integration discovery, compatibility and context health +without opening a store; use `oc-beads:stats` for the issue-database overview via +`bd status` (alias `bd stats`). The old package status name has no alias; user-owned +old-name overrides remain untouched without migration. + +Broader workflows retain their purposes: init guides human onboarding, prime uses +current context or a guarded refresh, version reports installed versions and +qualification limits, decision records rationale, template discovers formulas, +and workflow guides authorized work/recovery. They do not invent absent native +commands. Quickstart uses installed `bd quickstart` help and authorized context. +Compact targets semantic `bd admin compact`, not Dolt-history `bd compact` or +conversation compaction; restore retrieves pre-compaction issue content, displaying +it by default and requiring explicit write authority for `--apply`. Sync means +Dolt-remote synchronization, distinct from `bd federation sync`. Follow the linked +CLI reference, troubleshooting, resumability and worktree guidance before action. + ## Work within the assigned scope - Read the relevant issue and its dependencies before changing tracked state. diff --git a/assets/oc-beads/resources/CLI_REFERENCE.md b/assets/oc-beads/resources/CLI_REFERENCE.md index b4be6aa..8a9d82d 100644 --- a/assets/oc-beads/resources/CLI_REFERENCE.md +++ b/assets/oc-beads/resources/CLI_REFERENCE.md @@ -18,3 +18,25 @@ If a command or flag in an old example is absent from current help, do not guess its spelling or use a hidden interface. State the limitation and use a supported equivalent only when it preserves the requested outcome and authority. A static resource cannot prove installed host behavior or package delivery. + +## Package workflows and native operations + +Package commands are workflow prompts, not exact CLI aliases. `oc-beads:diagnostics` +reports integration health without opening a store; `oc-beads:stats` guides the +issue-database overview using `bd status` (alias `bd stats`). The package's old +status command is removed without an alias; user-owned old-name overrides remain +untouched and are not migrated. + +Init guides human onboarding; prime uses supplied context or a guarded refresh; +version reports installed versions and qualification limits; decision records +rationale; template discovers formulas; workflow guides authorized work/recovery. +Do not manufacture native decision, template or workflow commands. Quickstart +uses installed `bd quickstart` help and authorized context, without implicit setup. + +Compact guides semantic `bd admin compact`, not `bd compact` Dolt-history +squashing or conversation compaction; consult TROUBLESHOOTING.md for authority, +modes, explicit actor and inconsistent upstream help. Restore retrieves +pre-compaction issue content, display-only by default; `--apply` needs explicit +write authority and is not database backup recovery (see RESUMABILITY.md). Sync +uses Dolt-remote synchronization, distinct from `bd federation sync` and removed +JSONL sync (see WORKTREES.md). Inspect installed help and preserve authority. diff --git a/assets/oc-beads/resources/RESUMABILITY.md b/assets/oc-beads/resources/RESUMABILITY.md index dc83a85..fd4d278 100644 --- a/assets/oc-beads/resources/RESUMABILITY.md +++ b/assets/oc-beads/resources/RESUMABILITY.md @@ -81,3 +81,12 @@ manual fallback. If a write timed out, read the issue before retrying; the first write may have landed. Preserve uncertainty explicitly until it is resolved. Use the current CLI syntax from `bd prime` and command help when authorized. + +## Restore pre-compaction issue content + +`oc-beads:restore` guides `bd restore` retrieval of pre-compaction issue content, +display-only by default. `--apply` requires explicit authority to write that +content back to the issue. This is not database backup recovery, Git history +restoration or general store repair. Inspect installed help and report missing +content or uncertainty honestly; conflicting compact/restore help does not +establish guaranteed recovery or reversibility. diff --git a/assets/oc-beads/resources/TROUBLESHOOTING.md b/assets/oc-beads/resources/TROUBLESHOOTING.md index fb65bf7..72741fc 100644 --- a/assets/oc-beads/resources/TROUBLESHOOTING.md +++ b/assets/oc-beads/resources/TROUBLESHOOTING.md @@ -19,6 +19,28 @@ limitation and use a documented replacement only when it preserves the needed semantics. The specialized `bd agent` and `bd slot` commands are absent from the inspected CLI; see [AGENTS.md](AGENTS.md). +## Compact operation and authority + +`oc-beads:compact` guides semantic issue compaction with `bd admin compact`. +`bd compact` squashes Dolt history and is a different operation; neither means +conversation compaction. A bare invocation explains the workflow, not authority +to act. Clarify the operation and scope when a request is ambiguous, and inspect +applicable installed help before any explicitly authorized action. + +Prefer the agent-driven analyze/apply path. `--auto` sends issue content to an +external AI provider; `--dolt` performs storage garbage collection rather than +semantic summarization. These modes each require separate explicit authority; +ordinary compact approval selects neither. Always supply explicit `--actor` +for admin compact, which has its own local default of `agent`; do not inherit +that default or the human Git identity. + +In the inspected Beads 1.3.1 help, admin compact's Usage/flags identify the semantic +operation but its examples still say `bd compact`. Its discard wording also +conflicts with restore's snapshot description. Do not copy those stale examples +or promise reversibility from that conflicting help. Report the uncertainty and +use applicable help and explicit authority for a future actual request. Do not +execute administration to validate this prose or repair upstream behavior. + ## Store, migration, or routing problem If the CLI reports no store, an outdated schema, an unexpected location, or a diff --git a/assets/oc-beads/resources/WORKTREES.md b/assets/oc-beads/resources/WORKTREES.md index ae08489..d4db2ae 100644 --- a/assets/oc-beads/resources/WORKTREES.md +++ b/assets/oc-beads/resources/WORKTREES.md @@ -17,3 +17,8 @@ Use `bd worktree --help` and relevant subcommand help for current commands and safety checks. Inspect local changes before removal, preserve work that is not yours, and remove only a worktree whose cleanup is authorized. This resource does not create or clean up a worktree automatically. + +`oc-beads:sync` guides `bd sync` Dolt-remote synchronization, distinct from +`bd federation sync` and removed JSONL sync. Inspect current help and synchronize +only with explicit authority. Report conflicts without forcing a side; the +installed Beads CLI owns synchronization and consistency semantics. diff --git a/openspec/changes/archive/2026-10-22-clarify-command-semantics/.openspec.yaml b/openspec/changes/archive/2026-10-22-clarify-command-semantics/.openspec.yaml new file mode 100644 index 0000000..7cc41bb --- /dev/null +++ b/openspec/changes/archive/2026-10-22-clarify-command-semantics/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-10-22 diff --git a/openspec/changes/archive/2026-10-22-clarify-command-semantics/design.md b/openspec/changes/archive/2026-10-22-clarify-command-semantics/design.md new file mode 100644 index 0000000..d6bdc87 --- /dev/null +++ b/openspec/changes/archive/2026-10-22-clarify-command-semantics/design.md @@ -0,0 +1,28 @@ +# Design + +## Context + +See proposal.md for motivation. The accepted plan and S1 READY recheck are recorded in Bead `opencode-beads-ghq`; source baseline is e2f1152141ce6ffb3c500e4cb3b3ec9d2bb47859. This packet captures that bounded decision, without reopening planning. + +## Goals / Non-Goals + +**Goals:** Change the package diagnostic name and six approved descriptions, preserve callback mechanics and remaining descriptions, and align current guidance and regression evidence. + +**Non-Goals:** No issue-count status command, alias, config migration, upstream repair, new administration mode/manager, live qualification, canonical spec update, archive or release. + +## Decisions + +- Replace the diagnostic registration name and callback parameter only. Keeping an old status alias would preserve the demonstrated ambiguity; repurposing it would silently add store reads. Keep payload keys, safe probes and lifecycle unchanged, with only the approved host liveQualification wording correction. +- Keep compact as the semantic issue workflow. Link its existing TROUBLESHOOTING resource for analyze/apply, separate auto/external-AI and dolt/GC authority, and explicit actor. Do not infer an operation from ambiguous approval or stale upstream examples. +- Preserve all other workflow mechanics, 29 stems, 17 supporting links and native user overrides. Use central workflow-not-argv guidance rather than invent native decision/template/workflow commands. +- Exercise real prompt bodies, native registration callbacks and packed callbacks, retaining existing scope, context, unavailable-state and unload assertions. Keep raw RED/GREEN logs in the authorized scratch directory and append evidence directly to the Bead. + +## Risks / Trade-offs + +- [Opt-in beta command rename] → Document old package-name removal, stats/diagnostics destinations and preservation of user-owned old-name overrides; do not edit configuration. +- [Upstream admin help has stale examples and conflicting recovery wording] → Explain uncertainty without running administration or promising reversibility. +- [Fixtures do not qualify another live host/model] → Reuse accepted exact OpenCode 2.1.1 evidence and retain admission/qualification limits; no new universal or 2.1.2 claim. + +## Migration Plan + +Source changes are reviewable without publication or activation. Parent reviews source and owns task acceptance, canonical sync/archive and any later separately authorized publication. Implementation task acceptance stays unchecked during this worker pass; execution progress belongs in the Bead. diff --git a/openspec/changes/archive/2026-10-22-clarify-command-semantics/proposal.md b/openspec/changes/archive/2026-10-22-clarify-command-semantics/proposal.md new file mode 100644 index 0000000..b908944 --- /dev/null +++ b/openspec/changes/archive/2026-10-22-clarify-command-semantics/proposal.md @@ -0,0 +1,26 @@ +# Proposal + +## Why + +The package's integration diagnostic command is confused with the upstream issue overview, and several workflow descriptions obscure their native operation. Apply the owner-approved command clarity plan at baseline e2f1152141ce6ffb3c500e4cb3b3ec9d2bb47859 without expanding runtime behavior. + +## What Changes + +- **BREAKING**: Replace package-owned `oc-beads:status` with `oc-beads:diagnostics`, without an alias. Retain `stats` for issue overview and preserve user-owned old-name overrides without migration. +- Keep exactly 30 package entries and the original 29 workflow stems. Explain centrally that workflows are prompts guiding permitted operations, not exact CLI aliases. +- Clarify semantic `bd admin compact`, display-only `bd restore` versus explicitly authorized `--apply`, neutral quickstart wording, and Dolt-remote sync versus federation sync. +- Document compact analyze/apply preference, separate authority for external-AI `--auto` and storage-GC `--dolt`, and explicit `--actor`. + +## Capabilities + +### New Capabilities + +None. + +### Modified Capabilities + +- `workflow-access`: amend only Discoverable selected workflows, Read-only native diagnostics, and Capability-aware actor and context guidance. + +## Impact + +Current command descriptions/registration, README, six packaged guidance files, focused tests and packed callback checks change. Diagnostics keeps existing safe probes, payload keys and lifecycle behavior; all 17 guidance links remain. No configuration migration, upstream repair, administration execution, version/dependency change, new host/model qualification, canonical spec edit or archive. Bead `opencode-beads-ghq` owns execution evidence; parent owns acceptance and closure. diff --git a/openspec/changes/archive/2026-10-22-clarify-command-semantics/specs/workflow-access/spec.md b/openspec/changes/archive/2026-10-22-clarify-command-semantics/specs/workflow-access/spec.md new file mode 100644 index 0000000..9138cbc --- /dev/null +++ b/openspec/changes/archive/2026-10-22-clarify-command-semantics/specs/workflow-access/spec.md @@ -0,0 +1,102 @@ +# Workflow Access Delta + +## MODIFIED Requirements + +### Requirement: Discoverable selected workflows + +The package-owned `oc-beads` skill, all 15 corpus resources plus CODE_MODE and ADR rationale and all 29 `oc-beads:` entries plus `oc-beads:diagnostics` (including documented replacements) SHALL have a documented native entry point that exposes its purpose and relevant supporting guidance. Advertised command and skill behavior SHALL match the installed implementation and available tools rather than assume absent MCP tools or unreachable resources. + +#### Scenario: User invokes a selected command + +- **WHEN** a user discovers and invokes an installed selected command with arguments +- **THEN** the advertised workflow receives the intended arguments through its documented native entry point +- **AND** uses available execution tools without inventing a Beads MCP tool + +#### Scenario: Task requires deeper guidance + +- **WHEN** a selected workflow directs an agent to a supporting resource +- **THEN** that resource is reachable from the installed guidance's documented base +- **AND** SKILL.md explicitly links all 15 corpus resources plus CODE_MODE and ADR rather than relying on the host’s ten-file auto-listing +- **AND** its presence alone is not reported as evidence that the model used it + +#### Scenario: Installed resource requires external access + +- **WHEN** an installed resource outside the workspace encounters external-directory ask or deny +- **THEN** the integration respects approval/rejection and reports unreachable guidance honestly without bypassing permission + +#### Scenario: Package diagnostic name is replaced + +- **WHEN** the package registers its command surface +- **THEN** exactly 30 package commands include the original 29 workflow stems and `oc-beads:diagnostics`, with `stats` retained and no package-owned `oc-beads:status` alias +- **AND** documentation directs integration-health users to diagnostics and issue-overview users to stats; user-owned old-name overrides remain untouched without configuration migration + +#### Scenario: Workflow purpose differs from native argv + +- **WHEN** a user invokes a selected workflow +- **THEN** guidance explains that workflow prompts guide permitted operations rather than act as exact CLI aliases, including broader init, prime, version, decision, template and workflow purposes +- **AND** quickstart uses neutral installed-help wording without an unsupported deprecation claim, and sync distinguishes Dolt-remote synchronization from `bd federation sync` and removed JSONL sync + +### Requirement: Read-only native diagnostics + +The package SHALL expose effective discovery, compatibility, ownership conflicts and context/persistence status through `oc-beads:diagnostics` without opening a withheld store, changing configuration or exposing credentials. Diagnostics SHALL distinguish unavailable, failed, withheld and uncertain outcomes. + +#### Scenario: Discovery collision + +- **WHEN** a user customization prevents an owned entry from taking effect +- **THEN** diagnostics reports effective names/descriptions and detectable overrides while preserving native user-config precedence +- **AND** a description mismatch may identify an override but SHALL NOT be presented as proof of ownership; public owner identity and identical-description overrides remain unobservable and are disclosed +- **AND** command registration status reflects actual registration and lookup outcomes rather than an obsolete blanket hold + +#### Scenario: Integration health and issue overview are requested + +- **WHEN** a user invokes diagnostics or stats +- **THEN** diagnostics uses only the existing safe version/context probes and cached integration state without opening a store, while stats remains an issue-overview workflow using `bd status` (alias `bd stats`) +- **AND** the diagnostic payload and observed qualification limits remain unchanged apart from user-facing command-name wording + +#### Scenario: Diagnostics is overridden or unloaded + +- **WHEN** a user override is added or removed, or package diagnostics is unloaded while pending +- **THEN** native override precedence, package restoration after override removal and disposal are preserved, user-owned old status remains untouched, and unloaded work submits no late prompt + +### Requirement: Capability-aware actor and context guidance + +The integration SHALL render actual executor identity and request capabilities, deduplicate guidance while retaining authority, and retain full prime pending measurement. It SHALL preserve the original 29 workflow stems and selected advanced/admin workflows, replacing only package-owned status with diagnostics without an alias or user-override migration, with explicit links to 16 resources plus ADR. Durable references and freshness SHALL be operation-aware. + +#### Scenario: Execute is denied + +- **WHEN** execute is wholly denied for the actual request +- **THEN** code-mode-only Beads tools are unavailable and guidance offers direct shell only if separately available and not held +- **AND** when both capabilities are unavailable the limitation is reported without bypass or invented tool access + +#### Scenario: Typed and shell writes share an executor + +- **WHEN** a primary or delegated agent alternates typed and direct-shell writes +- **THEN** context and typed results expose the same actor derived from the actual request/invocation session and agent; attribution grants no permission, and permission checks separately use actual context.agent +- **AND** child executors keep their own identities, no model-controlled actor argument exists, and beads-task-agent remains an optional execution profile + +#### Scenario: A write changes cached state + +- **WHEN** a memory write may have landed, external state changes, or recovery needs current knowledge +- **THEN** relevant location context is refreshed or its uncertainty reported +- **AND** issue-write prime refresh is retained until supported prime content is verified independent of issue state +- **AND** acknowledged writes avoid redundant generic recovery cues, while uncertain results preserve targeted readback needs + +#### Scenario: Actor or capabilities change + +- **WHEN** a request changes agent, session or effective capabilities +- **THEN** rendered actor/capability guidance is recomputed without leaking cached identity or promising unobserved permissions +- **AND** deduplication preserves distinct local authority and the required scope, stop, ownership and honest-outcome rules + +#### Scenario: Semantic issue compaction is requested + +- **WHEN** compact guidance is invoked +- **THEN** it identifies semantic `bd admin compact`, distinguishes Dolt-history squashing with `bd compact` and conversation compaction, and clarifies ambiguous operation or authority before action; bare invocation is explanation only +- **AND** linked guidance prefers agent-driven analyze/apply; `--auto` external-AI mode and `--dolt` storage garbage collection each require separate explicit authority; ordinary compact approval selects neither +- **AND** any authorized admin compact invocation supplies explicit `--actor` because its local default is agent +- **AND** guidance discloses the conflicting upstream examples and discard/restore wording without promising recovery or executing administration to validate prose + +#### Scenario: Pre-compaction issue content is retrieved + +- **WHEN** restore guidance is invoked +- **THEN** it identifies `bd restore` as pre-compaction issue-content retrieval, display-only by default, with explicit authority required for `--apply` to write content back +- **AND** it does not imply database backup recovery or guaranteed reversibility diff --git a/openspec/changes/archive/2026-10-22-clarify-command-semantics/tasks.md b/openspec/changes/archive/2026-10-22-clarify-command-semantics/tasks.md new file mode 100644 index 0000000..560ae95 --- /dev/null +++ b/openspec/changes/archive/2026-10-22-clarify-command-semantics/tasks.md @@ -0,0 +1,17 @@ +# Tasks + +Task acceptance is reserved for parent review. The implementation executor records completed source contributions and validation directly in `opencode-beads-ghq`; these boxes remain unchecked during the worker pass. + +## 1. Command clarity and current guidance + +- [x] 1.1 Accept the no-alias diagnostics registration and exact approved workflow descriptions with central workflow-not-argv guidance; verify raw RED/GREEN command-body, native registration, override/removal/disposal, no-store diagnostics and stats-workflow tests plus packed callbacks, and matching README/packaged guidance. +- [x] 1.2 Accept compact/restore/quickstart/sync guidance including TROUBLESHOOTING analyze/apply, separate auto/dolt authority and explicit actor; verify representative prompt assertions, the named TROUBLESHOOTING assertion, docs contracts and all 17 resource links. + +## 2. Integrated review evidence + +- [x] 2.1 Review focused tests, typecheck, full tests, package smoke, strict named delta/global validation, diff check and protected-file hashes; verify only allowed paths changed and qualification/publication limits remain explicit in the Bead handoff. + +## Workflow follow-up + +- Parent reviews and accepts implementation, then owns any canonical spec synchronization, archive and task closure. +- Publication or activation requires separate explicit authority. diff --git a/openspec/specs/workflow-access/spec.md b/openspec/specs/workflow-access/spec.md index ca93fd8..d0c8155 100644 --- a/openspec/specs/workflow-access/spec.md +++ b/openspec/specs/workflow-access/spec.md @@ -9,7 +9,7 @@ Owner selections apply to the complete marketplace-main corpus: core workflows a ### Requirement: Discoverable selected workflows -The package-owned `oc-beads` skill, all 15 corpus resources plus CODE_MODE and ADR rationale and all 29 `oc-beads:` entries plus status (including documented replacements) SHALL have a documented native entry point that exposes its purpose and relevant supporting guidance. Advertised command and skill behavior SHALL match the installed implementation and available tools rather than assume absent MCP tools or unreachable resources. +The package-owned `oc-beads` skill, all 15 corpus resources plus CODE_MODE and ADR rationale and all 29 `oc-beads:` entries plus `oc-beads:diagnostics` (including documented replacements) SHALL have a documented native entry point that exposes its purpose and relevant supporting guidance. Advertised command and skill behavior SHALL match the installed implementation and available tools rather than assume absent MCP tools or unreachable resources. #### Scenario: User invokes a selected command @@ -29,6 +29,18 @@ The package-owned `oc-beads` skill, all 15 corpus resources plus CODE_MODE and A - **WHEN** an installed resource outside the workspace encounters external-directory ask or deny - **THEN** the integration respects approval/rejection and reports unreachable guidance honestly without bypassing permission +#### Scenario: Package diagnostic name is replaced + +- **WHEN** the package registers its command surface +- **THEN** exactly 30 package commands include the original 29 workflow stems and `oc-beads:diagnostics`, with `stats` retained and no package-owned `oc-beads:status` alias +- **AND** documentation directs integration-health users to diagnostics and issue-overview users to stats; user-owned old-name overrides remain untouched without configuration migration + +#### Scenario: Workflow purpose differs from native argv + +- **WHEN** a user invokes a selected workflow +- **THEN** guidance explains that workflow prompts guide permitted operations rather than act as exact CLI aliases, including broader init, prime, version, decision, template and workflow purposes +- **AND** quickstart uses neutral installed-help wording without an unsupported deprecation claim, and sync distinguishes Dolt-remote synchronization from `bd federation sync` and removed JSONL sync + ### Requirement: Coherent context and authority The integration SHALL preserve applicable user and repository authority across injected workflow, skills, commands and delegated guidance. It SHALL distinguish missing or failed context from context withheld by an explicit hold, and SHALL NOT recommend bypassing a hold through manual fallback. @@ -182,18 +194,29 @@ Canonical execution SHALL allow continuation within an authorized batch or goal, ### Requirement: Read-only native diagnostics -The package SHALL expose effective discovery, compatibility, ownership conflicts and context/persistence status through a native status entry without opening a withheld store, changing configuration or exposing credentials. Diagnostics SHALL distinguish unavailable, failed, withheld and uncertain outcomes. +The package SHALL expose effective discovery, compatibility, ownership conflicts and context/persistence status through `oc-beads:diagnostics` without opening a withheld store, changing configuration or exposing credentials. Diagnostics SHALL distinguish unavailable, failed, withheld and uncertain outcomes. #### Scenario: Discovery collision - **WHEN** a user customization prevents an owned entry from taking effect -- **THEN** status reports effective names/descriptions and detectable overrides while preserving native user-config precedence +- **THEN** diagnostics reports effective names/descriptions and detectable overrides while preserving native user-config precedence - **AND** a description mismatch may identify an override but SHALL NOT be presented as proof of ownership; public owner identity and identical-description overrides remain unobservable and are disclosed - **AND** command registration status reflects actual registration and lookup outcomes rather than an obsolete blanket hold +#### Scenario: Integration health and issue overview are requested + +- **WHEN** a user invokes diagnostics or stats +- **THEN** diagnostics uses only the existing safe version/context probes and cached integration state without opening a store, while stats remains an issue-overview workflow using `bd status` (alias `bd stats`) +- **AND** the diagnostic payload and observed qualification limits remain unchanged apart from user-facing command-name wording + +#### Scenario: Diagnostics is overridden or unloaded + +- **WHEN** a user override is added or removed, or package diagnostics is unloaded while pending +- **THEN** native override precedence, package restoration after override removal and disposal are preserved, user-owned old status remains untouched, and unloaded work submits no late prompt + ### Requirement: Capability-aware actor and context guidance -The integration SHALL render actual executor identity and request capabilities, deduplicate guidance while retaining authority, and retain full prime pending measurement. It SHALL preserve all 30 human command names, overrides and selected advanced/admin workflows, with explicit links to 16 resources plus ADR. Durable references and freshness SHALL be operation-aware. +The integration SHALL render actual executor identity and request capabilities, deduplicate guidance while retaining authority, and retain full prime pending measurement. It SHALL preserve the original 29 workflow stems and selected advanced/admin workflows, replacing only package-owned status with diagnostics without an alias or user-override migration, with explicit links to 16 resources plus ADR. Durable references and freshness SHALL be operation-aware. #### Scenario: Execute is denied @@ -219,3 +242,17 @@ The integration SHALL render actual executor identity and request capabilities, - **WHEN** a request changes agent, session or effective capabilities - **THEN** rendered actor/capability guidance is recomputed without leaking cached identity or promising unobserved permissions - **AND** deduplication preserves distinct local authority and the required scope, stop, ownership and honest-outcome rules + +#### Scenario: Semantic issue compaction is requested + +- **WHEN** compact guidance is invoked +- **THEN** it identifies semantic `bd admin compact`, distinguishes Dolt-history squashing with `bd compact` and conversation compaction, and clarifies ambiguous operation or authority before action; bare invocation is explanation only +- **AND** linked guidance prefers agent-driven analyze/apply; `--auto` external-AI mode and `--dolt` storage garbage collection each require separate explicit authority; ordinary compact approval selects neither +- **AND** any authorized admin compact invocation supplies explicit `--actor` because its local default is agent +- **AND** guidance discloses the conflicting upstream examples and discard/restore wording without promising recovery or executing administration to validate prose + +#### Scenario: Pre-compaction issue content is retrieved + +- **WHEN** restore guidance is invoked +- **THEN** it identifies `bd restore` as pre-compaction issue-content retrieval, display-only by default, with explicit authority required for `--apply` to write content back +- **AND** it does not imply database backup recovery or guaranteed reversibility diff --git a/package.json b/package.json index 0c7da9f..a3a6ff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@snarkipus/opencode-beads", - "version": "1.1.0-beta.1", + "version": "1.1.0-beta.2", "type": "module", "description": "A maintained OpenCode V2 integration for the Beads issue tracker: bd prime context injection with a schema-migration guard, and a bounded task agent.", "author": "Matt Jackson", diff --git a/scripts/test-package.ts b/scripts/test-package.ts index db85123..af505e2 100644 --- a/scripts/test-package.ts +++ b/scripts/test-package.ts @@ -301,8 +301,8 @@ try { const richSkill = skills.get("oc-beads"); if (richSkill?.path !== installedSkillPath || richSkill.content !== installedSkill.content) throw new Error("Installed skill registration differs from packed asset"); if (skills.get("beads") !== userSkill) throw new Error("Shared user skill was changed"); - const expectedCommands = [...Object.keys(workflows.WORKFLOWS).map((stem) => `oc-beads:${stem}`), "oc-beads:status"].sort(); - if (commands.size !== 30 || [...commands.keys()].sort().join("\0") !== expectedCommands.join("\0")) { + const expectedCommands = [...Object.keys(workflows.WORKFLOWS).map((stem) => `oc-beads:${stem}`), "oc-beads:diagnostics"].sort(); + if (commands.has("oc-beads:status") || !commands.has("oc-beads:diagnostics") || !commands.has("oc-beads:stats") || commands.size !== 30 || [...commands.keys()].sort().join("\0") !== expectedCommands.join("\0")) { throw new Error("Packed callback did not register all 30 native command definitions"); } invoking = true; @@ -319,13 +319,13 @@ try { || submitted.files !== invocation.prompt.files || submitted.agents !== invocation.prompt.agents || submitted.skills !== invocation.prompt.skills) { throw new Error(`Packed command did not preserve native invocation: ${definition.name}`); } - if (definition.name === "oc-beads:status") { + if (definition.name === "oc-beads:diagnostics") { const status = JSON.parse(submitted.text.split("\n")[1]!); if (status.commands.registration !== "registered" || status.commands.lookup !== "available" - || !status.commands.ownership.includes("identical-description") || status.liveQualification !== "not measured by status; see release acceptance evidence" + || !status.commands.ownership.includes("identical-description") || status.liveQualification !== "not measured by diagnostics; see release acceptance evidence" || status.typedContinuity !== "enabled: qualified beta registration" || status.typedRegistration !== "registered: beads namespace, code-mode-only") { - throw new Error("Packed status did not report observed registration and qualification limits"); + throw new Error("Packed diagnostics did not report observed registration and qualification limits"); } } else if (!submitted.text.includes(JSON.stringify(installedSkillPath))) throw new Error("Packed command uses the wrong JSON-quoted installed guidance base"); } diff --git a/src/host.ts b/src/host.ts index 7f8ad50..4d3c79b 100644 --- a/src/host.ts +++ b/src/host.ts @@ -254,7 +254,7 @@ export async function setupBeads( try { effectiveSkills = ctx.skill ? (await ctx.skill.list()).data.map((entry) => String(entry.id)) : "unavailable"; } catch { effectiveSkills = "unavailable: registry lookup failed"; } return JSON.stringify({ - host: hostVersion, admission: SUPPORTED_OPENCODE_RANGE, liveQualification: "not measured by status; see release acceptance evidence", + host: hostVersion, admission: SUPPORTED_OPENCODE_RANGE, liveQualification: "not measured by diagnostics; see release acceptance evidence", commands: { registration: commandRegistration, lookup: effectiveCommands ? "available" : "failed", diff --git a/src/workflows.ts b/src/workflows.ts index cc2adef..bf3a044 100644 --- a/src/workflows.ts +++ b/src/workflows.ts @@ -16,7 +16,7 @@ export const WORKFLOWS = { blocked: ["Inspect blocked work; distinguish explicit blocked status from dependency blocking.", "DEPENDENCIES"], close: ["Close only the requested work with acceptance and validation evidence and closure authority.", "WORKFLOWS"], comments: ["Read discussion or append the requested comment/checkpoint without replacing prior notes.", "RESUMABILITY"], - compact: ["Explain or perform explicitly authorized administrative issue compaction using current CLI help; this is separate from conversation compaction.", "TROUBLESHOOTING"], + compact: ["Guide semantic issue compaction with bd admin compact only when explicitly authorized; bd compact squashes Dolt history and is a different operation. This is not conversation compaction.", "TROUBLESHOOTING"], create: ["Create the requested issue with useful description, acceptance/design and discovered-from provenance when applicable; leave it unassigned unless assignment is intentional.", "ISSUE_CREATION"], decision: ["Record the requested decision, rationale and alternatives; reference intended behavior and detailed rationale in their project-owned homes.", "INTEGRATION_PATTERNS"], delete: ["Inspect the requested deletion and its effects; delete only with explicit scoped authority, never as a substitute for closure.", "TROUBLESHOOTING"], @@ -28,15 +28,15 @@ export const WORKFLOWS = { label: ["Inspect or update only requested labels while preserving the project's taxonomy.", "CLI_REFERENCE"], list: ["Retrieve issues with the requested supported filters. Retrieval does not authorize claims or task execution.", "CLI_REFERENCE"], prime: ["Use supplied current context when available; request a guarded full-context refresh only when authorized and no hold is active.", "RESUMABILITY"], - quickstart: ["Provide onboarding using current prime/help and packaged guidance; the deprecated bd quickstart command is not assumed available.", "BOUNDARIES"], + quickstart: ["Guide onboarding with installed bd quickstart help, current authorized context and packaged guidance; do not initialize a store or assume commands unavailable in the installed CLI.", "BOUNDARIES"], ready: ["Inspect actionable work. Honor an exact assignment; claim and execute only work already within the authorized scope.", "WORKFLOWS"], "rename-prefix": ["Explain the requested project identifier migration and reference impact using current CLI help; require explicit migration authority.", "TROUBLESHOOTING"], reopen: ["Inspect current state, then reopen only the requested issue with the supplied regression/correction reason.", "WORKFLOWS"], - restore: ["Inspect supported historical retrieval/restoration in the installed Dolt-based CLI; do not assume legacy Git restore syntax or restore without authority.", "RESUMABILITY"], + restore: ["Retrieve pre-compaction issue content with bd restore; display-only by default. Use --apply only with explicit authority to write that content back; this is not database backup recovery.", "RESUMABILITY"], search: ["Search issues using supported filters; distinguish issue search from reusable memory search.", "CLI_REFERENCE"], show: ["Read requested issue details, prior notes, acceptance and dependencies without mutating them.", "RESUMABILITY"], - stats: ["Report the requested issue overview without automatically claiming work.", "CLI_REFERENCE"], - sync: ["Inspect current bd sync help: current federation synchronization differs from removed JSONL sync. Synchronize only with explicit authority; disclose conflicts without forcing a side.", "WORKTREES"], + stats: ["Report the issue-database overview using bd status (alias bd stats); use oc-beads:diagnostics for integration health. Do not claim work.", "CLI_REFERENCE"], + sync: ["Inspect current bd sync help for Dolt-remote synchronization, distinct from bd federation sync and removed JSONL sync. Synchronize only with explicit authority; disclose conflicts without forcing a side.", "WORKTREES"], template: ["Discover supported templates/formulas through installed help; replace obsolete static template syntax and do not execute a formula automatically.", "MOLECULES"], update: ["Apply only requested field changes; use an atomic claim for authorized execution and append-style progress notes. Replacement of notes is intentional, never routine.", "RESUMABILITY"], version: ["Report actual installed CLI, package and host versions and qualification limits; do not hardcode a latest version or install/upgrade anything.", "CLI_REFERENCE"], @@ -90,11 +90,12 @@ export function applyBeadsSkill(editor: SkillEditor, skill: BeadsSkill, diagnose /** Build native prompt commands, never shell/template interpolation or synthetic continuation. */ export function createBeadsCommands( session: Pick, - status: (sessionID: string) => Promise, + diagnostics: (sessionID: string) => Promise, skillPath = BEADS_SKILL_PATH, signal?: AbortSignal, ): CommandDefinition[] { const common = [ + "Workflow commands guide permitted operations, not exact CLI aliases.", "Follow repository/user authority and the exact requested scope. Do not bypass a hold with manual prime or other store access.", "Use actual request capabilities: discover the native beads namespace and compose supported daily operations in code mode when present. Native shell is direct-only; advanced/admin workflows use permissioned direct shell and current CLI help. Do not call tools.shell inside execute. Advanced guidance does not enable automation.", "Every agent-authored write, claim and heartbeat needs the host-rendered actual executor's command-scoped BEADS_ACTOR or --actor. Preserve authorship; read created_by, owner and assignee separately.", @@ -115,11 +116,11 @@ export function createBeadsCommands( }, })); commands.push({ - name: "oc-beads:status", - description: "Inspect native discovery, conflicts, compatibility and context/persistence status without opening a store.", + name: "oc-beads:diagnostics", + description: "Inspect OpenCode Beads integration discovery, conflicts, compatibility and context/persistence diagnostics without opening a store; use oc-beads:stats for the issue-database overview.", async execute(input) { if (signal?.aborted) throw new Error("Beads workflow unloaded"); - const report = await status(input.sessionID); + const report = await diagnostics(input.sessionID); if (signal?.aborted) throw new Error("Beads workflow unloaded"); await session.prompt({ ...input.prompt, sessionID: input.sessionID, delivery: input.delivery, diff --git a/tests/docs.test.ts b/tests/docs.test.ts index 3edb82f..5b3b4cb 100644 --- a/tests/docs.test.ts +++ b/tests/docs.test.ts @@ -37,6 +37,48 @@ describe("documentation contracts", () => { expect(new Set(documentedVersions)).toEqual(new Set([packageManifest.version])); }); + test("pairs the beta.2 release pin with diagnostics and preserves beta.1 migration history", () => { + expect(readme).toContain("**1.1.0-beta.2**"); + expect(readme).not.toContain("publication remains pending owner approval"); + const install = readme.split("## Installation")[1]?.split("### Plugin options")[0] ?? ""; + expect(install).toContain(`"plugins": ["${packageIdentity}"]`); + expect(install).toContain("`/oc-beads:diagnostics` reports native registration and observed capabilities"); + expect(install).not.toContain("`/oc-beads:status` reports"); + expect(readme).toContain("29 `oc-beads:` workflows plus `oc-beads:diagnostics`"); + expect(readme).toContain("Beta.1 used `oc-beads:status`"); + expect(readme).toContain("Starting with beta.2, the package-owned `oc-beads:status` is removed without an alias"); + expect(readme).not.toContain("The diagnostics rename is not included in published beta.1 or the current npm `next` artifact"); + }); + + test("documents diagnostics replacement, workflow mappings and compact/restore boundaries", async () => { + expect(readme).toContain("29 `oc-beads:` workflows plus `oc-beads:diagnostics`"); + expect(readme).toContain("package-owned `oc-beads:status` is removed without an alias"); + expect(readme).toContain("User-defined old status overrides are untouched and are not migrated"); + expect(readme).toContain("`bd status` (alias `bd stats`)"); + expect(readme).toContain("workflow prompts, not exact CLI aliases"); + expect(readme).toContain("`bd admin compact`"); + expect(readme).toContain("`bd compact` squashes Dolt history"); + expect(changelog.split("## [1.1.0-beta.1]")[0]).toContain("oc-beads:diagnostics"); + for (const file of ["assets/oc-beads/SKILL.md", "assets/oc-beads/resources/CLI_REFERENCE.md"]) { + const guidance = await fs.readFile(file, "utf8"); + expect(guidance).toContain("workflow prompts, not exact CLI aliases"); + expect(guidance).toContain("oc-beads:diagnostics"); + expect(guidance).toContain("oc-beads:stats"); + } + const troubleshooting = await fs.readFile("assets/oc-beads/resources/TROUBLESHOOTING.md", "utf8"); + expect(troubleshooting).toContain("bare invocation"); + expect(troubleshooting).toContain("examples still say `bd compact`"); + expect(troubleshooting).toContain("conflicts with restore's snapshot description"); + const restore = await fs.readFile("assets/oc-beads/resources/RESUMABILITY.md", "utf8"); + expect(restore).toContain("pre-compaction issue content"); + expect(restore).toContain("display-only by default"); + expect(restore).toMatch(/--apply[\s\S]*explicit authority[\s\S]*write/); + expect(restore).toContain("not database backup recovery"); + const worktrees = await fs.readFile("assets/oc-beads/resources/WORKTREES.md", "utf8"); + expect(worktrees).toContain("Dolt-remote synchronization"); + expect(worktrees).toContain("bd federation sync"); + }); + test("documents beta opt-in, normal public registration, stable opt-out and known Stop limits", () => { expect(readme).toContain(`${packageManifest.name}@next`); expect(readme).toContain(`${packageManifest.name}@latest`); diff --git a/tests/host.test.ts b/tests/host.test.ts index 9f88d19..16eefa3 100644 --- a/tests/host.test.ts +++ b/tests/host.test.ts @@ -918,7 +918,7 @@ describe("owned workflow registration", () => { await cleanup(); expect(c.callbacks).toEqual([config]); expect(c.commands().get(ready.name)).toBe(user); - expect(c.commands().has("oc-beads:status")).toBe(false); + expect(c.commands().has("oc-beads:diagnostics")).toBe(false); const add = mock((_definition: CommandDefinition) => {}); packageCallback({ add }); expect(add).not.toHaveBeenCalled(); @@ -926,6 +926,35 @@ describe("owned workflow registration", () => { expect(f.events.aborted()).toBe(true); }); + test("diagnostics overrides restore natively and user-owned old status survives package removal", async () => { + const f = fakeContext(); + const c = commandFixture(f); + const cleanup = await setupBeads(f.ctx, { warn: () => {} }); + expect(c.commands().size).toBe(30); + expect(c.commands().has("oc-beads:status")).toBe(false); + const diagnostics = c.commands().get("oc-beads:diagnostics")!; + expect(diagnostics.description).toBe("Inspect OpenCode Beads integration discovery, conflicts, compatibility and context/persistence diagnostics without opening a store; use oc-beads:stats for the issue-database overview."); + const oldStatus = { name: "oc-beads:status", description: "USER OLD STATUS", execute: mock(async () => {}) }; + const override = { ...diagnostics, description: "USER DIAGNOSTICS", execute: mock(async () => {}) }; + const oldConfig = (editor: { add(definition: CommandDefinition): void }) => editor.add(oldStatus); + const newConfig = (editor: { add(definition: CommandDefinition): void }) => editor.add(override); + c.callbacks.push(oldConfig, newConfig); + expect(c.commands().get(diagnostics.name)).toBe(override); + await c.commands().get(diagnostics.name)!.execute(c.invocation); + expect(override.execute).toHaveBeenCalledTimes(1); + c.callbacks.splice(c.callbacks.indexOf(newConfig), 1); + expect(c.commands().get(diagnostics.name)).toBe(diagnostics); + expect(c.commands().get(oldStatus.name)).toBe(oldStatus); + await c.commands().get(oldStatus.name)!.execute(c.invocation); + expect(oldStatus.execute).toHaveBeenCalledTimes(1); + await c.commands().get("oc-beads:stats")!.execute(c.invocation); + expect(c.prompt.mock.calls.at(-1)![0].text).toContain("issue-database overview using bd status (alias bd stats)"); + expect(c.prompt.mock.calls.at(-1)![0].text).toContain("Supporting guidance:"); + await cleanup(); + expect(c.commands().get(oldStatus.name)).toBe(oldStatus); + expect(c.commands().has(diagnostics.name)).toBe(false); + }); + test("registers after an initial lookup failure and reports observable mismatches, missing names and ownership blind spots", async () => { const f = fakeContext(); const c = commandFixture(f); @@ -934,9 +963,9 @@ describe("owned workflow registration", () => { expect(c.transform).toHaveBeenCalledTimes(1); c.failLookup(false); const ready = c.commands().get("oc-beads:ready")!; - const status = c.commands().get("oc-beads:status")!; + const diagnostics = c.commands().get("oc-beads:diagnostics")!; const report = async () => { - await status.execute(c.invocation); + await diagnostics.execute(c.invocation); const text = String(c.prompt.mock.calls.at(-1)![0].text); return JSON.parse(text.split("\n")[1]!); }; @@ -1085,7 +1114,7 @@ test("cleanup attempts every owned disposer and reports a failed disposal", asyn expect(f.events.aborted()).toBe(true); }); -test("registered status distinguishes missing, held, failed, loading and uncertain context using only config probes", async () => { +test("registered diagnostics distinguishes missing, held, failed, loading and uncertain context using only config probes", async () => { const f = fakeContext({ pluginOptions: { autoMigrate: true } }); const c = commandFixture(f); let time = 0; @@ -1102,12 +1131,13 @@ test("registered status distinguishes missing, held, failed, loading and uncerta let release: (text: string) => void = () => {}; const prime = mock(async () => new Promise((resolve) => { release = resolve; })); const cleanup = await setupBeads(f.ctx, { bd, runtime: { prime }, now: () => time, retryMs: 1, warn: () => {} }); - const status = c.commands().get("oc-beads:status")!; + const diagnostics = c.commands().get("oc-beads:diagnostics")!; const report = async () => { - await status.execute(c.invocation); + await diagnostics.execute(c.invocation); return JSON.parse(String(c.prompt.mock.calls.at(-1)![0].text).split("\n")[1]!); }; const initial = await report(); + expect(initial.liveQualification).toBe("not measured by diagnostics; see release acceptance evidence"); expect(initial.context).toBe("missing: not loaded"); expect(initial.requestCapability).toBe("unknown: no actual request observation"); await f.request("s1", "build"); @@ -1147,7 +1177,7 @@ test("registered status distinguishes missing, held, failed, loading and uncerta await cleanup(); }); -test("unload aborts an in-flight native status without submitting a late prompt", async () => { +test("unload aborts an in-flight native diagnostics without submitting a late prompt", async () => { const f = fakeContext(); const c = commandFixture(f); let signal: AbortSignal | undefined; @@ -1159,7 +1189,7 @@ test("unload aborts an in-flight native status without submitting a late prompt" return { kind: "ready" }; }, } }); - const pending = c.commands().get("oc-beads:status")!.execute(c.invocation); + const pending = c.commands().get("oc-beads:diagnostics")!.execute(c.invocation); await settle(); await cleanup(); expect(signal?.aborted).toBe(true); diff --git a/tests/workflows.test.ts b/tests/workflows.test.ts index 58ad66f..39763eb 100644 --- a/tests/workflows.test.ts +++ b/tests/workflows.test.ts @@ -221,7 +221,7 @@ describe("oc-beads guidance assets", () => { describe("packaged native workflows", () => { test("forwards exact scope and partial-handoff authority cues without selecting or claiming work", async () => { const prompt = mock(async (_input: unknown) => ({} as Awaited>)); - const commands = createBeadsCommands({ prompt }, async () => "STATUS"); + const commands = createBeadsCommands({ prompt }, async () => "DIAGNOSTICS"); // These are literal caller instructions, not a mock model or a scope interpreter. const scenarios = [ ["ready", "Execute exact fixture-1 only; stop without substitution; closure belongs to parent."], @@ -249,14 +249,17 @@ describe("packaged native workflows", () => { expect(workflows).toContain("new discoveries never expand it"); }); - test("defines exactly the selected inventory's 29 command stems plus status", async () => { + test("defines exactly the selected inventory's 29 command stems plus diagnostics", async () => { const inventory = await Bun.file("docs/claude-code-integration-inventory.json").json(); const selected = inventory.marketplace_main.files .filter((file: { path: string }) => file.path.startsWith("plugins/beads/skills/beads/commands/")) .map((file: { selected_mapping: { target: string } }) => file.selected_mapping.target).sort(); expect(Object.keys(WORKFLOWS).map((stem) => `oc-beads:${stem}`).sort()).toEqual(selected); - const commands = createBeadsCommands({ prompt: mock(async () => ({} as Awaited>)) }, async () => "STATUS"); - expect(commands.map((command) => command.name).sort()).toEqual([...selected, "oc-beads:status"].sort()); + const commands = createBeadsCommands({ prompt: mock(async () => ({} as Awaited>)) }, async () => "DIAGNOSTICS"); + expect(commands).toHaveLength(30); + expect(new Set(commands.map((command) => command.name)).size).toBe(30); + expect(commands.some((command) => command.name === "oc-beads:status")).toBe(false); + expect(commands.map((command) => command.name).sort()).toEqual([...selected, "oc-beads:diagnostics"].sort()); }); test("forwards literal arguments, attachments, prompt fields and native delivery without template execution", async () => { @@ -265,7 +268,7 @@ describe("packaged native workflows", () => { sessionID: "s1", delivery: "queue", prompt: { text: "a 'quoted' $ARGUMENTS $(touch nope) `literal`", files: [{ uri: "file:///tmp/a%20b", name: "a b" }], agents: [{ name: "build" }], skills: [{ id: "oc-beads" }] }, } as unknown as CommandInvocation; - for (const command of createBeadsCommands({ prompt }, async () => "STATUS: withheld")) { + for (const command of createBeadsCommands({ prompt }, async () => "DIAGNOSTICS: withheld")) { await command.execute(input); const sent = prompt.mock.calls.at(-1)![0] as Record; expect(sent.sessionID).toBe(input.sessionID); @@ -274,14 +277,43 @@ describe("packaged native workflows", () => { expect(sent.agents).toBe(input.prompt.agents); expect(sent.skills).toBe(input.prompt.skills); expect(sent.text).toContain(input.prompt.text); - if (command.name !== "oc-beads:status") { + if (command.name !== "oc-beads:diagnostics") { expect(sent.text).toContain("Do not bypass a hold"); expect(sent.text).toContain("oc-beads"); expect(sent.text).not.toContain("mcp__"); - } else expect(sent.text).toContain("STATUS: withheld"); + } else expect(sent.text).toContain("DIAGNOSTICS: withheld"); } }); + test("workflow bodies clarify native purposes without invoking diagnostics", async () => { + const prompt = mock(async (_input: unknown) => ({} as Awaited>)); + const diagnostics = mock(async () => "DIAGNOSTICS"); + const commands = createBeadsCommands({ prompt }, diagnostics); + const purposes = { + compact: "Guide semantic issue compaction with bd admin compact only when explicitly authorized; bd compact squashes Dolt history and is a different operation. This is not conversation compaction.", + restore: "Retrieve pre-compaction issue content with bd restore; display-only by default. Use --apply only with explicit authority to write that content back; this is not database backup recovery.", + quickstart: "Guide onboarding with installed bd quickstart help, current authorized context and packaged guidance; do not initialize a store or assume commands unavailable in the installed CLI.", + sync: "Inspect current bd sync help for Dolt-remote synchronization, distinct from bd federation sync and removed JSONL sync. Synchronize only with explicit authority; disclose conflicts without forcing a side.", + stats: "Report the issue-database overview using bd status (alias bd stats); use oc-beads:diagnostics for integration health. Do not claim work.", + }; + const input = { sessionID: "s1", delivery: "queue", prompt: { text: "explain only" } } as CommandInvocation; + for (const [stem, purpose] of Object.entries(purposes)) { + const command = commands.find((entry) => entry.name === `oc-beads:${stem}`)!; + expect(command.description).toBe(purpose); + await command.execute(input); + expect((prompt.mock.calls.at(-1)![0] as { text: string }).text).toContain(purpose); + } + for (const stem of ["init", "prime", "version", "decision", "template", "workflow"]) { + await commands.find((entry) => entry.name === `oc-beads:${stem}`)!.execute(input); + expect((prompt.mock.calls.at(-1)![0] as { text: string }).text).toContain("Workflow commands guide permitted operations, not exact CLI aliases."); + } + expect(diagnostics).not.toHaveBeenCalled(); + }); + + test("TROUBLESHOOTING.md gives compact analyze/apply, separate mode authority and explicit actor guidance", () => { + expect(readResource("TROUBLESHOOTING")).toMatch(/Prefer the agent-driven analyze\/apply path[\s\S]*--auto[\s\S]*external AI provider[\s\S]*--dolt[\s\S]*storage garbage collection[\s\S]*each require separate explicit authority[\s\S]*ordinary compact approval selects neither[\s\S]*explicit `--actor`[\s\S]*default of `agent`/); + }); + test("loads the rich skill at its installed path with all 17 explicit links, beyond a sampled ten", async () => { const skill = await loadBeadsSkill(); expect(String(skill.id)).toBe("oc-beads"); @@ -306,7 +338,7 @@ describe("packaged native workflows", () => { test("beta package manifest includes owned assets at the selected prerelease version", async () => { const manifest = await Bun.file("package.json").json(); expect(manifest.files).toContain("assets/oc-beads"); - expect(manifest.version).toBe("1.1.0-beta.1"); + expect(manifest.version).toBe("1.1.0-beta.2"); }); });