diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6adfc3f..94aea5f 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -7,7 +7,7 @@ "name": "haku", "source": "./", "description": "Git-issue driven planning, orchestrator/worker development and verified merge-to-close for Claude Code (GitHub first)", - "version": "0.16.24", + "version": "0.16.25", "category": "workflow" } ] diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 0bb9937..65762a5 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "haku", - "version": "0.16.24", + "version": "0.16.25", "description": "HAKU - Harness Assistant Keeping Users in the loop. Git-issue driven story planning, orchestrator/worker development and verified merge-to-close for Claude Code (GitHub first, GitLab next).", "author": { "name": "dongqdev" }, "license": "MIT", diff --git a/agents/worker.md b/agents/worker.md index 12a3b01..fcc8396 100644 --- a/agents/worker.md +++ b/agents/worker.md @@ -16,6 +16,8 @@ You are a worker. You own one task issue, one worktree and one branch. 7. Finish with a summary: each acceptance criterion as met or unmet with evidence, what you did, what you tried that failed, and open risks. Write it to the file the orchestrator names. A statement that tests passed must come with the real command and its output in the report (the last lines are enough); "tests pass" alone is not accepted. +Right before the URL, print this one line once, exactly as written (replace N with the issue number): `( o w o ) haku PR ready #N` + Print the full pull request URL and your summary in your final message, not only in the file: a `/goal` check or a stop hook can read only what is printed. ## Pitfalls diff --git a/skills/build/SKILL.md b/skills/build/SKILL.md index 17b9f33..51e4a98 100644 --- a/skills/build/SKILL.md +++ b/skills/build/SKILL.md @@ -13,6 +13,14 @@ Helper: `node "${CLAUDE_PLUGIN_ROOT}/scripts/issues.js"` (called `issues.js`). Every choice you put to the user goes through a choice question (AskUserQuestion), never free text, and a risky branch is never settled by assuming. Recommended option first, literal UTF-8, no prose questions at reply end, never postpone. Read the full rule in the `## Decisions` section of `${CLAUDE_PLUGIN_ROOT}/skills/sniff/SKILL.md` before the first question; it applies here unchanged. +## Banner + +Start by printing this one line once, exactly as written, then continue: + +```text +( o w o ) haku build +``` + ## Loop 1. **Pick ready tasks.** Open `type:task` children whose `Depends-On` issues are closed and whose `Scope` does not overlap a running task. Skip a task labelled `deferred` (the user postponed it) or `blocked`. Never exceed `maxWorkers`. diff --git a/skills/plan/SKILL.md b/skills/plan/SKILL.md index 73e6c1e..311df74 100644 --- a/skills/plan/SKILL.md +++ b/skills/plan/SKILL.md @@ -13,6 +13,14 @@ Helper: `node "${CLAUDE_PLUGIN_ROOT}/scripts/issues.js"` (called `issues.js`). Every choice you put to the user goes through a choice question (AskUserQuestion), never free text, and a risky branch is never settled by assuming. Recommended option first, literal UTF-8, no prose questions at reply end, never postpone. Read the full rule in the `## Decisions` section of `${CLAUDE_PLUGIN_ROOT}/skills/sniff/SKILL.md` before the first question; it applies here unchanged. +## Banner + +Start by printing this one line once, exactly as written, then continue: + +```text +( o w o ) haku plan +``` + ## 1. Understand Read the repository (read-only) and the user's goal. Read `.haku/config.json` (assignee, maxWorkers, mergeMode, titlePrefix) from the repository root of the current checkout (that is the file `issues.js` itself reads) and `.haku/verify.json` from the **default branch** to learn which verify profiles exist. If either is missing, stop and point to `/haku:setup`. If the current folder is not a Git repository at all and the user is starting something new, `/haku:setup` starts the new-project flow (names, folder, remote repository); hand over to it instead of stopping. diff --git a/tests/banner.test.js b/tests/banner.test.js index 79c0991..6def240 100644 --- a/tests/banner.test.js +++ b/tests/banner.test.js @@ -31,3 +31,17 @@ test('the face is compact and the ears, face and mouth share one centre', () => assert.strictEqual(ears.indexOf('___') + 1, 4); assert.strictEqual(mouth.indexOf('vvv') + 1, 4); }); + +test('plan and build print a one-line mini banner that fits the column limit', () => { + for (const name of ['plan', 'build']) { + const text = fs.readFileSync(path.join(__dirname, '..', 'skills', name, 'SKILL.md'), 'utf8'); + const m = text.match(/## Banner[\s\S]*?```text\n([\s\S]*?)```/); + assert.ok(m, `${name}: banner block missing`); + assert.strictEqual(m[1], `( o w o ) haku ${name}\n`); + } +}); + +test('the worker prints a one-line PR banner', () => { + const worker = fs.readFileSync(path.join(__dirname, '..', 'agents', 'worker.md'), 'utf8'); + assert.match(worker, /\( o w o \) haku PR ready #N/); +});