@snarkipus/opencode-beads 1.0.2 → 1.1.0-beta.2

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.
@@ -0,0 +1,132 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import type { Plugin } from "@opencode/plugin";
5
+ import type { CommandDefinition } from "@opencode/plugin/promise/command";
6
+
7
+ type SkillEditor = Parameters<Parameters<Plugin.Context["skill"]["transform"]>[0]>[0];
8
+ export type BeadsSkill = Parameters<SkillEditor["add"]>[0];
9
+
10
+ /** Package-relative paths survive npm installation, spaces and ignored/deep install roots. */
11
+ export const BEADS_SKILL_PATH = fileURLToPath(new URL("../assets/oc-beads/SKILL.md", import.meta.url));
12
+
13
+ /** Exact membership is checked against the selected immutable command inventory. */
14
+ export const WORKFLOWS = {
15
+ audit: ["Inspect or explicitly record scoped audit evidence; never collect transcripts automatically.", "INTEGRATION_PATTERNS"],
16
+ blocked: ["Inspect blocked work; distinguish explicit blocked status from dependency blocking.", "DEPENDENCIES"],
17
+ close: ["Close only the requested work with acceptance and validation evidence and closure authority.", "WORKFLOWS"],
18
+ comments: ["Read discussion or append the requested comment/checkpoint without replacing prior notes.", "RESUMABILITY"],
19
+ 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"],
20
+ 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"],
21
+ decision: ["Record the requested decision, rationale and alternatives; reference intended behavior and detailed rationale in their project-owned homes.", "INTEGRATION_PATTERNS"],
22
+ delete: ["Inspect the requested deletion and its effects; delete only with explicit scoped authority, never as a substitute for closure.", "TROUBLESHOOTING"],
23
+ dep: ["Inspect or change only the requested dependencies. Verify that X depends on Y in the intended direction.", "DEPENDENCIES"],
24
+ epic: ["Inspect or manage the requested hierarchy; closed children alone do not establish parent acceptance.", "WORKFLOWS"],
25
+ export: ["Export only the requested scope and destination with current CLI help; distinguish issue interchange from a full backup or memory export.", "CLI_REFERENCE"],
26
+ import: ["Inspect current import help and requested input before an authorized import; disclose stale/upsert and partial-write risks and routing limits. Never initialize or restore implicitly.", "TROUBLESHOOTING"],
27
+ init: ["Provide human-directed onboarding and current bd init help, explaining side effects. Do not initialize a store automatically.", "INTEGRATION_PATTERNS"],
28
+ label: ["Inspect or update only requested labels while preserving the project's taxonomy.", "CLI_REFERENCE"],
29
+ list: ["Retrieve issues with the requested supported filters. Retrieval does not authorize claims or task execution.", "CLI_REFERENCE"],
30
+ prime: ["Use supplied current context when available; request a guarded full-context refresh only when authorized and no hold is active.", "RESUMABILITY"],
31
+ 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"],
32
+ ready: ["Inspect actionable work. Honor an exact assignment; claim and execute only work already within the authorized scope.", "WORKFLOWS"],
33
+ "rename-prefix": ["Explain the requested project identifier migration and reference impact using current CLI help; require explicit migration authority.", "TROUBLESHOOTING"],
34
+ reopen: ["Inspect current state, then reopen only the requested issue with the supplied regression/correction reason.", "WORKFLOWS"],
35
+ 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"],
36
+ search: ["Search issues using supported filters; distinguish issue search from reusable memory search.", "CLI_REFERENCE"],
37
+ show: ["Read requested issue details, prior notes, acceptance and dependencies without mutating them.", "RESUMABILITY"],
38
+ 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"],
39
+ 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"],
40
+ template: ["Discover supported templates/formulas through installed help; replace obsolete static template syntax and do not execute a formula automatically.", "MOLECULES"],
41
+ 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"],
42
+ version: ["Report actual installed CLI, package and host versions and qualification limits; do not hardcode a latest version or install/upgrade anything.", "CLI_REFERENCE"],
43
+ workflow: ["Guide native Beads work and recovery: inspect scope, read prior state, claim atomically, checkpoint meaningful learning, validate and return evidence. Continue only within an authorized batch/goal.", "WORKFLOWS"],
44
+ } as const;
45
+
46
+ export interface SkillLoadDependencies {
47
+ skillPath?: string;
48
+ readText?: (path: string) => Promise<string>;
49
+ }
50
+
51
+ /** Read only the explicit packaged guidance links; no scan, installer or watcher is needed. */
52
+ export async function loadBeadsSkill(deps: SkillLoadDependencies = {}): Promise<BeadsSkill> {
53
+ const skillPath = deps.skillPath ?? BEADS_SKILL_PATH;
54
+ const readText = deps.readText ?? ((path: string) => readFile(path, "utf8"));
55
+ let markdown: string;
56
+ try {
57
+ markdown = await readText(skillPath);
58
+ } catch {
59
+ throw new Error("skill-unreachable SKILL.md");
60
+ }
61
+ const content = markdown.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, "").trim();
62
+ const links = new Set([...content.matchAll(/\]\(((?:resources|adr)\/[^)]+)\)/g)].map((match) => match[1]!));
63
+ if (links.size !== 17) throw new Error("resource-links-invalid: expected 17 explicit supporting links");
64
+ for (const link of links) {
65
+ try {
66
+ if (!(await readText(resolve(dirname(skillPath), link))).trim()) throw new Error("empty");
67
+ } catch {
68
+ throw new Error(`resource-unreachable ${link}`);
69
+ }
70
+ }
71
+ // The accepted asset's semantic trigger; no general frontmatter parser or host scanner clone.
72
+ return {
73
+ id: "oc-beads" as BeadsSkill["id"],
74
+ name: "oc-beads" as BeadsSkill["name"],
75
+ description: "Use Beads for durable work tracking, dependencies, blockers, checkpoints, recovery and reusable project knowledge.",
76
+ path: skillPath as BeadsSkill["path"],
77
+ content,
78
+ };
79
+ }
80
+
81
+ /** Inspect the candidate editor on every rebuild, including earlier changing user transforms. */
82
+ export function applyBeadsSkill(editor: SkillEditor, skill: BeadsSkill, diagnose: (message: string) => void): void {
83
+ if (editor.list().some((entry) => String(entry.id) === "oc-beads" || String(entry.name) === "oc-beads")) {
84
+ diagnose("skill-collision oc-beads: existing customization preserved");
85
+ return;
86
+ }
87
+ editor.add(skill);
88
+ }
89
+
90
+ /** Build native prompt commands, never shell/template interpolation or synthetic continuation. */
91
+ export function createBeadsCommands(
92
+ session: Pick<Plugin.Context["session"], "prompt">,
93
+ diagnostics: (sessionID: string) => Promise<string>,
94
+ skillPath = BEADS_SKILL_PATH,
95
+ signal?: AbortSignal,
96
+ ): CommandDefinition[] {
97
+ const common = [
98
+ "Workflow commands guide permitted operations, not exact CLI aliases.",
99
+ "Follow repository/user authority and the exact requested scope. Do not bypass a hold with manual prime or other store access.",
100
+ "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.",
101
+ "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.",
102
+ "Distinguish task checkpoints from reusable memory. Report failed, partial and uncertain outcomes; never blindly retry an ambiguous write.",
103
+ `Load skill oc-beads (installed file ${JSON.stringify(skillPath)}). If guidance is missing or permission denies access, report it honestly without bypass.`,
104
+ ].join("\n");
105
+ const commands: CommandDefinition[] = Object.entries(WORKFLOWS).map(([stem, [purpose, resource]]) => ({
106
+ name: `oc-beads:${stem}`,
107
+ description: purpose,
108
+ async execute(input) {
109
+ if (signal?.aborted) throw new Error("Beads workflow unloaded");
110
+ await session.prompt({
111
+ ...input.prompt,
112
+ sessionID: input.sessionID,
113
+ delivery: input.delivery,
114
+ text: `${purpose}\n${common}\nSupporting guidance: ${JSON.stringify(resolve(dirname(skillPath), "resources", `${resource}.md`))}\n\nUser request:\n${input.prompt.text}`,
115
+ });
116
+ },
117
+ }));
118
+ commands.push({
119
+ name: "oc-beads:diagnostics",
120
+ 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.",
121
+ async execute(input) {
122
+ if (signal?.aborted) throw new Error("Beads workflow unloaded");
123
+ const report = await diagnostics(input.sessionID);
124
+ if (signal?.aborted) throw new Error("Beads workflow unloaded");
125
+ await session.prompt({
126
+ ...input.prompt, sessionID: input.sessionID, delivery: input.delivery,
127
+ text: `Report these observed Beads diagnostics. This is read-only; do not run store-opening commands, change configuration or infer live qualification.\n${report}\n\nUser request:\n${input.prompt.text}`,
128
+ });
129
+ },
130
+ });
131
+ return commands;
132
+ }