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 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
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  description: "Code reviewer and quality gate. Reviews Areczek's work: tests, linting, typecheck, and diff review. Decides pass/fail."
3
3
  mode: subagent
4
- model: anthropic/claude-sonnet-4-20250514
5
4
  temperature: 0.1
6
5
  color: "#f43f5e"
7
6
  tools:
@@ -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
@@ -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:
@@ -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
- const stories = JSON.parse(args.stories).map((s, i) => ({
125
- id: s.id || `story-${i + 1}`,
126
- title: s.title || `Story ${i + 1}`,
127
- description: s.description || "",
128
- acceptanceCriteria: s.acceptanceCriteria || [],
129
- priority: s.priority || "medium",
130
- status: "pending",
131
- assignedTo: "areczek",
132
- iteration: 0,
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.4",
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": "latest"
30
+ "@opencode-ai/plugin": "^1.2.7"
31
31
  },
32
32
  "devDependencies": {
33
- "@types/node": "latest",
34
- "typescript": "latest"
33
+ "@types/node": "^25.3.0",
34
+ "typescript": "^5.9.3"
35
35
  },
36
36
  "files": [
37
37
  "dist/**/*",
@@ -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