Compare commits

...

10 Commits

Author SHA1 Message Date
Pit Friedrich 9112d9524f model fixation for commands and subagents 2026-07-25 20:36:40 +02:00
pitfriedrich 18a76b0350 Merge pull request 'feat: add CalcFunctionFactory for calculator operations (#13)' (#14) from ai/issue-13 into main
Reviewed-on: #14
2026-07-25 18:10:54 +00:00
Pit Friedrich 55e5cbeb0f feat: add CalcFunctionFactory for calculator operations (#13)
CI / build-and-test (pull_request) Successful in 16s
Callers pick an operation via the CalcOperation enum instead of
instantiating implementation classes directly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 20:09:19 +02:00
Pit Friedrich 01fa52a1fc git attrs 2026-07-25 20:03:43 +02:00
pitfriedrich 18570dec1c Merge pull request 'feat: add power operation to calculator (#11)' (#12) from ai/issue-11 into main
Reviewed-on: #12
2026-07-25 17:59:15 +00:00
Pit Friedrich 9244d49d75 fix: add PowerFunction calculator operation (#11)
CI / build-and-test (pull_request) Successful in 17s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:57:21 +02:00
Pit Friedrich 80ad7e837c error in fix-issue creating labels 2026-07-25 19:53:47 +02:00
Pit Friedrich 37606bf304 fixed return of next-issue agent 2026-07-25 19:47:05 +02:00
Pit Friedrich d10efd5beb set default code dir 2026-07-25 19:35:33 +02:00
Pit Friedrich b44f8363ea increased loop interval 2026-07-25 19:34:05 +02:00
10 changed files with 177 additions and 20 deletions
+1
View File
@@ -2,6 +2,7 @@
name: next-issue name: next-issue
description: Wählt das nächste zu bearbeitende Gitea-Issue und gibt nur die Kerndaten zurück. description: Wählt das nächste zu bearbeitende Gitea-Issue und gibt nur die Kerndaten zurück.
tools: mcp__gitea__list_issues, mcp__gitea__issue_read tools: mcp__gitea__list_issues, mcp__gitea__issue_read
model: haiku
--- ---
Finde das nächste offene Issue im Repo <owner>/<repo> mit Label `ai-ready` Finde das nächste offene Issue im Repo <owner>/<repo> mit Label `ai-ready`
und NICHT mit Label `ai-wip` oder `ai-blocked`. und NICHT mit Label `ai-wip` oder `ai-blocked`.
+19 -2
View File
@@ -4,12 +4,24 @@ argument-hint: <issue-nummer>
allowed-tools: > allowed-tools: >
Bash, Edit, Read, Write, Grep, Glob, Bash, Edit, Read, Write, Grep, Glob,
mcp__gitea__issue_read, mcp__gitea__issue_write, mcp__gitea__issue_read, mcp__gitea__issue_write,
mcp__gitea__label_read,
mcp__gitea__pull_request_write mcp__gitea__pull_request_write
model: opus
--- ---
Bearbeite Gitea-Issue #$1 im aktuellen Repo. Schritt für Schritt: Bearbeite Gitea-Issue #$1 im aktuellen Repo. Schritt für Schritt:
**Label-Regeln (wichtig):** Die Gitea-Label-API arbeitet mit numerischen
Label-IDs, nicht mit Namen. Hole daher ZUERST einmalig die Label-Liste über
`label_read` (`method: list_repo_labels`) und merke dir die Zuordnung
Name → ID für die gesamte Bearbeitung. Verwende ausschließlich `add_labels`
(mit `labels: [<id>]`) und `remove_label` (mit `label_id: <id>`).
Niemals `replace_labels` oder `clear_labels` benutzen — das löscht alle
übrigen Labels des Issues (z.B. `prio/*`).
1. Lies Issue #$1 (Titel, Beschreibung, Kommentare) über `issue_read`. 1. Lies Issue #$1 (Titel, Beschreibung, Kommentare) über `issue_read`.
2. Setze Label `ai-wip` via `issue_write`, entferne `ai-ready`. Notiere die aktuell gesetzten Labels, damit du sie nicht verlierst.
2. Hole die Label-Liste via `label_read`. Setze Label `ai-wip`
(`add_labels`), entferne `ai-ready` (`remove_label`).
3. Analysiere das Repo und finde die Ursache. Wenn der Scope zu groß/unklar 3. Analysiere das Repo und finde die Ursache. Wenn der Scope zu groß/unklar
ist (siehe CLAUDE.md), brich ab: kommentiere das Issue mit einer kurzen ist (siehe CLAUDE.md), brich ab: kommentiere das Issue mit einer kurzen
Begründung, setze `ai-blocked`, und beende ohne Codeänderung. Begründung, setze `ai-blocked`, und beende ohne Codeänderung.
@@ -20,4 +32,9 @@ Bearbeite Gitea-Issue #$1 im aktuellen Repo. Schritt für Schritt:
7. Push den aktuellen Branch zum Remote. 7. Push den aktuellen Branch zum Remote.
8. Öffne via `pull_request_write` einen PR gegen `main` (bzw. `develop`). 8. Öffne via `pull_request_write` einen PR gegen `main` (bzw. `develop`).
Die PR-Beschreibung MUSS `Closes #$1` enthalten. Die PR-Beschreibung MUSS `Closes #$1` enthalten.
9. Kommentiere am Issue mit dem PR-Link, setze Label `ai-review`. 9. Kommentiere am Issue mit dem PR-Link, setze Label `ai-review`
(`add_labels`) und entferne `ai-wip` (`remove_label`).
Wenn du in einem Schritt `ai-blocked` setzt, entferne ebenfalls `ai-wip`.
Existiert ein benötigtes Label nicht im Repo, kommentiere das am Issue statt
zu raten — erfinde keine Label-IDs.
+12
View File
@@ -0,0 +1,12 @@
# Normalize line endings independent of core.autocrlf.
* text=auto
# Maven wrapper: POSIX shell script must stay LF, even on Windows checkouts.
mvnw text eol=lf
*.sh text eol=lf
# Windows batch wrapper needs CRLF.
mvnw.cmd text eol=crlf
# Binaries: never convert.
*.jar binary
+6 -6
View File
@@ -3,11 +3,11 @@ set -euo pipefail
source .env source .env
REPO_DIR="$HOME/code/dein-repo" # Haupt-Klon REPO_DIR="$HOME/codebase/looptest" # Haupt-Klon
BASE_BRANCH="main" BASE_BRANCH="main"
TEST_CMD="<dein Testkommando>" # z.B. ./gradlew test TEST_CMD="./mvnw test" # z.B. ./gradlew test
MAX_ISSUES=5 # pro Durchlauf, damit du nicht davonläufst MAX_ISSUES=5 # pro Durchlauf, damit du nicht davonläufst
POLL_INTERVAL=300 # Sekunden zwischen Polls (0 = einmal laufen) POLL_INTERVAL=120 # Sekunden zwischen Polls (0 = einmal laufen)
cd "$REPO_DIR" cd "$REPO_DIR"
@@ -18,8 +18,8 @@ process_next() {
# 1) Nächstes Issue holen (Sub-Agent, minimaler Output) # 1) Nächstes Issue holen (Sub-Agent, minimaler Output)
local out local out
out=$(claude -p "Nutze den Sub-Agent 'next-issue'." \ out=$(claude -p "Nutze den Sub-Agent 'next-issue'. Gib NUR dessen Rueckgabezeile aus (ISSUE=<nr> oder ISSUE=NONE), keinen weiteren Text." \
--allowedTools "mcp__gitea__list_issues,mcp__gitea__issue_read" \ --allowedTools "Agent,mcp__gitea__list_issues,mcp__gitea__issue_read" \
--output-format text) --output-format text)
local nr local nr
nr=$(echo "$out" | grep -oE 'ISSUE=[0-9NONE]+' | cut -d= -f2) nr=$(echo "$out" | grep -oE 'ISSUE=[0-9NONE]+' | cut -d= -f2)
@@ -40,7 +40,7 @@ process_next() {
( (
cd "$wt" cd "$wt"
claude -p "/fix-issue $nr" \ claude -p "/fix-issue $nr" \
--allowedTools "Bash($TEST_CMD),Bash(git *),Edit,Read,Write,Grep,Glob,mcp__gitea__issue_read,mcp__gitea__issue_write,mcp__gitea__pull_request_write" \ --allowedTools "Bash($TEST_CMD),Bash(git *),Edit,Read,Write,Grep,Glob,mcp__gitea__issue_read,mcp__gitea__issue_write,mcp__gitea__label_read,mcp__gitea__pull_request_write" \
--output-format text --output-format text
) || echo "!!! Worker für #$nr mit Fehler beendet" ) || echo "!!! Worker für #$nr mit Fehler beendet"
@@ -1,22 +1,16 @@
package com.example; package com.example;
import com.example.util.AddFunction;
import com.example.util.CalcFunction; import com.example.util.CalcFunction;
import com.example.util.DivideFunction; import com.example.util.CalcFunctionFactory;
import com.example.util.MultiplyFunction; import com.example.util.CalcOperation;
import com.example.util.SubtractFunction;
public class LoopTestApplication { public class LoopTestApplication {
static void main() { static void main() {
System.out.println("============== Calculator ============="); System.out.println("============== Calculator =============");
CalcFunction add = new AddFunction(); for (CalcOperation operation : CalcOperation.values()) {
System.out.println("ADDITION: " + add.calc(2, 5, 6)); CalcFunction function = CalcFunctionFactory.create(operation);
CalcFunction subtract = new SubtractFunction(); System.out.println(operation + ": " + function.calc(2, 5, 6));
System.out.println("SUBTRACTION: " + subtract.calc(2, 5, 6)); }
CalcFunction multiply = new MultiplyFunction();
System.out.println("MULTIPLICATION: " + multiply.calc(2, 5, 6));
CalcFunction divide = new DivideFunction();
System.out.println("DIVISION: " + divide.calc(2, 5, 6));
} }
} }
@@ -0,0 +1,20 @@
package com.example.util;
public final class CalcFunctionFactory {
private CalcFunctionFactory() {
}
public static CalcFunction create(CalcOperation operation) {
if (operation == null) {
throw new IllegalArgumentException("Operation must not be null");
}
return switch (operation) {
case ADD -> new AddFunction();
case SUBTRACT -> new SubtractFunction();
case MULTIPLY -> new MultiplyFunction();
case DIVIDE -> new DivideFunction();
case POWER -> new PowerFunction();
};
}
}
@@ -0,0 +1,10 @@
package com.example.util;
public enum CalcOperation {
ADD,
SUBTRACT,
MULTIPLY,
DIVIDE,
POWER
}
@@ -0,0 +1,15 @@
package com.example.util;
public class PowerFunction implements CalcFunction {
public double calc(double... input) {
if (input.length == 0) {
return 0;
}
double result = input[0];
for (int i = 1; i < input.length; i++) {
result = Math.pow(result, input[i]);
}
return result;
}
}
@@ -0,0 +1,53 @@
package com.example.util;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
class CalcFunctionFactoryTest {
@Test
void createsAddFunction() {
assertInstanceOf(AddFunction.class, CalcFunctionFactory.create(CalcOperation.ADD));
}
@Test
void createsSubtractFunction() {
assertInstanceOf(SubtractFunction.class, CalcFunctionFactory.create(CalcOperation.SUBTRACT));
}
@Test
void createsMultiplyFunction() {
assertInstanceOf(MultiplyFunction.class, CalcFunctionFactory.create(CalcOperation.MULTIPLY));
}
@Test
void createsDivideFunction() {
assertInstanceOf(DivideFunction.class, CalcFunctionFactory.create(CalcOperation.DIVIDE));
}
@Test
void createsPowerFunction() {
assertInstanceOf(PowerFunction.class, CalcFunctionFactory.create(CalcOperation.POWER));
}
@Test
void createsFunctionForEveryOperation() {
for (CalcOperation operation : CalcOperation.values()) {
assertNotNull(CalcFunctionFactory.create(operation), "No function for " + operation);
}
}
@Test
void createdFunctionCalculates() {
assertEquals(13.0, CalcFunctionFactory.create(CalcOperation.ADD).calc(2.0, 5.0, 6.0));
}
@Test
void rejectsNullOperation() {
assertThrows(IllegalArgumentException.class, () -> CalcFunctionFactory.create(null));
}
}
@@ -0,0 +1,35 @@
package com.example.util;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class PowerFunctionTest {
private final PowerFunction powerFunction = new PowerFunction();
@Test
void raisesMultipleValuesLeftToRight() {
assertEquals(1073741824.0, powerFunction.calc(2.0, 5.0, 6.0));
}
@Test
void returnsSingleValue() {
assertEquals(5.0, powerFunction.calc(5.0));
}
@Test
void returnsZeroForNoInput() {
assertEquals(0.0, powerFunction.calc());
}
@Test
void raisesToNegativeExponent() {
assertEquals(0.25, powerFunction.calc(2.0, -2.0));
}
@Test
void raisesToZeroExponent() {
assertEquals(1.0, powerFunction.calc(7.0, 0.0));
}
}