opencodekit 0.15.9 → 0.15.11

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.
Files changed (62) hide show
  1. package/dist/index.js +9 -7
  2. package/dist/template/.opencode/AGENTS.md +7 -2
  3. package/dist/template/.opencode/agent/build.md +390 -0
  4. package/dist/template/.opencode/agent/general.md +1 -0
  5. package/dist/template/.opencode/agent/looker.md +1 -0
  6. package/dist/template/.opencode/agent/painter.md +218 -0
  7. package/dist/template/.opencode/agent/plan.md +3 -0
  8. package/dist/template/.opencode/agent/vision.md +1 -0
  9. package/dist/template/.opencode/command/edit-image.md +1 -2
  10. package/dist/template/.opencode/command/generate-icon.md +1 -2
  11. package/dist/template/.opencode/command/generate-image.md +1 -2
  12. package/dist/template/.opencode/command/generate-pattern.md +1 -2
  13. package/dist/template/.opencode/command/generate-storyboard.md +1 -2
  14. package/dist/template/.opencode/command/implement.md +136 -10
  15. package/dist/template/.opencode/command/restore-image.md +1 -2
  16. package/dist/template/.opencode/dcp.jsonc +1 -15
  17. package/dist/template/.opencode/memory/observations/2026-01-25-decision-agent-roles-build-orchestrates-general-e.md +14 -0
  18. package/dist/template/.opencode/memory/observations/2026-01-25-decision-simplified-swarm-helper-tool-to-fix-type.md +20 -0
  19. package/dist/template/.opencode/memory/observations/2026-01-25-decision-use-beads-as-swarm-board-source-of-truth.md +14 -0
  20. package/dist/template/.opencode/memory/observations/2026-01-25-learning-user-wants-real-swarm-coordination-guida.md +15 -0
  21. package/dist/template/.opencode/memory/research/opencode-mcp-bug-report.md +126 -0
  22. package/dist/template/.opencode/opencode.json +812 -704
  23. package/dist/template/.opencode/package.json +1 -1
  24. package/dist/template/.opencode/plans/swarm-protocol.md +123 -0
  25. package/dist/template/.opencode/plugin/README.md +10 -0
  26. package/dist/template/.opencode/plugin/swarm-enforcer.ts +297 -0
  27. package/dist/template/.opencode/skill/supabase-postgres-best-practices/AGENTS.md +1490 -0
  28. package/dist/template/.opencode/skill/supabase-postgres-best-practices/SKILL.md +57 -0
  29. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/advanced-full-text-search.md +55 -0
  30. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/advanced-jsonb-indexing.md +49 -0
  31. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/conn-idle-timeout.md +46 -0
  32. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/conn-limits.md +44 -0
  33. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/conn-pooling.md +41 -0
  34. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/conn-prepared-statements.md +46 -0
  35. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/data-batch-inserts.md +54 -0
  36. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/data-n-plus-one.md +53 -0
  37. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/data-pagination.md +50 -0
  38. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/data-upsert.md +50 -0
  39. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/lock-advisory.md +56 -0
  40. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/lock-deadlock-prevention.md +68 -0
  41. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/lock-short-transactions.md +50 -0
  42. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/lock-skip-locked.md +54 -0
  43. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/monitor-explain-analyze.md +45 -0
  44. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/monitor-pg-stat-statements.md +55 -0
  45. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/monitor-vacuum-analyze.md +55 -0
  46. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/query-composite-indexes.md +44 -0
  47. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/query-covering-indexes.md +40 -0
  48. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/query-index-types.md +45 -0
  49. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/query-missing-indexes.md +43 -0
  50. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/query-partial-indexes.md +45 -0
  51. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/schema-data-types.md +46 -0
  52. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/schema-foreign-key-indexes.md +59 -0
  53. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/schema-lowercase-identifiers.md +55 -0
  54. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/schema-partitioning.md +55 -0
  55. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/schema-primary-keys.md +61 -0
  56. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/security-privileges.md +54 -0
  57. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/security-rls-basics.md +50 -0
  58. package/dist/template/.opencode/skill/supabase-postgres-best-practices/rules/security-rls-performance.md +57 -0
  59. package/dist/template/.opencode/skill/swarm-coordination/SKILL.md +405 -0
  60. package/dist/template/.opencode/tool/swarm-delegate.ts +175 -0
  61. package/dist/template/.opencode/tool/swarm-helper.ts +164 -0
  62. package/package.json +1 -1
