- Enhanced Biome config with test file override for noConsole - Applied Biome auto-fixes (8 files: formatting, template literals, optional chains) - Updated all package repository URLs to git.shazhou.work/uncaged/workflow.git - Added workflow-agent-claude-code to publish order in scripts/publish-all.mjs - Added --ignore-scripts flag to publish command to bypass prepublishOnly guard - Installed vitest in root devDependencies for test infrastructure - Created vitest.config.ts for all 8 packages with passWithNoTests: true - Fixed 3 test files to use vitest imports instead of bun:test - Added test and test:ci scripts to packages missing them - Added missing build step to .gitea/workflows/ci.yml - Renamed CI job from 'test' to 'check' for clarity - Created workflows/solve-issue.yaml with TDD-driven issue resolution workflow - Registered solve-issue workflow with uwf (hash: 084YVM60BR8G6) - Added packageManager: bun@1.3.14 to root package.json - Added preinstall guard to block npm/pnpm/yarn - Added prepublishOnly guard to root and all 7 public packages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,18 +7,19 @@ on:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
- run: bun install
|
||||
|
||||
- name: Check
|
||||
- name: Build
|
||||
run: bun run build
|
||||
|
||||
- name: Lint
|
||||
run: bun run check
|
||||
|
||||
- name: Test
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@
|
||||
"linter": {
|
||||
"rules": {
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off"
|
||||
"noExplicitAny": "off",
|
||||
"noConsole": "off"
|
||||
},
|
||||
"style": {
|
||||
"noNonNullAssertion": "off"
|
||||
|
||||
+6
-1
@@ -1,11 +1,14 @@
|
||||
{
|
||||
"name": "@uncaged/workflow-monorepo",
|
||||
"private": true,
|
||||
"packageManager": "bun@1.3.14",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"uwf": "bun packages/cli-workflow/src/cli.ts",
|
||||
"preinstall": "npx only-allow bun",
|
||||
"prepublishOnly": "echo 'Use bun run release instead' && exit 1",
|
||||
"build": "bunx tsc --build",
|
||||
"check": "bunx tsc --build && biome check . && bash scripts/lint-log-tags.sh",
|
||||
"typecheck": "bunx tsc --build",
|
||||
@@ -23,7 +26,9 @@
|
||||
"@types/node": "^25.7.0",
|
||||
"@types/xxhashjs": "^0.2.4",
|
||||
"@uncaged/workflow-agent-hermes": "workspace:*",
|
||||
"bun-types": "^1.3.13"
|
||||
"bun-types": "^1.3.13",
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^4.1.7"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"yaml": "^2.8.4"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
@@ -34,12 +35,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/cli-workflow"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ describe("solve-issue workflow: tea pr create worktree fix", () => {
|
||||
expect(frontmatter).toBeDefined();
|
||||
expect(frontmatter?.oneOf).toBeDefined();
|
||||
const committedVariant = frontmatter.oneOf.find(
|
||||
(v: any) => v.properties?.["$status"]?.const === "committed",
|
||||
(v: any) => v.properties?.$status?.const === "committed",
|
||||
);
|
||||
expect(committedVariant).toBeDefined();
|
||||
expect(committedVariant.required).toContain("$status");
|
||||
|
||||
@@ -56,7 +56,7 @@ const VALID_OUTPUT: AdapterOutput = {
|
||||
|
||||
describe("spawnAgent JSON parsing", () => {
|
||||
test("B1. parses valid JSON from agent stdout", () => {
|
||||
const stdout = JSON.stringify(VALID_OUTPUT) + "\n";
|
||||
const stdout = `${JSON.stringify(VALID_OUTPUT)}\n`;
|
||||
const result = parseAgentStdout(stdout);
|
||||
expect(result.stepHash).toBe("0123456789ABC");
|
||||
expect(result.detailHash).toBe("DEFGH12345678");
|
||||
@@ -68,7 +68,7 @@ describe("spawnAgent JSON parsing", () => {
|
||||
});
|
||||
|
||||
test("B2. extracts stepHash for head pointer", () => {
|
||||
const stdout = JSON.stringify(VALID_OUTPUT) + "\n";
|
||||
const stdout = `${JSON.stringify(VALID_OUTPUT)}\n`;
|
||||
const result = parseAgentStdout(stdout);
|
||||
expect(result.stepHash).toBe("0123456789ABC");
|
||||
expect(isCasRef(result.stepHash)).toBe(true);
|
||||
@@ -76,7 +76,7 @@ describe("spawnAgent JSON parsing", () => {
|
||||
|
||||
test("B3. handles debug lines before JSON", () => {
|
||||
const debugLines = "[debug] loading context...\n[debug] running agent...\n";
|
||||
const stdout = debugLines + JSON.stringify(VALID_OUTPUT) + "\n";
|
||||
const stdout = `${debugLines + JSON.stringify(VALID_OUTPUT)}\n`;
|
||||
const result = parseAgentStdout(stdout);
|
||||
expect(result.stepHash).toBe("0123456789ABC");
|
||||
});
|
||||
@@ -88,13 +88,13 @@ describe("spawnAgent JSON parsing", () => {
|
||||
|
||||
test("B5. rejects JSON missing stepHash", () => {
|
||||
const incomplete = { detailHash: "DEFGH12345678", role: "planner" };
|
||||
const stdout = JSON.stringify(incomplete) + "\n";
|
||||
const stdout = `${JSON.stringify(incomplete)}\n`;
|
||||
expect(() => parseAgentStdout(stdout)).toThrow("missing valid stepHash");
|
||||
});
|
||||
|
||||
test("B6. rejects JSON with invalid stepHash", () => {
|
||||
const bad = { ...VALID_OUTPUT, stepHash: "not-a-hash" };
|
||||
const stdout = JSON.stringify(bad) + "\n";
|
||||
const stdout = `${JSON.stringify(bad)}\n`;
|
||||
expect(() => parseAgentStdout(stdout)).toThrow("missing valid stepHash");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,12 +5,7 @@ export {
|
||||
generateUserReference as cmdSkillUser,
|
||||
} from "@uncaged/workflow-util";
|
||||
|
||||
const SKILL_NAMES = [
|
||||
"user",
|
||||
"author",
|
||||
"developer",
|
||||
"adapter",
|
||||
] as const;
|
||||
const SKILL_NAMES = ["user", "author", "developer", "adapter"] as const;
|
||||
|
||||
export function cmdSkillList(): ReadonlyArray<string> {
|
||||
return [...SKILL_NAMES];
|
||||
|
||||
@@ -3,5 +3,6 @@ import { defineConfig } from "vitest/config";
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "bun test",
|
||||
"test:ci": "bun test"
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/json-cas": "^0.5.3",
|
||||
@@ -34,12 +35,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/workflow-agent-builtin"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
@@ -18,8 +18,9 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "bun test",
|
||||
"test:ci": "bun test"
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/json-cas": "^0.5.3",
|
||||
@@ -34,12 +35,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/workflow-agent-claude-code"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -152,9 +152,7 @@ async function runClaudeCode(ctx: AgentContext): Promise<AgentRunResult> {
|
||||
} catch (err) {
|
||||
log(
|
||||
"5VKR8N3Q",
|
||||
"resume failed for session %s, falling back to fresh run: %s",
|
||||
cachedSessionId,
|
||||
err,
|
||||
`resume failed for session ${cachedSessionId}, falling back to fresh run: ${err}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
@@ -18,8 +18,9 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "bun test",
|
||||
"test:ci": "bun test __tests__/*.test.ts"
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/json-cas": "^0.5.3",
|
||||
@@ -35,12 +36,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/workflow-agent-hermes"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"engines": {
|
||||
"bun": ">= 1.0.0"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
@@ -5,7 +5,9 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "bun server.ts",
|
||||
"build": "vite build"
|
||||
"build": "vite build",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "^1.5.0",
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/json-cas": "^0.5.3",
|
||||
"@uncaged/json-cas-fs": "^0.5.3"
|
||||
@@ -26,12 +31,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/workflow-protocol"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import type { StartNodePayload, StepRecord, Target } from "../types.js";
|
||||
|
||||
describe("Protocol types for thread/edge location", () => {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
@@ -15,8 +15,9 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "bun test",
|
||||
"test:ci": "bun test"
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/json-cas": "^0.5.3",
|
||||
@@ -34,12 +35,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/workflow-util-agent"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
describe("parseArgv empty prompt error message", () => {
|
||||
let stderrOutput: string;
|
||||
|
||||
@@ -214,7 +214,7 @@ function getConstValue(propSchema: JSONSchema): string {
|
||||
function buildVariantBlock(variant: JSONSchema, discriminant: string): string {
|
||||
const props = extractSchemaProperties(variant);
|
||||
const value = getConstValue(
|
||||
((variant.properties as Record<string, JSONSchema>) ?? {})[discriminant] ?? {},
|
||||
(variant.properties as Record<string, JSONSchema>)?.[discriminant] ?? {},
|
||||
);
|
||||
const yamlExample = buildYamlExampleBlock(props);
|
||||
const fieldList = buildFieldList(props);
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [{ "path": "../workflow-protocol" }]
|
||||
"references": [{ "path": "../workflow-protocol" }, { "path": "../workflow-util" }]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
@@ -14,6 +14,11 @@
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "echo 'Use bun run release from repo root' && exit 1",
|
||||
"test": "vitest run",
|
||||
"test:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.3"
|
||||
@@ -23,12 +28,12 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow.git",
|
||||
"url": "https://git.shazhou.work/uncaged/workflow.git",
|
||||
"directory": "packages/workflow-util"
|
||||
},
|
||||
"homepage": "https://github.com/shazhou-ww/uncaged-workflow#readme",
|
||||
"homepage": "https://git.shazhou.work/uncaged/workflow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/shazhou-ww/uncaged-workflow/issues"
|
||||
"url": "https://git.shazhou.work/uncaged/workflow/issues"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { extractUlidTimestamp, generateUlid } from "../ulid.js";
|
||||
|
||||
describe("extractUlidTimestamp", () => {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/__tests__/**/*.test.ts"],
|
||||
passWithNoTests: true,
|
||||
},
|
||||
});
|
||||
@@ -21,6 +21,7 @@ const publishOrder = [
|
||||
"workflow-util-agent",
|
||||
"workflow-agent-hermes",
|
||||
"workflow-agent-builtin",
|
||||
"workflow-agent-claude-code",
|
||||
"cli-workflow",
|
||||
];
|
||||
|
||||
@@ -59,7 +60,7 @@ let failed = false;
|
||||
for (const name of publishOrder) {
|
||||
const pkgDir = join(root, "packages", name);
|
||||
const tagFlag = tag ? `--tag ${tag}` : "";
|
||||
const cmd = `npm publish --access public ${tagFlag}`;
|
||||
const cmd = `npm publish --access public --ignore-scripts ${tagFlag}`;
|
||||
|
||||
console.log(`📦 ${name}...`);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
{ "path": "packages/workflow-util-agent" },
|
||||
{ "path": "packages/workflow-agent-hermes" },
|
||||
{ "path": "packages/workflow-agent-builtin" },
|
||||
{ "path": "packages/workflow-agent-claude-code" },
|
||||
{ "path": "packages/cli-workflow" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
name: "solve-issue"
|
||||
description: "TDD-driven issue resolution adapted for the workflow monorepo with bun + vitest"
|
||||
roles:
|
||||
planner:
|
||||
description: "Analyzes issue and outputs a TDD test spec"
|
||||
goal: "You are a planning agent. You analyze Gitea issues and produce a TDD test specification that downstream roles will implement and verify."
|
||||
capabilities:
|
||||
- issue-analysis
|
||||
- planning
|
||||
procedure: |
|
||||
On first run (no previous steps):
|
||||
1. Read the issue and all comments from Gitea using `tea issues <number> -r <owner/repo>`
|
||||
2. Look for project conventions files (CLAUDE.md, CONTRIBUTING.md) in the repo
|
||||
3. Assess whether the issue has enough information to produce a test spec
|
||||
4. If insufficient info: comment on the issue via `echo "..." | tea comment <number> -r <owner/repo>` (skip if you already commented), then output $status=insufficient_info
|
||||
5. If sufficient: produce a detailed TDD test spec in markdown covering all scenarios
|
||||
|
||||
On subsequent runs (bounced back by tester with fix_spec):
|
||||
1. Read the tester's output from the previous step to understand what's wrong with the spec
|
||||
2. Revise the test spec accordingly
|
||||
|
||||
After producing the test spec:
|
||||
1. Store it via `uwf cas put-text "<markdown content>"` and capture the returned hash
|
||||
2. Put the hash in frontmatter.plan (required when $status=ready)
|
||||
3. Set repoPath to the absolute path of the repository root
|
||||
output: "Output a brief summary of the test spec. Set $status to ready (with plan hash and repoPath) or insufficient_info."
|
||||
frontmatter:
|
||||
oneOf:
|
||||
- properties:
|
||||
$status: { const: "ready" }
|
||||
plan: { type: string }
|
||||
repoPath: { type: string }
|
||||
required: [$status, plan, repoPath]
|
||||
- properties:
|
||||
$status: { const: "insufficient_info" }
|
||||
required: [$status]
|
||||
developer:
|
||||
description: "TDD implementation per test spec"
|
||||
goal: "You are a developer agent. You implement code changes following TDD — write tests first, then implementation."
|
||||
capabilities:
|
||||
- coding
|
||||
procedure: |
|
||||
IMPORTANT: Always work in a git worktree, NEVER modify the main working directory directly.
|
||||
The repo path and other details are provided in your task prompt.
|
||||
|
||||
Before starting any work, set up an isolated worktree:
|
||||
1. cd into the repo path provided in your task prompt
|
||||
2. `git fetch origin` to get latest refs
|
||||
3. First time (no existing branch):
|
||||
- `git worktree add .worktrees/fix/<issue-number>-<short-slug> -b fix/<issue-number>-<short-slug> origin/main`
|
||||
- `cd .worktrees/fix/<issue-number>-<short-slug> && bun install`
|
||||
4. If bounced back from reviewer or tester (branch already exists):
|
||||
- cd into the existing worktree under `.worktrees/fix/<issue-number>-<short-slug>`
|
||||
- `git fetch origin && git rebase origin/main`
|
||||
5. ALL subsequent work must happen inside the worktree directory.
|
||||
|
||||
Then implement TDD:
|
||||
6. Read the test spec from CAS: `uwf cas get <plan hash>` (find the hash from the planner's output in your task prompt)
|
||||
7. If bounced back from reviewer or tester: read the previous role's feedback in your task prompt
|
||||
8. Write tests first based on the spec (use vitest)
|
||||
9. Implement the code to make tests pass
|
||||
10. Ensure `bun run build` passes with no errors
|
||||
11. Run `bun test` to verify all tests pass
|
||||
|
||||
If you cannot complete the implementation (e.g. the issue is too complex, blocked by external factors,
|
||||
or repeated attempts fail), set $status=failed with a reason.
|
||||
output: "List all files changed and provide a summary. Set $status to done (with branch/worktree), or failed (with reason)."
|
||||
frontmatter:
|
||||
oneOf:
|
||||
- properties:
|
||||
$status: { const: "done" }
|
||||
branch: { type: string }
|
||||
worktree: { type: string }
|
||||
required: [$status, branch, worktree]
|
||||
- properties:
|
||||
$status: { const: "failed" }
|
||||
reason: { type: string }
|
||||
required: [$status, reason]
|
||||
reviewer:
|
||||
description: "Code standards compliance check"
|
||||
goal: "You are a code reviewer. You verify code standards compliance — NOT functionality (that's the tester's job)."
|
||||
capabilities:
|
||||
- code-review
|
||||
- static-analysis
|
||||
procedure: |
|
||||
The worktree path is provided in your task prompt. cd into it first.
|
||||
|
||||
Before reviewing, verify the git branch:
|
||||
1. Run `git branch --show-current` — confirm the branch name references the issue number being worked on
|
||||
2. If the branch doesn't correspond to the issue, flag it in your output and reject
|
||||
|
||||
Then perform code review:
|
||||
Hard checks (must all pass):
|
||||
3. `bun run build` — no build errors
|
||||
4. `bunx biome check` — no lint violations
|
||||
5. TypeScript strict mode — no type errors
|
||||
|
||||
Soft checks (review against project conventions from CLAUDE.md):
|
||||
- Functional-first: functions + types, no classes (except for errors or third-party requirements)
|
||||
- Named exports only, no default exports
|
||||
- No optional properties (use `T | null` instead of `?:`)
|
||||
- Folder module discipline: index.ts only re-exports, types in types.ts
|
||||
- Crockford Base32 log tags (8-char, unique per call site)
|
||||
- No `console.log` in production code (use createLogger from @uncaged/workflow-util)
|
||||
- No dynamic imports in production code
|
||||
|
||||
Only review standards compliance. Do NOT test functionality.
|
||||
If rejecting, you MUST explain the specific reason in your output.
|
||||
output: "Explain your decision with specific file/line references. Set $status to approved (with branch/worktree) or rejected (with comments)."
|
||||
frontmatter:
|
||||
oneOf:
|
||||
- properties:
|
||||
$status: { const: "approved" }
|
||||
branch: { type: string }
|
||||
worktree: { type: string }
|
||||
required: [$status, branch, worktree]
|
||||
- properties:
|
||||
$status: { const: "rejected" }
|
||||
comments: { type: string }
|
||||
worktree: { type: string }
|
||||
required: [$status, comments, worktree]
|
||||
tester:
|
||||
description: "Functional correctness verification"
|
||||
goal: "You are a tester agent. You verify that the implementation correctly satisfies every scenario in the test spec."
|
||||
capabilities:
|
||||
- testing
|
||||
procedure: |
|
||||
The worktree path is provided in your task prompt. cd into it first.
|
||||
|
||||
1. Run `bun test` for automated test verification
|
||||
2. Read the test spec from CAS: `uwf cas get <plan hash>` (find the hash from the planner step in the thread history)
|
||||
3. Verify each scenario in the spec is covered and passing
|
||||
4. Determine outcome:
|
||||
- passed: all scenarios verified, tests pass
|
||||
- fix_code: tests fail or implementation doesn't match spec → send back to developer
|
||||
- fix_spec: the spec itself is wrong or incomplete → send back to planner
|
||||
output: "Report test results per scenario. Set $status to passed (with branch/worktree), fix_code (with report), or fix_spec (with report)."
|
||||
frontmatter:
|
||||
oneOf:
|
||||
- properties:
|
||||
$status: { const: "passed" }
|
||||
branch: { type: string }
|
||||
worktree: { type: string }
|
||||
required: [$status, branch, worktree]
|
||||
- properties:
|
||||
$status: { const: "fix_code" }
|
||||
report: { type: string }
|
||||
required: [$status, report]
|
||||
- properties:
|
||||
$status: { const: "fix_spec" }
|
||||
report: { type: string }
|
||||
required: [$status, report]
|
||||
committer:
|
||||
description: "Commits and creates PR"
|
||||
goal: "You are a committer agent. You create a clean commit and push a PR linking the original issue."
|
||||
capabilities: []
|
||||
procedure: |
|
||||
The worktree path, branch name, and repo info are provided in your task prompt.
|
||||
cd into the worktree first.
|
||||
|
||||
Note: You inherit the developer's worktree and branch. Do NOT create a new branch.
|
||||
1. Stage all changes: `git add -A`
|
||||
2. Commit with a descriptive message referencing the issue: `git commit -m "type: description\n\nFixes #N"`
|
||||
3. Push the branch: `git push -u origin <branch-name>`
|
||||
- If push hook fails: capture the error log in your output, mark hook_failed
|
||||
4. On push success: create a PR via `tea pr create --repo <owner/repo> --title "..." --description "..."`
|
||||
- Extract owner/repo from: `git remote get-url origin | sed 's/.*[:/]\([^/]*\/[^.]*\).*/\1/'`
|
||||
- PR description must include: What / Why / Changes / Ref sections, with `Fixes #N` in Ref
|
||||
- On tea failure: capture stderr/stdout, include PR details for manual creation, mark hook_failed
|
||||
5. After PR creation, clean up the worktree:
|
||||
- cd to the repo root (parent of .worktrees)
|
||||
- `git worktree remove <worktree-path>`
|
||||
output: "Include PR URL on success or error log on failure. Set $status to committed (with prUrl) or hook_failed (with error)."
|
||||
frontmatter:
|
||||
oneOf:
|
||||
- properties:
|
||||
$status: { const: "committed" }
|
||||
prUrl: { type: string }
|
||||
required: [$status, prUrl]
|
||||
- properties:
|
||||
$status: { const: "hook_failed" }
|
||||
error: { type: string }
|
||||
required: [$status, error]
|
||||
graph:
|
||||
$START:
|
||||
_: { role: "planner", prompt: "Analyze the issue and produce an implementation plan." }
|
||||
planner:
|
||||
insufficient_info: { role: "$END", prompt: "Insufficient information to proceed; end the workflow." }
|
||||
ready: { role: "developer", prompt: "Implement the TDD test spec (CAS hash: {{{plan}}}) in repo {{{repoPath}}}." }
|
||||
developer:
|
||||
done: { role: "reviewer", prompt: "Review branch {{{branch}}} at {{{worktree}}} for code standards compliance." }
|
||||
failed: { role: "$END", prompt: "Developer failed: {{{reason}}}. Ending workflow." }
|
||||
reviewer:
|
||||
rejected: { role: "developer", prompt: "Reviewer rejected: {{{comments}}}. Fix the issues in repo {{{worktree}}}." }
|
||||
approved: { role: "tester", prompt: "Review passed. Run tests on branch {{{branch}}} at {{{worktree}}}." }
|
||||
tester:
|
||||
fix_code: { role: "developer", prompt: "Tests found code issues: {{{report}}}. Fix and re-submit." }
|
||||
fix_spec: { role: "planner", prompt: "Tests found spec issues: {{{report}}}. Revise the test spec." }
|
||||
passed: { role: "committer", prompt: "All tests passed. Commit and push branch {{{branch}}} from {{{worktree}}}." }
|
||||
committer:
|
||||
hook_failed: { role: "developer", prompt: "Push hook failed: {{{error}}}. Fix and re-submit." }
|
||||
committed: { role: "$END", prompt: "PR created: {{{prUrl}}}. Workflow complete." }
|
||||
Reference in New Issue
Block a user