opencode-kolchoz-loop 1.0.4 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/agents/agents/areczek.md +3 -0
- package/dist/agents/anetka.md +0 -1
- package/dist/agents/areczek.md +3 -1
- package/dist/agents/grazynka.md +0 -1
- package/dist/agents/januszek.md +0 -1
- package/dist/index.js +55 -10
- package/package.json +4 -4
- package/src/agents/areczek.md +3 -0
package/README.md
CHANGED
|
@@ -136,6 +136,14 @@ Agents use `claude-sonnet-4` by default. Override in `opencode.json`:
|
|
|
136
136
|
|
|
137
137
|
Recommendation: Anetka and Areczek should use different models. Cross-model review reduces shared blind spots.
|
|
138
138
|
|
|
139
|
+
## Commit gate
|
|
140
|
+
|
|
141
|
+
Before Areczek can submit a story for review, `kolchoz_submit_for_review` validates Git:
|
|
142
|
+
- no uncommitted changes in the working tree
|
|
143
|
+
- latest commit message starts with `feat(<storyId>):`
|
|
144
|
+
|
|
145
|
+
If either check fails, submission is blocked until Areczek creates the correct commit.
|
|
146
|
+
|
|
139
147
|
## Compound engineering
|
|
140
148
|
|
|
141
149
|
The system builds knowledge in `AGENTS.md` automatically:
|
|
@@ -144,6 +152,28 @@ The system builds knowledge in `AGENTS.md` automatically:
|
|
|
144
152
|
2. Anetka discovers a gotcha -> `kolchoz_learn("gotcha", "...")`
|
|
145
153
|
3. Future sessions read AGENTS.md -> better context -> better outcomes
|
|
146
154
|
|
|
155
|
+
## Release automation
|
|
156
|
+
|
|
157
|
+
This repository includes GitHub Actions workflows for a release cycle:
|
|
158
|
+
|
|
159
|
+
1. Run `Prepare Release Draft` manually from GitHub Actions on `main` or `master`.
|
|
160
|
+
2. Choose `RELEASE_TYPE`: `major`, `minor`, or `patch`.
|
|
161
|
+
3. Workflow bumps `package.json` version, commits it, creates a tag, and opens a draft release.
|
|
162
|
+
4. Publish the draft release in GitHub Releases.
|
|
163
|
+
5. Publishing the release triggers npm publishing from the release tag.
|
|
164
|
+
|
|
165
|
+
Workflow files:
|
|
166
|
+
- `.github/workflows/prepare-release.yml`
|
|
167
|
+
- `.github/workflows/publish-on-release.yml`
|
|
168
|
+
|
|
169
|
+
Required npm setup:
|
|
170
|
+
- Configure npm Trusted Publisher for this GitHub repository and workflow file `publish-on-release.yml`.
|
|
171
|
+
- Trusted publishing uses GitHub OIDC, so `NPM_TOKEN` is not required for package publishing.
|
|
172
|
+
|
|
173
|
+
Important:
|
|
174
|
+
- `Prepare Release Draft` guarantees matching `tag` and `package.json` version.
|
|
175
|
+
- If branch protection blocks direct pushes by Actions, allow `GITHUB_TOKEN` pushes for this workflow.
|
|
176
|
+
|
|
147
177
|
## License
|
|
148
178
|
|
|
149
179
|
MIT
|
|
@@ -41,6 +41,9 @@ Use these capabilities consistently:
|
|
|
41
41
|
- Commit format: `feat(story-id): short description`
|
|
42
42
|
- Always inspect `git diff` before committing
|
|
43
43
|
- If something goes wrong: `git stash` or `git reset`
|
|
44
|
+
- `kolchoz_submit_for_review` is hard-gated by Git checks:
|
|
45
|
+
- working tree must be clean (no pending changes)
|
|
46
|
+
- latest commit message must match current story: `feat(<storyId>): ...`
|
|
44
47
|
|
|
45
48
|
### Tests
|
|
46
49
|
- Run existing tests after changes: `npm test` / `bun test` / equivalent
|
package/dist/agents/anetka.md
CHANGED
package/dist/agents/areczek.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Lead implementer. Writes code, runs tests, commits changes. Has full access to tools, browser MCP, and Git. Executes PRD user stories."
|
|
3
3
|
mode: subagent
|
|
4
|
-
model: anthropic/claude-sonnet-4-20250514
|
|
5
4
|
temperature: 0.1
|
|
6
5
|
color: "#22d3ee"
|
|
7
6
|
steps: 50
|
|
@@ -42,6 +41,9 @@ Use these capabilities consistently:
|
|
|
42
41
|
- Commit format: `feat(story-id): short description`
|
|
43
42
|
- Always inspect `git diff` before committing
|
|
44
43
|
- If something goes wrong: `git stash` or `git reset`
|
|
44
|
+
- `kolchoz_submit_for_review` is hard-gated by Git checks:
|
|
45
|
+
- working tree must be clean (no pending changes)
|
|
46
|
+
- latest commit message must match current story: `feat(<storyId>): ...`
|
|
45
47
|
|
|
46
48
|
### Tests
|
|
47
49
|
- Run existing tests after changes: `npm test` / `bun test` / equivalent
|
package/dist/agents/grazynka.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Requirements analyst. Clarifies requests from Januszek, analyzes the codebase, and creates a structured PRD with user stories and acceptance criteria."
|
|
3
3
|
mode: subagent
|
|
4
|
-
model: anthropic/claude-sonnet-4-20250514
|
|
5
4
|
temperature: 0.2
|
|
6
5
|
color: "#a855f7"
|
|
7
6
|
tools:
|
package/dist/agents/januszek.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Main Kolchoz Loop orchestrator. Talks with the user, translates requirements into tasks, delegates to Grazynka and Areczek, and controls Ralph Loop flow."
|
|
3
3
|
mode: primary
|
|
4
|
-
model: anthropic/claude-sonnet-4-20250514
|
|
5
4
|
temperature: 0.3
|
|
6
5
|
color: "#ff6b35"
|
|
7
6
|
tools:
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,9 @@ import { tool } from "@opencode-ai/plugin/tool";
|
|
|
2
2
|
import { readFile, writeFile, mkdir, readdir, copyFile, stat } from "fs/promises";
|
|
3
3
|
import { join, dirname } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
|
+
import { execFile } from "child_process";
|
|
6
|
+
import { promisify } from "util";
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
5
8
|
// ── Filesystem helpers ──
|
|
6
9
|
async function ensureDir(dir) {
|
|
7
10
|
await mkdir(dir, { recursive: true });
|
|
@@ -41,6 +44,30 @@ async function appendProgress(dir, message) {
|
|
|
41
44
|
await writeFile(file, line, "utf-8");
|
|
42
45
|
}
|
|
43
46
|
}
|
|
47
|
+
async function runGit(projectRoot, args) {
|
|
48
|
+
const { stdout } = await execFileAsync("git", args, { cwd: projectRoot });
|
|
49
|
+
return stdout.trim();
|
|
50
|
+
}
|
|
51
|
+
async function validateStoryCommit(projectRoot, storyId) {
|
|
52
|
+
try {
|
|
53
|
+
await runGit(projectRoot, ["rev-parse", "--is-inside-work-tree"]);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return "ERROR: Git repository not found. Commit is required before review.";
|
|
57
|
+
}
|
|
58
|
+
const status = await runGit(projectRoot, ["status", "--porcelain"]);
|
|
59
|
+
if (status.length > 0) {
|
|
60
|
+
return (`ERROR: Uncommitted changes detected. Commit all changes for ${storyId} before review.\n` +
|
|
61
|
+
`Hint: git add -A && git commit -m "feat(${storyId}): short description"`);
|
|
62
|
+
}
|
|
63
|
+
const lastCommitMessage = await runGit(projectRoot, ["log", "-1", "--pretty=%s"]);
|
|
64
|
+
const requiredPrefix = `feat(${storyId}):`;
|
|
65
|
+
if (!lastCommitMessage.startsWith(requiredPrefix)) {
|
|
66
|
+
return (`ERROR: Last commit message must start with "${requiredPrefix}".\n` +
|
|
67
|
+
`Current: "${lastCommitMessage}"`);
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
44
71
|
// ── Agent provisioning ──
|
|
45
72
|
// Copies bundled .md agent files to .opencode/agents/
|
|
46
73
|
// so OpenCode discovers them as real agents.
|
|
@@ -121,16 +148,29 @@ export const KolchozLoop = async ({ project, client, $, directory, worktree }) =
|
|
|
121
148
|
stories: tool.schema.string(), // JSON array
|
|
122
149
|
},
|
|
123
150
|
async execute(args) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
151
|
+
let parsed;
|
|
152
|
+
try {
|
|
153
|
+
const raw = JSON.parse(args.stories);
|
|
154
|
+
if (!Array.isArray(raw))
|
|
155
|
+
throw new Error("stories must be a JSON array");
|
|
156
|
+
parsed = raw;
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
return `ERROR: Invalid stories JSON — ${err instanceof Error ? err.message : String(err)}`;
|
|
160
|
+
}
|
|
161
|
+
const stories = parsed.map((value, i) => {
|
|
162
|
+
const s = value;
|
|
163
|
+
return {
|
|
164
|
+
id: s.id || `story-${i + 1}`,
|
|
165
|
+
title: s.title || `Story ${i + 1}`,
|
|
166
|
+
description: s.description || "",
|
|
167
|
+
acceptanceCriteria: s.acceptanceCriteria || [],
|
|
168
|
+
priority: s.priority || "medium",
|
|
169
|
+
status: "pending",
|
|
170
|
+
assignedTo: "areczek",
|
|
171
|
+
iteration: 0,
|
|
172
|
+
};
|
|
173
|
+
});
|
|
134
174
|
const prd = {
|
|
135
175
|
title: args.title,
|
|
136
176
|
createdBy: "grazynka",
|
|
@@ -202,6 +242,11 @@ export const KolchozLoop = async ({ project, client, $, directory, worktree }) =
|
|
|
202
242
|
const story = prd.userStories.find((s) => s.id === args.storyId);
|
|
203
243
|
if (!story)
|
|
204
244
|
return `ERROR: Story ${args.storyId} not found.`;
|
|
245
|
+
const commitValidationError = await validateStoryCommit(projectRoot, args.storyId);
|
|
246
|
+
if (commitValidationError) {
|
|
247
|
+
await appendProgress(stateDir, `[Areczek] Submission blocked for ${args.storyId}: missing/invalid commit`);
|
|
248
|
+
return commitValidationError;
|
|
249
|
+
}
|
|
205
250
|
story.status = "review";
|
|
206
251
|
await writeJson(stateDir, "prd.json", prd);
|
|
207
252
|
const state = await readJson(stateDir, "loop-state.json", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-kolchoz-loop",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Multi-agent Ralph Loop plugin for OpenCode - Januszek, Grazynka, Areczek, Anetka",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@opencode-ai/plugin": "
|
|
30
|
+
"@opencode-ai/plugin": "^1.2.7"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@types/node": "
|
|
34
|
-
"typescript": "
|
|
33
|
+
"@types/node": "^25.3.0",
|
|
34
|
+
"typescript": "^5.9.3"
|
|
35
35
|
},
|
|
36
36
|
"files": [
|
|
37
37
|
"dist/**/*",
|
package/src/agents/areczek.md
CHANGED
|
@@ -41,6 +41,9 @@ Use these capabilities consistently:
|
|
|
41
41
|
- Commit format: `feat(story-id): short description`
|
|
42
42
|
- Always inspect `git diff` before committing
|
|
43
43
|
- If something goes wrong: `git stash` or `git reset`
|
|
44
|
+
- `kolchoz_submit_for_review` is hard-gated by Git checks:
|
|
45
|
+
- working tree must be clean (no pending changes)
|
|
46
|
+
- latest commit message must match current story: `feat(<storyId>): ...`
|
|
44
47
|
|
|
45
48
|
### Tests
|
|
46
49
|
- Run existing tests after changes: `npm test` / `bun test` / equivalent
|