@@ -11,7 +11,7 @@
11
11
  "type-check": "tsc --noEmit"
12
12
  },
13
13
  "dependencies": {
14
- "@opencode-ai/plugin": "1.1.31"
14
+ "@opencode-ai/plugin": "1.1.36"
15
15
  },
16
16
  "devDependencies": {
17
17
  "@types/node": "^25.0.3",
@@ -0,0 +1,123 @@
1
+ # Swarm Protocol (Beads-as-Board)
2
+
3
+ ## Goal
4
+
5
+ Use `.beads/` as the single source of truth for task state + dependencies, while agents coordinate through structured artifacts (not freeform chatter) and verification gates.
6
+
7
+ ## Roles (Strict)
8
+
9
+ - Lead: Owns scope, prioritization, and all Beads state transitions.
10
+ - Planner: Turns intent into Beads tasks + dependency DAG; no code changes.
11
+ - Worker: Executes exactly one claimed task; posts a structured report.
12
+ - Verifier: Independently validates acceptance checks; blocks close on missing evidence.
13
+
14
+ ## Board = Beads
15
+
16
+ Canonical state lives in `.beads/issues.jsonl` (tasks) and `.beads/artifacts/<id>/` (task artifacts).
17
+
18
+ - Create tasks: `bd create "Title" -p <1-3>`
19
+ - See unblocked work: `bd ready`
20
+ - Inspect context: `bd show <id>`
21
+ - Claim work: `bd update <id> --status=in_progress`
22
+ - Close work: `bd close <id> --reason="..."` then `bd sync`
23
+
24
+ ## Task Artifact Contract
25
+
26
+ Every task MUST have `.beads/artifacts/<id>/spec.md`.
27
+
28
+ Optional supporting files:
29
+
30
+ - `.beads/artifacts/<id>/plan.md`: multi-step implementation plan, files touched, and gates
31
+ - `.beads/artifacts/<id>/review.md`: verifier notes + evidence summary
32
+
33
+ ### spec.md (Minimum Template)
34
+
35
+ - Context: why this exists
36
+ - Scope: in / out
37
+ - Constraints: MUST / MUST NOT (security, deps, dist/, etc.)
38
+ - Acceptance Criteria: checkboxes, each with a verification method
39
+ - Evidence Required: exact commands and expected signals (e.g. "typecheck command passes")
40
+
41
+ #### Verification Defaults (Language-Agnostic)
42
+
43
+ Do NOT assume npm/bun/pytest/etc. Prefer this pattern:
44
+
45
+ - `typecheck`: `<command>`
46
+ - `lint`: `<command>`
47
+ - `test`: `<command>`
48
+ - `build` (optional): `<command>`
49
+
50
+ If the repository has a canonical list of commands, reference it (e.g. `.opencode/memory/project/commands.md`).
51
+
52
+ Common stacks (examples only):
53
+
54
+ | Stack | typecheck | lint | test |
55
+ | ------- | ------------------------------------------ | ---------------------------- | ------------------------ |
56
+ | Node/TS | `npm run typecheck` or `bun run typecheck` | `npm run lint` | `bun test` or `npm test` |
57
+ | Python | `python -m mypy .` | `ruff check .` | `pytest` |
58
+ | Go | `go test ./...` (compile+test) | `golangci-lint run` | `go test ./...` |
59
+ | Rust | `cargo check` | `cargo fmt --check` (format) | `cargo test` |
60
+
61
+ ## Delegation Packet (Worker Input)
62
+
63
+ Every delegated task MUST include the following envelope:
64
+
65
+ - TASK: `<id> - <title>`
66
+ - EXPECTED OUTCOME: measurable end state
67
+ - REQUIRED TOOLS: e.g. `read`, `grep`, `lsp`, `bash`
68
+ - MUST DO: e.g. LSP-before-edits, run typecheck, run lint
69
+ - MUST NOT DO: e.g. no new deps, no dist/ edits, no git push
70
+ - ACCEPTANCE CHECKS: list of commands + pass criteria
71
+ - CONTEXT: links to `.beads/artifacts/<id>/spec.md` + relevant files
72
+
73
+ ### Helper Tool
74
+
75
+ If available, use the custom tool `swarm-delegate` to generate (and optionally write) a delegation packet:
76
+
77
+ ```ts
78
+ swarm -
79
+ delegate({
80
+ bead_id: "opencodekit-template-xyz",
81
+ expected_outcome: "<measurable end state>",
82
+ required_tools: "read, grep, lsp, bash",
83
+ must_do: "LSP before edits, run project verification commands",
84
+ must_not_do: "no new deps, don't edit dist/",
85
+ acceptance_checks: "typecheck: <command>, lint: <command>, test: <command>",
86
+ context: "See .beads/artifacts/<id>/spec.md",
87
+ write: true,
88
+ });
89
+ ```
90
+
91
+ ## Worker Report (Worker Output)
92
+
93
+ Workers MUST respond with a structured report:
94
+
95
+ - Result: done / blocked / needs replan
96
+ - Changes: file list + what changed (with file references)
97
+ - Verification: commands run + pass/fail summary
98
+ - Risks/Notes: edge cases, follow-ups
99
+ - Confidence: high / medium / low
100
+
101
+ ## Gates (Non-Negotiable)
102
+
103
+ - Planning gate: `.beads/artifacts/<id>/spec.md` exists with acceptance criteria BEFORE implementation starts
104
+ - Execution gate: worker provides verification evidence BEFORE close
105
+ - Review gate (risk-based): verifier signs off in `review.md` BEFORE close
106
+
107
+ ## Replan Triggers
108
+
109
+ Immediately stop execution and return to planning if:
110
+
111
+ - Scope expands to 4+ files unexpectedly
112
+ - Requirement ambiguity changes implementation choice
113
+ - Two-strike tool failures
114
+ - New dependency or `.opencode/` structure change would be needed
115
+
116
+ ## Lead Checklist
117
+
118
+ 1. `bd ready` -> pick task -> `bd show <id>`
119
+ 2. Ensure `.beads/artifacts/<id>/spec.md` has acceptance checks
120
+ 3. `bd update <id> --status=in_progress`
121
+ 4. Delegate with the packet format
122
+ 5. Require worker report + evidence
123
+ 6. `bd close <id> --reason="..."` + `bd sync`
@@ -80,6 +80,16 @@ Session 3: read_session("previous") → Tests (90k) → close
80
80
  - High-priority or in-progress TODOs → Inject continuation prompt
81
81
  - Low-priority pending TODOs → OS notification only (no forced continuation)
82
82
 
83
+ ### swarm-enforcer.ts
84
+
85
+ **Swarm protocol guardrails (Beads-as-board)** - nudges agents to follow the Beads-first workflow.
86
+
87
+ - Treats `.beads/` as the single source of truth for the swarm task board
88
+ - If user expresses implementation intent and no task is `in_progress`, injects a nudge to use `bd ready/show/update`
89
+ - If there are `in_progress` tasks but `.beads/artifacts/<id>/spec.md` is missing, nudges to create it before implementation
90
+ - On `file.edited`, warns if code is being changed without a claimed task or with missing `spec.md`
91
+ - On `session.idle`, reminds to `bd close` + `bd sync` when work is done
92
+
83
93
  ### notification.ts
84
94
 
85
95
  **Session completion alerts** - sends native notifications when AI finishes.
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Swarm Enforcer Plugin
3
+ *
4
+ * Beads is the single source of truth for the swarm board.
5
+ * This plugin nudges agents to:
6
+ * - Claim a Beads task before making code changes
7
+ * - Ensure `spec.md` exists for in-progress tasks
8
+ * - Close/sync in-progress work at session end
9
+ *
10
+ * This plugin is intentionally non-destructive: it never runs `bd update/close/sync`.
11
+ */
12
+
13
+ import fsPromises from "node:fs/promises";
14
+ import path from "node:path";
15
+ import type { Plugin } from "@opencode-ai/plugin";
16
+
17
+ type BeadsIssue = {
18
+ id: string;
19
+ title?: string;
20
+ status?: string;
21
+ };
22
+
23
+ const BEADS_DIR = ".beads";
24
+ const ISSUES_FILE = "issues.jsonl";
25
+
26
+ const CODE_EXTENSIONS = [
27
+ ".ts",
28
+ ".tsx",
29
+ ".js",
30
+ ".jsx",
31
+ ".mjs",
32
+ ".cjs",
33
+ ".py",
34
+ ".go",
35
+ ".rs",
36
+ ".java",
37
+ ".c",
38
+ ".cpp",
39
+ ".h",
40
+ ".hpp",
41
+ ];
42
+
43
+ const WORK_INTENT_PATTERNS = [
44
+ /\b(implement|fix|refactor|add|remove|delete|update|change|modify|create|build)\b/i,
45
+ /\b(edit|patch)\b/i,
46
+ ];
47
+
48
+ function looksLikeWorkIntent(text: string): boolean {
49
+ return WORK_INTENT_PATTERNS.some((p) => p.test(text));
50
+ }
51
+
52
+ function isCodeFile(filePath: string): boolean {
53
+ return CODE_EXTENSIONS.some((ext) => filePath.endsWith(ext));
54
+ }
55
+
56
+ function isIgnoredPath(repoDir: string, filePath: string): boolean {
57
+ const absPath = path.isAbsolute(filePath)
58
+ ? filePath
59
+ : path.join(repoDir, filePath);
60
+ const rel = path.relative(repoDir, absPath);
61
+
62
+ // Outside repo: ignore
63
+ if (rel.startsWith("..")) return true;
64
+
65
+ const normalized = rel.replace(/\\/g, "/");
66
+ return (
67
+ normalized.startsWith("node_modules/") ||
68
+ normalized.startsWith("dist/") ||
69
+ normalized.startsWith(".beads/") ||
70
+ normalized.startsWith(".git/")
71
+ );
72
+ }
73
+
74
+ function summarizeIssues(issues: BeadsIssue[], limit = 5): string {
75
+ return issues
76
+ .slice(0, limit)
77
+ .map((i) => `${i.id}${i.title ? `: ${i.title}` : ""}`)
78
+ .join("\n");
79
+ }
80
+
81
+ async function readIssuesJsonl(repoDir: string): Promise<BeadsIssue[]> {
82
+ const issuesPath = path.join(repoDir, BEADS_DIR, ISSUES_FILE);
83
+
84
+ let content: string;
85
+ try {
86
+ content = await fsPromises.readFile(issuesPath, "utf-8");
87
+ } catch {
88
+ return [];
89
+ }
90
+
91
+ const issues: BeadsIssue[] = [];
92
+ const lines = content.split(/\r?\n/);
93
+ for (const line of lines) {
94
+ const trimmed = line.trim();
95
+ if (!trimmed) continue;
96
+ try {
97
+ const parsed = JSON.parse(trimmed);
98
+ if (parsed && typeof parsed.id === "string") {
99
+ issues.push({
100
+ id: parsed.id,
101
+ title: typeof parsed.title === "string" ? parsed.title : undefined,
102
+ status: typeof parsed.status === "string" ? parsed.status : undefined,
103
+ });
104
+ }
105
+ } catch {
106
+ // Ignore malformed JSONL lines
107
+ }
108
+ }
109
+
110
+ return issues;
111
+ }
112
+
113
+ async function specExists(repoDir: string, issueId: string): Promise<boolean> {
114
+ const specPath = path.join(
115
+ repoDir,
116
+ BEADS_DIR,
117
+ "artifacts",
118
+ issueId,
119
+ "spec.md",
120
+ );
121
+ try {
122
+ await fsPromises.access(specPath);
123
+ return true;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+
129
+ function buildNudge(params: {
130
+ inProgress: BeadsIssue[];
131
+ missingSpec: BeadsIssue[];
132
+ }): string {
133
+ const { inProgress, missingSpec } = params;
134
+
135
+ if (inProgress.length === 0) {
136
+ return `
137
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
138
+ ⚡ [SWARM PROTOCOL]
139
+
140
+ Beads is the swarm board. Before any code changes:
141
+
142
+ 1) Pick a task: \`bd ready\` (or \`bd list\`)
143
+ 2) Inspect: \`bd show <id>\`
144
+ 3) Claim: \`bd update <id> --status=in_progress\`
145
+
146
+ Then proceed with work and collect verification evidence.
147
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
148
+ `;
149
+ }
150
+
151
+ if (missingSpec.length > 0) {
152
+ return `
153
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
154
+ ⚡ [SWARM PROTOCOL]
155
+
156
+ In-progress Beads exist, but \`spec.md\` is missing for:
157
+
158
+ ${summarizeIssues(missingSpec)}
159
+
160
+ Create \`.beads/artifacts/<id>/spec.md\` before implementation.
161
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
162
+ `;
163
+ }
164
+
165
+ return "";
166
+ }
167
+
168
+ export const SwarmEnforcer: Plugin = async ({ client, directory }) => {
169
+ const repoDir = directory || process.cwd();
170
+ let lastStateAt = 0;
171
+ let cachedInProgress: BeadsIssue[] = [];
172
+ let cachedMissingSpec: BeadsIssue[] = [];
173
+
174
+ const refreshState = async () => {
175
+ const now = Date.now();
176
+ if (now - lastStateAt < 1500) return;
177
+ lastStateAt = now;
178
+
179
+ const issues = await readIssuesJsonl(repoDir);
180
+ const inProgress = issues.filter((i) => i.status === "in_progress");
181
+
182
+ const missingSpec: BeadsIssue[] = [];
183
+ for (const issue of inProgress.slice(0, 10)) {
184
+ if (!(await specExists(repoDir, issue.id))) {
185
+ missingSpec.push(issue);
186
+ }
187
+ }
188
+
189
+ cachedInProgress = inProgress;
190
+ cachedMissingSpec = missingSpec;
191
+ };
192
+
193
+ const showToast = async (
194
+ title: string,
195
+ message: string,
196
+ variant: "info" | "success" | "warning" | "error" = "info",
197
+ ) => {
198
+ try {
199
+ await client.tui.showToast({
200
+ body: {
201
+ title,
202
+ message,
203
+ variant,
204
+ duration: variant === "error" ? 8000 : 5000,
205
+ },
206
+ });
207
+ } catch {
208
+ // If toast is unavailable, fail silently
209
+ }
210
+ };
211
+
212
+ return {
213
+ // Nudge early when user expresses implementation intent
214
+ "chat.message": async (input, output) => {
215
+ const { sessionID, messageID } = input;
216
+ const { message, parts } = output;
217
+ if (message.role !== "user") return;
218
+
219
+ const fullText = parts
220
+ .filter((p) => p.type === "text" && !("synthetic" in p && p.synthetic))
221
+ .map((p) => ("text" in p ? p.text : ""))
222
+ .join(" ");
223
+
224
+ if (!looksLikeWorkIntent(fullText)) return;
225
+
226
+ await refreshState();
227
+
228
+ const nudge = buildNudge({
229
+ inProgress: cachedInProgress,
230
+ missingSpec: cachedMissingSpec,
231
+ });
232
+ if (!nudge) return;
233
+
234
+ parts.push({
235
+ id: `swarm-nudge-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
236
+ sessionID,
237
+ messageID: messageID || "",
238
+ type: "text",
239
+ text: nudge,
240
+ synthetic: true,
241
+ } as import("@opencode-ai/sdk").Part);
242
+ },
243
+
244
+ // Warn if code gets edited while no task is claimed / spec missing
245
+ "file.edited": async ({ event }) => {
246
+ const filePath = event.properties?.file || event.properties?.path;
247
+ if (!filePath || typeof filePath !== "string") return;
248
+ if (isIgnoredPath(repoDir, filePath)) return;
249
+
250
+ const absPath = path.isAbsolute(filePath)
251
+ ? filePath
252
+ : path.join(repoDir, filePath);
253
+
254
+ if (!isCodeFile(absPath)) return;
255
+
256
+ await refreshState();
257
+
258
+ if (cachedInProgress.length === 0) {
259
+ await showToast(
260
+ "Swarm: No task claimed",
261
+ "Beads is the board. Claim a task before code edits (bd ready/show/update).",
262
+ "warning",
263
+ );
264
+ return;
265
+ }
266
+
267
+ if (cachedMissingSpec.length > 0) {
268
+ await showToast(
269
+ "Swarm: Missing spec.md",
270
+ `Create .beads/artifacts/<id>/spec.md for: ${cachedMissingSpec
271
+ .slice(0, 3)
272
+ .map((i) => i.id)
273
+ .join(", ")}`,
274
+ "warning",
275
+ );
276
+ }
277
+ },
278
+
279
+ // Session end reminder: close/sync if tasks still in progress
280
+ "session.idle": async () => {
281
+ await refreshState();
282
+ if (cachedInProgress.length === 0) return;
283
+
284
+ const list = cachedInProgress
285
+ .slice(0, 5)
286
+ .map((i) => i.id)
287
+ .join(", ");
288
+ await showToast(
289
+ "Swarm: Work still in progress",
290
+ `In-progress Beads: ${list}. Close with bd close + bd sync when done.`,
291
+ "info",
292
+ );
293
+ },
294
+ };
295
+ };
296
+
297
+ export default SwarmEnforcer;