diff --git a/AGENTS.md b/AGENTS.md index 517700e..f646e18 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -61,17 +61,14 @@ packages/opencode/.opencode/ # Generated OpenCode output for review - Use angle-bracket placeholders consistently for derived values and stored context, such as ``, ``, ``, ``, and define each placeholder before it is referenced later in the command - When referring to placeholders literally in prose, always wrap them in backticks, such as `` or ``; keep output examples plain when the placeholder represents substituted user-facing text - If arguments can mean different things, explicitly disambiguate them in `### Interpret Arguments` and store each interpretation in a separate placeholder -- For navigator-style commands, separate context loading, blocker checks, delegated execution, and final reporting into distinct workflow subsections so the control flow is easy to follow -- Prefer explicit subsection names like `### Load ... Context`, `### Check Blockers`, `### Delegate ...`, and `### Mark Complete And Loop` when the command coordinates multiple phases or subagents +- For multi-step commands, separate context loading, blocker checks, execution, and final reporting into distinct workflow subsections so the control flow is easy to follow +- Prefer explicit subsection names like `### Load ... Context`, `### Check Blockers`, and `### Mark Complete And Loop` when a command coordinates multiple phases - Treat loader tools and provided attachments as the source of truth for orchestration inputs; avoid extra exploratory commands when an existing tool result already answers the question -- Before dispatching a same-session command step, say what delegated result should be stored and whether the workflow must stop, pause, or continue based on that result -- Use literal `` tags when the workflow must delegate exact text through `command_expansion`; `agent` and `command` are required, and the block body is the exact rendered body to send for that command -- Do not use `` blocks in command docs; author navigator delegation with `` blocks only -- Do not restate `command_expansion` or `task` mechanics inside command docs; navigator owns that execution flow +- Reuse component phases within a command so state can be carried forward without repeated loader calls - When a command can pause for approval or loop over repeated work, describe the resume condition and the exact cases that must STOP without mutating state - Use `## Additional Context` for instructions about how optional guidance, related tickets, focus areas, or other stored context should influence analysis and response formatting - Use `### Output` as the final workflow step to define the exact user-facing response shape, including placeholders for generated values -- Make success, blocked, no-op, waiting, and resume-required outcomes explicit in `### Output` or the surrounding workflow so navigator-led flows report deterministic end states +- Make success, blocked, no-op, waiting, and resume-required outcomes explicit in `### Output` or the surrounding workflow so multi-step flows report deterministic end states - For terminal command outcomes, prefer an explicit final line inside the output block: `No additional steps are required.` - Omit that final line for outputs that intentionally wait for approval, pause for resume, loop to the next task, or otherwise continue beyond the current checkpoint - For one-off commands that do not orchestrate follow-up work, make every success, blocked, or no-op output explicitly terminal with that final line @@ -106,28 +103,10 @@ $ARGUMENTS - Load the required file, ticket, or PR context - STOP if the source of truth cannot be loaded -### Delegate Planning +### Execute Workflow - - -Task: -Task context: -Additional context: - - -- Store the delegated result as `` -- STOP if planning is blocked or unusable - -### Delegate Implementation - - - -Plan: -Constraints: - - -- Store the delegated result as `` -- STOP if implementation is blocked or incomplete +- Run reusable component phases inline and preserve their named results +- STOP if a required phase is blocked or incomplete ### Output @@ -135,18 +114,6 @@ Constraints: - For terminal outcomes, end the output block with `No additional steps are required.` Omit that line when the command is intentionally waiting, looping, or continuing. ``` -Example delegation rule: - -```text -Before delegation, write the exact `...` block, say what delegated result should be stored, and whether the workflow should continue or STOP based on that result. -``` - -Example literal session command rule: - -```text -Before literal command forwarding, write the exact `...` block, then let navigator expand and execute it, and say what delegated result should be stored and whether the workflow should continue or STOP based on that result. -``` - ## Component Authoring - Store reusable command fragments in `packages/core/components/` diff --git a/README.md b/README.md index fa25895..57782ef 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ Kompass keeps AI coding agents on course with token-efficient, composable workfl ## Bundled Surface -- Commands cover direct work (`/ask`, `/commit`, `/merge`, `/skill/create`, `/skill/optimize`), orchestration (`/dev`, `/ship`, `/todo`, `/loop/pr/fix`), ticket planning/sync, and PR review/shipping flows. -- Agents are intentionally narrow: `worker` is generic, `planner` is no-edit planning, `navigator` owns multi-step orchestration, and `reviewer` is a no-edit review specialist. -- Structured tools keep workflows grounded in repo and GitHub state: `changes_load`, `command_expansion` (resolve a slash command and return the expanded prompt for immediate delegation), `pr_load`, `pr_sync`, `ticket_load`, `ticket_sync`. +- Commands cover direct work (`/ask`, `/commit`, `/merge`, `/skill/create`, `/skill/optimize`), orchestration (`/dev`, `/ship`, `/todo`, `/pr/fix/loop`), ticket planning/sync, and PR review/shipping flows. `/branch/inline`, `/commit/inline`, `/commit-and-push/inline`, `/pr/create/inline`, and `/ship/inline` reuse the invoking session instead of starting a subtask. +- Agents are intentionally narrow: `worker` handles implementation and multi-step workflows, `planner` is no-edit planning, and `reviewer` is a no-edit review specialist. +- Structured tools keep workflows grounded in repo and GitHub state: `changes_load`, `pr_load`, `pr_load_review`, `pr_sync`, `ticket_load`, `ticket_sync`. - Reusable command-template components live in `packages/core/components/` and are documented in the components reference. ## Prerequisites diff --git a/kompass.jsonc b/kompass.jsonc index ad61bfa..6260572 100644 --- a/kompass.jsonc +++ b/kompass.jsonc @@ -13,19 +13,24 @@ "commands": { "ask": { "enabled": true }, "branch": { "enabled": true }, + "branch/inline": { "enabled": true }, "commit": { "enabled": true }, + "commit/inline": { "enabled": true }, "commit-and-push": { "enabled": true }, + "commit-and-push/inline": { "enabled": true }, "dev": { "enabled": true }, "learn": { "enabled": true }, - "loop/pr/fix": { "enabled": true }, "merge": { "enabled": true }, "pr/create": { "enabled": true }, + "pr/create/inline": { "enabled": true }, "pr/fix": { "enabled": true }, + "pr/fix/loop": { "enabled": true }, "pr/review": { "enabled": true }, "review": { "enabled": true }, "skill/create": { "enabled": true }, "skill/optimize": { "enabled": true }, "ship": { "enabled": true }, + "ship/inline": { "enabled": true }, "rmslop": { "enabled": true }, "todo": { "enabled": true }, "ticket/ask": { "enabled": true }, @@ -37,15 +42,14 @@ "agents": { "worker": { "enabled": true }, - "navigator": { "enabled": true }, "planner": { "enabled": true }, "reviewer": { "enabled": true }, }, "tools": { "changes_load": { "enabled": true }, - "command_expansion": { "enabled": true }, "pr_load": { "enabled": true }, + "pr_load_review": { "enabled": true }, "pr_sync": { "enabled": true }, "ticket_load": { "enabled": true }, "ticket_sync": { "enabled": true }, @@ -53,13 +57,18 @@ "components": { "change-summary": { "enabled": true }, + "branch": { "enabled": true }, "changes-summary": { "enabled": true }, "commit": { "enabled": true }, "dev-flow": { "enabled": true }, "load-pr": { "enabled": true }, "load-ticket": { "enabled": true }, + "pr-create": { "enabled": true }, + "pr-branch-update": { "enabled": true }, + "pr-fix": { "enabled": true }, + "push": { "enabled": true }, "skill-authoring": { "enabled": true }, - "summarize-changes": { "enabled": true }, + "ticket-planning": { "enabled": true }, }, "defaults": { diff --git a/kompass.schema.json b/kompass.schema.json index 2faf9b6..71d60cc 100644 --- a/kompass.schema.json +++ b/kompass.schema.json @@ -38,19 +38,25 @@ "branch": { "$ref": "#/$defs/commandConfig" }, + "branch/inline": { + "$ref": "#/$defs/commandConfig" + }, "commit": { "$ref": "#/$defs/commandConfig" }, + "commit/inline": { + "$ref": "#/$defs/commandConfig" + }, "commit-and-push": { "$ref": "#/$defs/commandConfig" }, - "dev": { + "commit-and-push/inline": { "$ref": "#/$defs/commandConfig" }, - "learn": { + "dev": { "$ref": "#/$defs/commandConfig" }, - "loop/pr/fix": { + "learn": { "$ref": "#/$defs/commandConfig" }, "merge": { @@ -59,9 +65,15 @@ "pr/create": { "$ref": "#/$defs/commandConfig" }, + "pr/create/inline": { + "$ref": "#/$defs/commandConfig" + }, "pr/fix": { "$ref": "#/$defs/commandConfig" }, + "pr/fix/loop": { + "$ref": "#/$defs/commandConfig" + }, "pr/review": { "$ref": "#/$defs/commandConfig" }, @@ -77,6 +89,9 @@ "ship": { "$ref": "#/$defs/commandConfig" }, + "ship/inline": { + "$ref": "#/$defs/commandConfig" + }, "rmslop": { "$ref": "#/$defs/commandConfig" }, @@ -105,19 +120,24 @@ "enum": [ "ask", "branch", + "branch/inline", "commit", + "commit/inline", "commit-and-push", + "commit-and-push/inline", "dev", "learn", - "loop/pr/fix", "merge", "pr/create", + "pr/create/inline", "pr/fix", + "pr/fix/loop", "pr/review", "review", "skill/create", "skill/optimize", "ship", + "ship/inline", "rmslop", "todo", "ticket/ask", @@ -136,19 +156,24 @@ "enum": [ "ask", "branch", + "branch/inline", "commit", + "commit/inline", "commit-and-push", + "commit-and-push/inline", "dev", "learn", - "loop/pr/fix", "merge", "pr/create", + "pr/create/inline", "pr/fix", + "pr/fix/loop", "pr/review", "review", "skill/create", "skill/optimize", "ship", + "ship/inline", "rmslop", "todo", "ticket/ask", @@ -172,9 +197,6 @@ "worker": { "$ref": "#/$defs/agentConfig" }, - "navigator": { - "$ref": "#/$defs/agentConfig" - }, "planner": { "$ref": "#/$defs/agentConfig" }, @@ -185,7 +207,7 @@ "type": "array", "items": { "type": "string", - "enum": ["worker", "navigator", "planner", "reviewer"] + "enum": ["worker", "planner", "reviewer"] }, "uniqueItems": true, "deprecated": true @@ -199,10 +221,10 @@ "changes_load": { "$ref": "#/$defs/toolConfig" }, - "command_expansion": { + "pr_load": { "$ref": "#/$defs/toolConfig" }, - "pr_load": { + "pr_load_review": { "$ref": "#/$defs/toolConfig" }, "pr_sync": { @@ -223,6 +245,9 @@ "change-summary": { "$ref": "#/$defs/componentConfig" }, + "branch": { + "$ref": "#/$defs/componentConfig" + }, "changes-summary": { "$ref": "#/$defs/componentConfig" }, @@ -238,17 +263,29 @@ "load-ticket": { "$ref": "#/$defs/componentConfig" }, + "pr-create": { + "$ref": "#/$defs/componentConfig" + }, + "pr-branch-update": { + "$ref": "#/$defs/componentConfig" + }, + "pr-fix": { + "$ref": "#/$defs/componentConfig" + }, + "push": { + "$ref": "#/$defs/componentConfig" + }, "skill-authoring": { "$ref": "#/$defs/componentConfig" }, - "summarize-changes": { + "ticket-planning": { "$ref": "#/$defs/componentConfig" }, "enabled": { "type": "array", "items": { "type": "string", - "enum": ["change-summary", "changes-summary", "commit", "dev-flow", "load-pr", "load-ticket", "skill-authoring", "summarize-changes"] + "enum": ["branch", "change-summary", "changes-summary", "commit", "dev-flow", "load-pr", "load-ticket", "pr-create", "pr-branch-update", "pr-fix", "push", "skill-authoring", "ticket-planning"] }, "uniqueItems": true, "deprecated": true @@ -256,7 +293,7 @@ "paths": { "type": "object", "propertyNames": { - "enum": ["change-summary", "changes-summary", "commit", "dev-flow", "load-pr", "load-ticket", "skill-authoring", "summarize-changes"] + "enum": ["branch", "change-summary", "changes-summary", "commit", "dev-flow", "load-pr", "load-ticket", "pr-create", "pr-branch-update", "pr-fix", "push", "skill-authoring", "ticket-planning"] }, "additionalProperties": { "type": "string" @@ -391,8 +428,8 @@ "type": "string", "enum": [ "changes_load", - "command_expansion", "pr_load", + "pr_load_review", "pr_sync", "ticket_sync", "ticket_load" diff --git a/packages/core/agents/index.ts b/packages/core/agents/index.ts index 4fabcf6..7916f77 100644 --- a/packages/core/agents/index.ts +++ b/packages/core/agents/index.ts @@ -21,7 +21,6 @@ export interface ResolvedAgentDefinition export function getAgentDefinitions(config: ReturnType): Record { return { worker: config.agents.worker, - navigator: config.agents.navigator, reviewer: config.agents.reviewer, planner: config.agents.planner, }; diff --git a/packages/core/agents/navigator.md b/packages/core/agents/navigator.md deleted file mode 100644 index 6016874..0000000 --- a/packages/core/agents/navigator.md +++ /dev/null @@ -1,31 +0,0 @@ -You coordinate structured, multi-step workflows. - -## Rules - -- Follow the active command and provided context. -- Manage step order, stored state, approvals, and stop conditions yourself. -- Load only the context needed for the current step. -- Execute required user-interaction steps exactly as the command defines them; if a required interaction tool is unavailable, use the command's non-interactive fallback. -- If a step is blocked, incomplete, or fails, stop and report it clearly. - -## Delegation - -When you see a `...` block, you MUST make TWO tool calls in sequence: - -1. **Expand**: Call `<%= it.config.tools.command_expansion.name %>` with `command` from the tag and `body` set to the rendered block content -2. **Delegate**: IMMEDIATELY call `task` with `subagent_type: AGENT_NAME` and `prompt` set to the expanded text from step 1 - -**CRITICAL RULES:** -- These are TWO SEPARATE tool calls. You must call BOTH. -- DO NOT execute the expanded content yourself. Your job is to DELEGATE via `task`. -- The `task` result IS the delegated result. Use it as the source of truth. -- If you don't call `task`, the delegation is incomplete and will fail. - -- Treat each `` block as literal input; do not rewrite or interpret before expansion. -- Run `` blocks sequentially unless the workflow clearly makes them independent. -- If a `` block is malformed, the expansion fails, or the delegated `task` fails, stop and report it clearly. - -## Output - -- Follow any explicit command output exactly. -- Otherwise report what finished and whether the workflow is continuing, paused, blocked, or complete. diff --git a/packages/core/agents/reviewer.md b/packages/core/agents/reviewer.md index 7a80d50..62ebaef 100644 --- a/packages/core/agents/reviewer.md +++ b/packages/core/agents/reviewer.md @@ -14,6 +14,7 @@ Before reviewing, always check repository guidance: - In CI or shallow clones, pass explicit base and head refs - For branch comparisons, treat the returned commit list as the authoritative scope: review the commits ahead of base and use file diffs only as supporting context - Scan the summary first to understand scope, file states, and risk clusters + - If the result reports deferred diffs, inspect them directly one file at a time using the returned comparison and changed paths - Never switch branches, create local review branches, or otherwise mutate `HEAD`; if a loader fails, prefer reporting the blocker over changing checkout state 2. **Read Code**: Read every changed file individually before finalizing diff --git a/packages/core/commands/branch.md b/packages/core/commands/branch.md index 607a7de..b83f371 100644 --- a/packages/core/commands/branch.md +++ b/packages/core/commands/branch.md @@ -1,6 +1,6 @@ ## Goal -Create and switch to a categorized branch whose name summarizes the current uncommitted work. +Create and switch to a categorized branch whose name summarizes the current uncommitted work.<% if (it.inline) { %> Reuse the invoking session's change context instead of loading it again.<% } %> ## Additional Context @@ -21,24 +21,16 @@ $ARGUMENTS ### Load Changes +<% if (it.inline) { -%> +- Reuse the current session's known uncommitted file set and diffs as `` +- Do not call `<%= it.config.tools.changes_load.name %>`; if session context is insufficient, inspect worktree status and relevant diffs to establish the complete remaining uncommitted file set without broadening scope +- Run `git branch --show-current` and store the result as `` +<% } else { -%> <%~ include("@change-summary", { config: it.config, rules: "- pass `uncommitted: true` to get uncommitted changes only" }) %> -- Store the loaded change result as `` - Store the current branch as `` when it is available +<% } -%> -### Check Blockers - -- If `` contains no files, STOP and report that there is nothing to branch from -- If `` already starts with a conventional work-branch category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, STOP and report that branching was skipped because the current branch already looks like a work branch - -### Create Branch - -- Choose a branch category from the summarized change themes and `` -- Prefer conventional categories such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` -- Store the chosen category as `` -- Generate a concise kebab-case slug from the summarized change themes and `` when available, then store it as `` -- Create and checkout `/` with `git checkout -b` -- If that name already exists, retry once with a short numeric suffix -- Store the checked-out branch as `` +<%~ include("@branch") %> ### Output @@ -60,7 +52,7 @@ No additional steps are required. When the branch is created, display: ``` -Created branch: +Created branch: From: diff --git a/packages/core/commands/commit-and-push.md b/packages/core/commands/commit-and-push.md index b745067..ec3f5c1 100644 --- a/packages/core/commands/commit-and-push.md +++ b/packages/core/commands/commit-and-push.md @@ -1,6 +1,6 @@ ## Goal -Create a commit and immediately push it to the remote repository. +Create a commit and immediately push it to the remote repository.<% if (it.inline) { %> Reuse the invoking session's change context instead of loading it again.<% } %> ## Additional Context @@ -21,8 +21,12 @@ $ARGUMENTS ### Load Changes +<% if (it.inline) { -%> +- Reuse the current session's known uncommitted file set and diffs as `` +- Do not call `<%= it.config.tools.changes_load.name %>`; if session context is insufficient, inspect worktree status and relevant diffs to establish the complete remaining uncommitted file set without broadening scope +<% } else { -%> <%~ include("@change-summary", { config: it.config, rules: "- pass `uncommitted: true` to get uncommitted changes only" }) %> -- Store the loaded change result as `` +<% } -%> ### Check Blockers @@ -31,14 +35,10 @@ $ARGUMENTS ### Create Commit <%~ include("@commit") %> -- Store the created commit hash as `` ### Push to Remote -- Run `git push` and use its output as the source of truth -- If the current branch has no upstream set, retry with `git push -u origin ` -- Store the successful destination as `` -- If push fails, STOP and report the push error +<%~ include("@push", { config: it.config }) %> ### Output diff --git a/packages/core/commands/commit.md b/packages/core/commands/commit.md index d17f8f4..45176dc 100644 --- a/packages/core/commands/commit.md +++ b/packages/core/commands/commit.md @@ -1,6 +1,6 @@ ## Goal -Create a commit with an appropriate message summarizing the uncommitted changes. +Create a commit with an appropriate message summarizing the uncommitted changes.<% if (it.inline) { %> Reuse the invoking session's change context instead of loading it again.<% } %> ## Additional Context @@ -21,8 +21,12 @@ $ARGUMENTS ### Load Changes +<% if (it.inline) { -%> +- Reuse the current session's known uncommitted changes as `` +- Do not call `<%= it.config.tools.changes_load.name %>`; inspect the worktree only when the session context does not identify which files remain uncommitted +<% } else { -%> <%~ include("@change-summary", { config: it.config, rules: "- pass `uncommitted: true` to get uncommitted changes only" }) %> -- Store the loaded change result as `` +<% } -%> ### Check Blockers @@ -31,7 +35,6 @@ $ARGUMENTS ### Create Commit <%~ include("@commit") %> -- Store the created commit hash as `` ### Output diff --git a/packages/core/commands/index.ts b/packages/core/commands/index.ts index 8b01c89..ce7a82d 100644 --- a/packages/core/commands/index.ts +++ b/packages/core/commands/index.ts @@ -16,7 +16,6 @@ interface CommandDefinition { agent: string; templatePath: string; subtask?: boolean; - config?: Record; } export const commandDefinitions: Record = { @@ -30,19 +29,37 @@ export const commandDefinitions: Record = { agent: "worker", templatePath: "commands/branch.md", }, + "branch/inline": { + description: "Create a branch using context from the current session", + agent: "worker", + templatePath: "commands/branch.md", + subtask: false, + }, commit: { description: "Commit current changes with a message", agent: "worker", templatePath: "commands/commit.md", }, + "commit/inline": { + description: "Commit changes using context from the current session", + agent: "worker", + templatePath: "commands/commit.md", + subtask: false, + }, "commit-and-push": { description: "Commit and push current changes", agent: "worker", templatePath: "commands/commit-and-push.md", }, + "commit-and-push/inline": { + description: "Commit and push using context from the current session", + agent: "worker", + templatePath: "commands/commit-and-push.md", + subtask: false, + }, dev: { description: "Implement a request and prepare it for PR creation", - agent: "navigator", + agent: "worker", templatePath: "commands/dev.md", }, learn: { @@ -51,10 +68,10 @@ export const commandDefinitions: Record = { templatePath: "commands/learn.md", subtask: false, }, - "loop/pr/fix": { + "pr/fix/loop": { description: "Watch PR CI and comments, repeatedly fixing both without approval prompts", - agent: "navigator", - templatePath: "commands/loop/pr/fix.md", + agent: "worker", + templatePath: "commands/pr/fix/loop.md", }, merge: { description: "Merge a branch and auto-resolve conflicts best-effort", @@ -66,11 +83,16 @@ export const commandDefinitions: Record = { agent: "worker", templatePath: "commands/pr/create.md", }, + "pr/create/inline": { + description: "Create a PR in the current session", + agent: "worker", + templatePath: "commands/pr/create.md", + subtask: false, + }, "pr/fix": { description: "Fix PR feedback or CI failures, push updates, and reply", agent: "worker", templatePath: "commands/pr/fix.md", - subtask: false, }, "pr/review": { description: "Review the current PR and publish review feedback", @@ -94,9 +116,15 @@ export const commandDefinitions: Record = { }, ship: { description: "Ship branch work through commit and PR creation", - agent: "navigator", + agent: "worker", templatePath: "commands/ship.md", }, + "ship/inline": { + description: "Ship branch work using context from the current session", + agent: "worker", + templatePath: "commands/ship.md", + subtask: false, + }, rmslop: { description: "Remove AI code slop from current branch", agent: "worker", @@ -104,7 +132,7 @@ export const commandDefinitions: Record = { }, todo: { description: "Work through a todo file task by task", - agent: "navigator", + agent: "worker", templatePath: "commands/todo.md", }, "ticket/ask": { @@ -114,7 +142,7 @@ export const commandDefinitions: Record = { }, "ticket/dev": { description: "Implement a ticket and create a PR", - agent: "navigator", + agent: "worker", templatePath: "commands/ticket/dev.md", }, "ticket/create": { @@ -138,6 +166,7 @@ export interface ResolvedCommandDefinition extends Omit { template: string; subtask: boolean; + config?: Record; } async function loadComponents( @@ -199,11 +228,11 @@ export async function resolveCommands( let template: string; const commandConfig = { enabled: true, - ...(definition.config ?? {}), ...(config.commands.entries[name] ?? {}), }; const templateData = { ...commandConfig, + inline: definition.subtask === false, config: { shared: config.shared, tools: names.tools, diff --git a/packages/core/commands/loop/pr/fix.md b/packages/core/commands/loop/pr/fix.md deleted file mode 100644 index 21550c6..0000000 --- a/packages/core/commands/loop/pr/fix.md +++ /dev/null @@ -1,93 +0,0 @@ -## Goal - -Continuously watch a pull request, fix CI failures and PR feedback, commit, push, reply, and repeat until the PR is clean. - -## Additional Context - -Use `` to constrain which feedback should be handled, how aggressive the fix pass should be, or which CI checks matter when the PR has optional checks. -- This command is intentionally non-interactive: do not ask for approval before delegated fix work, commits, pushes, or PR replies. -- CI failures are part of the loop: capture them as actionable work, fix them, push, then watch CI again. - -## Workflow - -### Arguments - - -$ARGUMENTS - - -### Interpret Arguments - -- If `` looks like a PR number or URL, store it as `` -- If `` includes extra fix guidance, CI guidance, or scope constraints, store it as `` -- If empty, leave `` undefined and let `<%= it.config.tools.pr_load.name %>` resolve the default PR context -- Initialize `` as `0` - -### Load PR Context - -<%~ include("@load-pr", { config: it.config, ref: "", result: "" }) %> - -- Store `` as `` -- Store `` as `` -- STOP if `` or `` is unavailable - -### Watch CI And Comments - -- Run `gh pr checks --watch` to wait for the latest PR checks to finish -- If the command exits successfully, store `` as `green` -- If there are no checks configured for the PR, store `` as `no checks` -- If the command reports failing, cancelled, timed out, missing, or inconclusive checks, store `` with that state and capture the failing check names, URLs, and failure output as `` -- Do not STOP only because CI failed; failed checks are actionable feedback for this loop - -### Reload PR Feedback - -Call `<%= it.config.tools.pr_load.name %>` with `` and store the refreshed result as ``. - -- Review ``, ``, and `` -- Identify open, unresolved, actionable reviewer feedback that has not already been answered by the author or superseded by later commits -- Combine actionable reviewer feedback and `` into `` -- Store the number of actionable reviewer items as `` -- Store the number of actionable CI failures as `` -- If `` and `` are both `0`, continue to `### Output` - -### Delegate Fix Pass - -"> -auto - -Fix all actionable PR review feedback and CI failures from the latest loop pass. -CI status: -CI failures: -Actionable work: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked, incomplete, reports failing validation, or reports that push or PR replies failed, STOP and report the fix blocker -- If `` reports that no changes were made for actionable work, STOP and report that manual follow-up is needed to avoid looping on unchanged CI or feedback -- Otherwise, increment `` by `1` and return to `### Load PR Context` - -### Output - -If stopped by a delegated fix blocker, display: -``` -PR loop blocked for # - -- CI status: -- Fix passes completed: -- Blocker: - -No additional steps are required. -``` - -When complete, display: -``` -PR loop complete for # - -- CI status: -- CI failures remaining: 0 -- Actionable feedback remaining: 0 -- Fix passes completed: - -No additional steps are required. -``` diff --git a/packages/core/commands/pr/create.md b/packages/core/commands/pr/create.md index 2e234f8..f0fbd97 100644 --- a/packages/core/commands/pr/create.md +++ b/packages/core/commands/pr/create.md @@ -1,15 +1,10 @@ ## Goal -Create a pull request for the current branch, handling the entire workflow from change detection to PR submission. +Create a pull request for the current branch from its committed changes.<% if (it.inline) { %> Run in the invoking session while loading the final branch comparison as authoritative state.<% } %> ## Additional Context -Consider `` when analyzing changes and writing the PR description. -- Always include the `Ticket`, `Description`, and `Checklist` sections in that order. -- Use the literal `SKIPPED` when ticket mention was skipped. -- Keep the description focused on intent, not implementation details. -- Mark checklist validation items as completed if validation was performed. -- Uncommitted changes and being on the base branch block PR creation entirely. +Use ``<% if (it.inline) { %> and relevant invoking-session context<% } %> when writing the PR. Include `Ticket`, `Description`, and `Checklist` sections in that order, and use `SKIPPED` when ticket mention is skipped. ## Workflow @@ -21,146 +16,31 @@ $ARGUMENTS ### Interpret Arguments -- **Branch name**: If `` looks like a branch reference (e.g., "main", "origin/develop"), store it as `` -- **Ticket directive**: If `` clearly requests ticket auto-creation, store `` as `auto` -- **Ticket reference**: If `` includes a ticket URL or clear ticket reference, store it as `` and store `` as `provided` -- **Skip ticket**: If `` clearly says to skip ticket mention, store `` as `skip` -- **Additional context**: If `` provides guidance (focus areas, related issues, notes), store it as `` -- **Empty**: If no `` provided, proceed with defaults - -### Load & Analyze Changes - -<%~ include("@change-summary", { config: it.config, rules: "- If `` is defined: call `" + it.config.tools.changes_load.name + "` with the `base` parameter set to ``\n- Otherwise: call `" + it.config.tools.changes_load.name + "` with no parameters\n- Never pass `uncommitted: true` in this command" }) %> - -- Store the loaded change result as `` -- Store the current branch from `` as `` when it is available -- Store the effective base branch as `` by preferring `` when it was provided, otherwise using the base branch implied by `.comparison` -- When `.comparison` is not `uncommitted`, describe the PR from the commits ahead of ``, not from the raw branch comparison string by itself - -### Check Blockers - -- If `.comparison` is "uncommitted": - - STOP immediately - - Report: "There are uncommitted changes. Please commit or stash them before creating a PR." - - List the changed files from `` - - Do NOT proceed further -- Treat this as a blocker only when `<%= it.config.tools.changes_load.name %>` returns `comparison: "uncommitted"` from the default call above; never force that mode during PR creation -- If `` equals ``: - - STOP immediately - - Report: "You are currently on the base branch (). Please checkout a feature branch before creating a PR." - - Suggest: `git checkout -b ` - - Do NOT proceed further -- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR - -<%~ include("@summarize-changes") %> - -### Resolve Ticket - -- If `` is already `auto`, `provided`, or `skip`, do not ask a follow-up question -- Otherwise, if the `question` tool is available, this step is mandatory whenever the user did not already provide ticket handling through ``: - - Ask exactly one `question` before creating a ticket or PR - - This includes the common case where no ticket-related argument was provided at all - - Do not infer, assume, or default to any ticket mode while the `question` tool is available - - Never choose `skip` unless the user explicitly selects `Skip` or explicitly asks to skip ticket mention in `` - - Do not proceed to `Prepare Ticket Reference`, `Push Branch`, or `Create PR` until the answer is resolved - - Ask with: - - header `Provide Ticket` - - question `Provide Ticket` - - options: - - `Automatically Create` - create a fresh ticket from the summarized branch work - - `Skip` - mention `SKIPPED` in the PR body - - custom answers enabled so the user can paste a ticket URL or ticket reference directly -- Otherwise, if the `question` tool is not available: - - Do not ask a follow-up question - - Only in this case may the workflow continue without user input - - Store `` as `skip` - - Store `` as `SKIPPED` - - Continue without blocking -- Normalize the result into one of these paths: - - `Automatically Create` => `` = `auto` - - custom ticket URL or reference => `` = `provided` and store the answer as `` - - `Skip` => `` = `skip` - -### Prepare Ticket Reference - -When `` is `auto`, create the ticket before creating the PR: -<%~ include("@changes-summary", { config: it.config }) %> -- Use `<%= it.config.tools.ticket_sync.name %>` with `refUrl` unset -- Set `assignees` to `[@me]` so the created ticket is assigned to yourself as the author -- Store the created issue reference or URL as `` - -Otherwise: -- If `` is `provided`, use the provided ticket value as `` -- If `` is `skip`, store the literal `SKIPPED` as `` - -### Push Branch - -Run `git push` and use its output as the source of truth. - -- Do not run extra git commands just to decide whether to push -- If the branch was pushed during this run, report `Push: yes` -- If `git push` reports no push was needed, report `Push: no` -- If `Push: yes`, also report `Pushed: → origin/` -- Store the push status line as `` -- When a push occurs, store the pushed ref line as `` - -### Create PR - -Use `<%= it.config.tools.pr_sync.name %>` to create the pull request: -- This step is PR creation only -- Omit `review`, `replies`, `commentBody`, and `commitId` entirely unless you are intentionally updating or reviewing an existing PR instead of creating one -- Generate a concise title (max 70 chars) summarizing the change and store it as `` -- Generate a short description that briefly describes the intent and scope -- Pass `` as `head` when it is available so PR creation does not depend on local upstream inference -- Set `assignees` to `[@me]` so the created PR is assigned to yourself as the author -- Generate a compact checklist that mirrors the same human-facing structure used for the ticket summary: - - group delivered work into 2-4 functional or outcome-focused sections - - use concise section names instead of generic labels like `Changes` - - end with one `Validation` section containing reviewer-facing confirmation steps - - do not use execution-status notes as checklist items -- Render the PR body with this exact structure by setting `body` directly: - - `## Ticket`, followed by `` on the next line - - `## Description`, followed by the short description - - `## Checklist`, followed by the checklist items and any subsection headings -- Use `` as the base branch when it is defined -- Do NOT restate the full diff -- Do NOT rely on the branch diff alone to describe the PR; the description must match the commits ahead of `` -- Keep it compact and directional -- Store the returned URL as `` -- If `<%= it.config.tools.pr_sync.name %>` reports that a PR already exists for the branch, treat the result as an existing PR -- Track whether the branch was pushed during this run and report that status in the final response +- Store a branch reference as `` +- Store ticket auto-creation as `` = `auto`, an explicit ticket reference as ``, or an explicit skip as `` = `skip` +- Store remaining guidance as `` -### Output +### Load And Analyze Changes -If PR creation stops because there is nothing to include, display: -``` -Nothing to include in a PR +<% if (it.inline) { -%> +- Retain the authoritative branch comparison load even though this command runs in the invoking session; do not infer the final base, commit scope, or diff from session memory +<% } -%> +<%~ include("@change-summary", { config: it.config, rules: "- If `` is defined, pass it as `base`; otherwise call the tool with no parameters\n- Never pass `uncommitted: true`" }) %> -No additional steps are required. -``` +<%~ include("@pr-create", { config: it.config, analyze: false }) %> -When a new PR is created, display: +### Output + +When complete, display: ``` Created PR: URL: -Branch: +Branch: -> Ticket: - - +Push: No additional steps are required. ``` -If a PR already exists for the branch, display: -``` -PR already exists - -URL: -Branch: -Ticket: - - - -No additional steps are required. -``` +If `` is true, replace the first line with `PR already exists`. diff --git a/packages/core/commands/pr/fix.md b/packages/core/commands/pr/fix.md index 20584da..fa15951 100644 --- a/packages/core/commands/pr/fix.md +++ b/packages/core/commands/pr/fix.md @@ -1,12 +1,10 @@ ## Goal -Address feedback or CI failures on a pull request by making fixes and responding to review threads. +Address feedback or CI failures on a pull request, validate the fixes, push them, and respond. ## Additional Context -Use `` when prioritizing which review feedback or CI failure to address first and when deciding how much scope to take on in this pass. -- Default `/pr/fix` behavior is review-first: show the proposed fix, gather feedback, and loop until the user approves before committing, pushing, or replying on the PR. -- Treat `/pr/fix auto` as the explicit opt-in to skip the approval loop and proceed directly from passing validation to commit, push, and PR replies. +Use `` to prioritize feedback and scope. Default behavior requires review; `auto` explicitly skips approval. ## Workflow @@ -18,149 +16,26 @@ $ARGUMENTS ### Interpret Arguments -- If `` clearly requests automatic completion (for example `auto`), store `` as `auto` -- If `` looks like a PR number (e.g., "123") or URL, store it as `` -- If `` includes extra fix guidance, scope constraints, or priorities, store it as `` -- Otherwise, store `` as `review` -- If empty, leave `` undefined and let `<%= it.config.tools.pr_load.name %>` resolve the default PR context +- Store automatic completion requests as `` = `auto`; otherwise use `review` +- Store a PR number or URL as `` and remaining guidance as `` +- Leave `` undefined when absent ### Load PR Context <%~ include("@load-pr", { config: it.config, ref: "", result: "" }) %> -### Align Local Branch - -- If `` is unavailable, STOP and report that the PR head branch could not be determined -- Run `gh pr checkout ` before analyzing repository files or making code changes for this PR -- After checkout, store the active branch as `` -- If checkout fails or times out, STOP and report that the PR branch could not be checked out locally; do not retry checkout unless the user explicitly asks -- Do not inspect or modify local code for this PR until `` equals `` - -### Load Changes - -Call `<%= it.config.tools.changes_load.name %>` with `base: `, `head: `, and `depthHint: ` only when it is a positive integer. Store as ``. - -### Analyze Feedback - -Separate true course corrections from noise or already-resolved feedback: -1. Review `` for open, unresolved conversations -2. Check `` for state changes (CHANGES_REQUESTED, etc.) -3. Include any CI failures, logs, failing check names, or reproduction details provided in `` as actionable feedback -4. Use `` to understand the current PR diff before deciding what to adjust -5. Prioritize critical issues (bugs, security, broken contracts, failing required checks) -6. Identify which files need changes - -Do not blindly follow every suggestion—some may lead you off course. - -### Implement Fixes - -1. Fix critical navigation issues first -2. Follow existing code patterns and conventions -3. Use `` as the working branch for every local code read or edit in this command -4. Make focused, minimal changes -5. When maintaining your current heading despite a suggestion, be prepared to explain why -6. Store the modified-file count as `` - -### Validate Changes - -Run the most relevant available validation for the fixes: -<% for (const line of it.config.shared.validation) { -%> -- <%= line %> -<% } -%> -- Confirm the fixes address the feedback -- Store the collected validation details as `` -- Store the overall validation outcome as `` with value `yes` or `no` - -### Review Fixes With User - -- If `` is `no`, STOP and report that validation is failing before any commit, push, or PR response happens -- If `` is `auto`, skip this review gate and continue directly to `### Commit And Push Updates` -- Otherwise, this review step is mandatory before any commit, push, or PR reply: - - Present the implemented fix summary, changed file count, and validation results - - If `` is greater than `0`, ask exactly one `question` with: - - header `Review Fixes` - - question `Do these PR fixes look good to commit, push, and respond on the PR?` - - options: - - `Go Ahead` - commit, push, and respond to the PR now - - `Revise` - update the fix based on user feedback before committing - - Keep custom answers enabled so the user can provide concrete feedback - - If `` is `0`, ask exactly one `question` with: - - header `Need Feedback` - - question `I did not make any changes for this PR feedback or CI failure. What should I revise or investigate next?` - - options: - - `Revise` - provide feedback for another pass - - `Stop Here` - stop without committing, pushing, or replying on the PR - - Keep custom answers enabled so the user can provide concrete feedback -- Normalize the answer into one of these paths: - - If `` is greater than `0`: - - `Go Ahead` => continue to `### Commit And Push Updates` - - `Revise` or custom feedback => store the feedback as ``, then continue to `### Apply Review Feedback` - - If `` is `0`: - - `Stop Here` => STOP and report that no changes were made, so nothing was committed, pushed, or sent to the PR - - `Revise` or custom feedback => store the feedback as ``, then continue to `### Apply Review Feedback` -- Repeat this review step until the user selects `Go Ahead` after a pass that produces changes, or explicitly selects `Stop Here` when no changes were made -- If the `question` tool is unavailable while `` is `review`, STOP and report that approval is required before commit, push, or PR replies - -### Apply Review Feedback - -- Use `` to refine the implementation without widening scope unless the feedback explicitly asks for it -- Return to `### Implement Fixes`, then rerun validation and the review step - -### Commit And Push Updates - -If validation passes: -1. Stage changes: `git add -A` -2. Create commit (use `commit` tool or `git commit`) -3. Push branch: `git push` -4. Store push status as `` with value `yes` or `no` - -### Respond to Threads - -Only after commit and push succeed, reply to addressed threads: -- Keep replies short and factual—clear signals, no chatter -- Use `<%= it.config.tools.pr_sync.name %>` to post comments or replies: +<%~ include("@pr-branch-update") %> -``` -# General PR comment -<%= it.config.tools.pr_sync.name %> refUrl="" commentBody="" - -# Reply to a specific review thread (use comment.id from threads.comments) -<%= it.config.tools.pr_sync.name %> refUrl="" replies=[{"inReplyTo": , "body": ""}] - -# Follow-up inline review comment on a specific line -<%= it.config.tools.pr_sync.name %> refUrl="" commitId="" review={"comments": [{"path": "", "line": , "body": ""}]} -``` - -Confirm which feedback was addressed and which was intentionally not followed. -- Store the number of resolved threads as `` +<%~ include("@pr-fix", { config: it.config, auto: false }) %> ### Output -When waiting for approval or revision feedback, display: -``` -Review fixes for PR # - -- Changes made: files modified -- Validation passing: -- Validation details: -``` - -If the workflow stops after a no-change pass, display: -``` -No changes made for PR # - -- Changes made: 0 files modified -- Validation passing: -- Validation details: - -No additional steps are required. -``` - -When fixes are complete, display exactly this final completion summary and stop. Do not continue with extra analysis, planning, or follow-up tasks unless the workflow is blocked or the user asked for more: +When fixes are complete, display: ``` PR fix complete for # - Changes made: files modified +- Base update: - Threads resolved: - Validation passing: - Validation details: diff --git a/packages/core/commands/pr/fix/loop.md b/packages/core/commands/pr/fix/loop.md new file mode 100644 index 0000000..e4c0cb9 --- /dev/null +++ b/packages/core/commands/pr/fix/loop.md @@ -0,0 +1,69 @@ +## Goal + +Continuously watch a pull request, fix CI failures and new review feedback, push, reply, and repeat until clean. + +## Additional Context + +- Use `` to constrain feedback and CI handling +- This workflow is non-interactive and must not ask for approval +- Preserve the initial PR snapshot and use incremental review checkpoints on later passes + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- Store a PR number or URL as `` and remaining guidance as `` +- Initialize `` as `0` + +### Load Initial PR Context + +<%~ include("@load-pr", { config: it.config, ref: "", result: "" }) %> +- Store ``, ``, and `` from ``, ``, and `` +- Store the initial reviews, issue comments, and threads as `` +- STOP if any required value is unavailable + +### Align Branch With Base + +<%~ include("@pr-branch-update") %> + +### Watch CI + +- Run `gh pr checks --watch` +- Store success or no configured checks as `` +- Capture failing, cancelled, timed out, missing, or inconclusive checks as `` without stopping + +### Load Incremental Feedback + +- Call `<%= it.config.tools.pr_load_review.name %>` with `pr: ` and `since: ` +- Store the result as `` and advance `` to `` +- Merge new reviews, issue comments, and whole changed threads into ``, deduplicating by stable IDs +- Combine open actionable feedback and `` into `` +- If there is no actionable feedback and no actionable CI failure, continue to `### Output` + +<%~ include("@pr-fix", { config: it.config, auto: true }) %> + +### Continue Loop + +- Increment `` and return to `### Align Branch With Base` +- Do not call `<%= it.config.tools.pr_load.name %>` again during this loop + +### Output + +When complete, display: +``` +PR loop complete for # + +- CI status: +- Base update: +- CI failures remaining: 0 +- Actionable feedback remaining: 0 +- Fix passes completed: + +No additional steps are required. +``` diff --git a/packages/core/commands/ship.md b/packages/core/commands/ship.md index 27a1e6a..7071eca 100644 --- a/packages/core/commands/ship.md +++ b/packages/core/commands/ship.md @@ -1,10 +1,10 @@ ## Goal -Ship the current work by dispatching branch creation, commit creation, and PR creation in the current session. +Ship the current work through branch creation, commit creation, and PR creation in one workflow.<% if (it.inline) { %> Reuse the invoking session's change context for the initial branch and commit phases.<% } %> ## Additional Context -Use `` to steer delegated branch naming. Use `` to refine the delegated commit and PR summaries. Pass `` through to PR creation when it was provided. +Use `` for branch naming and `` for commit and PR summaries. Reuse loaded state within this command instead of reloading it between phases. ## Workflow @@ -17,61 +17,44 @@ $ARGUMENTS ### Interpret Arguments - Initialize ``, ``, and `` as empty -- If `` is empty, proceed with defaults -- If the trimmed `` is only a branch reference (for example `main` or `origin/develop`), store it as `` and leave the context fields empty -- Otherwise, store `` as both `` and `` +- If `` is only a branch reference, store it as `` +- Otherwise, store it as both `` and `` -### Delegate Branch Creation +### Load Uncommitted Changes Once - -Branch naming guidance: - +<% if (it.inline) { -%> +- Reuse the current session's known uncommitted changes as `` for branch naming and commit creation +- Do not call `<%= it.config.tools.changes_load.name %>` before the branch and commit phases; inspect the worktree only when the session context does not identify which files remain uncommitted +<% } else { -%> +<%~ include("@change-summary", { config: it.config, rules: "- pass `uncommitted: true` to get uncommitted changes only" }) %> +- Reuse `` for branch naming and commit creation +<% } -%> -- Store the delegated result as `` -- If `` says there was nothing to branch from, continue on the current branch -- If `` says branching was skipped because the current branch already looks like a work branch, continue on the current branch -- If `` is blocked or incomplete, STOP and report the branch blocker -- Otherwise, continue with the created branch +<%~ include("@branch") %> -### Delegate Commit +### Create Commit - -Additional context: - +- If `` contains files, create the commit from the already loaded ``: +<%~ include("@commit") %> +- Store `` as the created hash and message +- If `` contains no files, store `` as `no new commit` -- Store the delegated result as `` -- If `` says there was nothing to commit, continue without creating a new commit -- If `` is blocked or incomplete, STOP and report the commit blocker -- Otherwise, continue with the created commit +### Load Branch Changes -### Delegate PR Creation +- Call `<%= it.config.tools.changes_load.name %>` with `base: ` when defined, otherwise with no arguments +- Store the new result as ``; this post-commit comparison is required for PR creation -"> -Base branch: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the PR blocker -- If `` says there is nothing to include in a PR, STOP and report that there is nothing to ship -- Otherwise, continue with the created or existing PR +<%~ include("@pr-create", { config: it.config }) %> ### Output -If there is nothing to ship, display: -``` -Nothing to ship - -No additional steps are required. -``` - When complete, display: ``` Ship flow complete Branch: Commit: -PR: +PR: No additional steps are required. ``` diff --git a/packages/core/commands/ticket/create.md b/packages/core/commands/ticket/create.md index 6e0545f..9d64bcb 100644 --- a/packages/core/commands/ticket/create.md +++ b/packages/core/commands/ticket/create.md @@ -24,15 +24,12 @@ $ARGUMENTS <%~ include("@change-summary", { config: it.config, rules: "- If `` is defined: call `" + it.config.tools.changes_load.name + "` with the `base` parameter set to ``\n- Otherwise: call `" + it.config.tools.changes_load.name + "` with no parameters" }) %> -- Store the loaded change result as `` - When `.comparison` is not `uncommitted`, describe the ticket from the commits ahead of the resolved base branch, not from branch names alone ### Check Blockers - If `` contains no files, STOP and report that there is no work to summarize in a ticket -<%~ include("@summarize-changes") %> - ### Create Ticket Use `<%= it.config.tools.ticket_sync.name %>` with `refUrl` unset to create the ticket: diff --git a/packages/core/commands/ticket/dev.md b/packages/core/commands/ticket/dev.md index 50e5759..cc19daf 100644 --- a/packages/core/commands/ticket/dev.md +++ b/packages/core/commands/ticket/dev.md @@ -1,10 +1,10 @@ ## Goal -Implement a ticket by orchestrating development, branching, commit-and-push, and PR creation. +Implement a ticket, create a branch and commit, push it, and create a pull request in one workflow. ## Additional Context -Use `` to refine scope, sequencing, and tradeoffs across the delegated `/<%= it.config.commands.dev.name %>`, `/<%= it.config.commands.branch.name %>`, `/<%= it.config.commands["commit-and-push"].name %>`, and `/<%= it.config.commands["pr/create"].name %>` steps. +Use `` to refine scope and delivery. Reuse loaded change state across adjacent phases. ## Workflow @@ -16,74 +16,54 @@ $ARGUMENTS ### Interpret Arguments -- Interpret `` as `` (ticket reference, URL, file path, or raw request) -- If `` includes extra delivery guidance, scope constraints, or notes, store them as `` -- If `` is empty, derive it from the conversation before continuing +- Store the ticket reference, URL, file, or request as `` +- Store extra delivery guidance as `` ### Load Ticket Context <%~ include("@load-ticket", { config: it.config, source: "", result: "" }) %> -- Store the ticket reference for PR creation as `` by preferring the original reference, otherwise using the canonical ticket URL from `` when one is available, otherwise using `SKIPPED` -- Store a concise ticket summary as `` -- If `` cannot be loaded, STOP and report that the ticket source is missing or invalid +- Store a concise `` and canonical `` when available +- STOP if ticket context cannot be loaded -<%~ include("@dev-flow") %> - -### Delegate Implementation - - -Ticket reference: -Ticket context: -Additional context: - +### Implement Ticket -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the implementation blocker - -### Delegate Branch Creation +<%~ include("@dev-flow") %> +- Implement the smallest complete change for `` and `` +- Run the most relevant available validation +<% for (const line of it.config.shared.validation) { -%> +- <%= line %> +<% } -%> +- Store results as `` and STOP if required validation fails - -Branch naming guidance: -Additional context: - +### Load Uncommitted Changes Once -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the branch blocker -- If `` says branching was skipped because the current branch already looks like a work branch, continue +<%~ include("@change-summary", { config: it.config, rules: "- pass `uncommitted: true` to get uncommitted changes only" }) %> +- Set `` to `` -### Delegate Commit And Push +<%~ include("@branch") %> -"> -Ticket reference: -Ticket summary: -Additional context: - +### Commit Changes -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the commit or push blocker -- If `` says there was nothing to commit or push, continue to PR creation so already-committed branch work can still be shipped +- If `` contains files: +<%~ include("@commit") %> +- Otherwise, continue so previously committed ticket work can still be shipped -### Delegate PR Creation +### Load Branch Changes -"> -Ticket reference: -Ticket context: -Additional context: - +- Call `<%= it.config.tools.changes_load.name %>` with no parameters and store the result as `` +- Store `` as `provided` when `` exists, otherwise `skip` -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the PR blocker -- Otherwise, continue and store the resulting PR URL as `` +<%~ include("@pr-create", { config: it.config }) %> ### Output -When the ticket work is complete, display: +When complete, display: ``` Implemented ticket: -Implementation: -Branch: -Commit and push: +Validation: +Branch: +Commit: PR: No additional steps are required. diff --git a/packages/core/commands/ticket/plan-and-sync.md b/packages/core/commands/ticket/plan-and-sync.md index a357a15..cf4a3df 100644 --- a/packages/core/commands/ticket/plan-and-sync.md +++ b/packages/core/commands/ticket/plan-and-sync.md @@ -22,48 +22,7 @@ Create a scoped implementation plan from a request or ticket, then capture that $ARGUMENTS -### Interpret Arguments - -- If `` looks like a ticket reference or URL, store it as `` -- Otherwise, treat `` as `` -- If `` includes planning focus areas, constraints, or notes beyond the main request, store them as `` -- If no `` are provided, derive the current request from the conversation and store it as `` - -### Load Planning Context - -- If `` is defined: -<%~ include("@load-ticket", { config: it.config, source: "", result: "", comments: true }) %> -- Otherwise, treat the relevant request and conversation context as `` -- If `` is empty or missing, STOP and report that planning context could not be determined - -### Interpret Planning Context - -- From `` and ``, derive: - - `` - the current planning task or request - - `` - earlier context that still applies - - `` - technical details already proposed in the discussion - - `` - only the issues that are still unresolved -- Use the current request to determine `` -- Do not discard earlier comments when they still define constraints, business rules, implementation decisions, migration rules, naming, sequencing, or scoping limits - -### Inspect Repo Context - -- If the request is technical and repository context is available, perform light targeted reconnaissance before finalizing the plan -- Inspect the relevant code, schema, config, UI patterns, and tests needed to validate `` and ground the plan -- Confirm current behavior and existing patterns instead of relying on ticket text alone -- If relevant repo context cannot be found or verified, note that gap and avoid false certainty - -### Shape the Plan - -- Turn ``, ``, ``, ``, and repo findings into: - - `` - a short, useful title - - `` - a brief description of the intended outcome, scope, important constraints, and material technical direction - - `` - concise requirement checklist items - - `` - validation checklist items -- Preserve good technical details from the ticket or conversation when they are valid -- Improve incomplete technical details when repo inspection provides a better grounded direction -- Do not replace material technical guidance with generic outcome language -- Avoid placeholder-like labels or awkward title formats such as `Ticket`, `Description`, or `Ticket : Description` +<%~ include("@ticket-planning", { config: it.config }) %> ### Sync Ticket diff --git a/packages/core/commands/ticket/plan.md b/packages/core/commands/ticket/plan.md index 95042cf..956b0fb 100644 --- a/packages/core/commands/ticket/plan.md +++ b/packages/core/commands/ticket/plan.md @@ -22,48 +22,7 @@ Create a scoped implementation plan from a request or ticket and present it dire $ARGUMENTS -### Interpret Arguments - -- If `` looks like a ticket reference or URL, store it as `` -- Otherwise, treat `` as `` -- If `` includes planning focus areas, constraints, or notes beyond the main request, store them as `` -- If no `` are provided, derive the current request from the conversation and store it as `` - -### Load Planning Context - -- If `` is defined: -<%~ include("@load-ticket", { config: it.config, source: "", result: "", comments: true }) %> -- Otherwise, treat the relevant request and conversation context as `` -- If `` is empty or missing, STOP and report that planning context could not be determined - -### Interpret Planning Context - -- From `` and ``, derive: - - `` - the current planning task or request - - `` - earlier context that still applies - - `` - technical details already proposed in the discussion - - `` - only the issues that are still unresolved -- Use the current request to determine `` -- Do not discard earlier comments when they still define constraints, business rules, implementation decisions, migration rules, naming, sequencing, or scoping limits - -### Inspect Repo Context - -- If the request is technical and repository context is available, perform light targeted reconnaissance before finalizing the plan -- Inspect the relevant code, schema, config, UI patterns, and tests needed to validate `` and ground the plan -- Confirm current behavior and existing patterns instead of relying on ticket text alone -- If relevant repo context cannot be found or verified, note that gap and avoid false certainty - -### Shape the Plan - -- Turn ``, ``, ``, ``, and repo findings into: - - `` - a short, useful title - - `` - a brief description of the intended outcome, scope, important constraints, and material technical direction - - `` - concise requirement checklist items - - `` - validation checklist items -- Preserve good technical details from the ticket or conversation when they are valid -- Improve incomplete technical details when repo inspection provides a better grounded direction -- Do not replace material technical guidance with generic outcome language -- Avoid placeholder-like labels or awkward title formats such as `Ticket`, `Description`, or `Ticket : Description` +<%~ include("@ticket-planning", { config: it.config }) %> ### Present Plan diff --git a/packages/core/commands/todo.md b/packages/core/commands/todo.md index 721fc25..f17303f 100644 --- a/packages/core/commands/todo.md +++ b/packages/core/commands/todo.md @@ -1,14 +1,12 @@ ## Goal -Work through a todo file one pending item at a time by planning, getting approval, implementing, committing, and marking completed tasks. +Work through a todo file one pending item at a time by planning, getting approval, implementing, committing, and marking it complete. ## Additional Context - Keep the loop focused on one checklist item at a time -- Do not merge separate todo items unless the file explicitly frames them as one task -- If implementation reveals scope that materially changes the approved plan, pause and re-plan before marking the task complete -- Use `` to prioritize tradeoffs, constraints, or validation expectations during planning and implementation -- Delegate planner and worker steps through literal `` blocks and use the delegated results as the source of truth for planning, implementation, and commit steps. +- Pause and revise the plan when implementation materially changes approved scope +- Use `` for constraints and validation expectations ## Workflow @@ -20,111 +18,40 @@ $ARGUMENTS ### Interpret Arguments -- If `` contains a file reference prefixed with `@`, store that value as `` -- If `` includes execution guidance, scope constraints, or notes beyond the file reference, store them as `` -- If no file reference is provided, default `` to `@TODO.md` - -### Load Todo Context - -- Prefer the file content already provided by the user's file mention or attachment for `` -- Only load `` yourself if that content is not already available in context -- If the file cannot be loaded, STOP and report that `` could not be found or read -- Treat markdown checklist items with unchecked boxes as pending tasks, preserving file order -- Ignore headings, checked items, and non-checklist lines when selecting work -- If there are no pending tasks, STOP and report that `` has no remaining work -- Store the first pending task text as `` -- Store any nearby checklist context that materially clarifies `` as `` - -### Check Blockers - -- If the first pending item is unclear, let the planner identify missing details or questions when it can do so safely from `` and `` -- Only STOP here when the task is too ambiguous to plan at all and the workflow cannot produce a meaningful plan or targeted clarification request - -### Delegate Planning - -"> -Task: -Task context: -Additional context: - - -- Store the delegated result as `` -- If the planner is blocked or cannot produce a usable plan, store the blocker as ``, then STOP and report that planning blocker - -### Review Plan With User - -- Show `` and `` to the user before any implementation work starts -- Ask one `question` with: - - header `Plan Review` - - question `Does this plan look good to implement?` - - options: - - `Implement` - proceed with the current plan - - `Revise` - update the plan based on feedback -- custom answers enabled so the user can provide specific plan changes -- If the user requests changes, store that feedback as `` -- Only run the revised planning block below when the user requests changes -- If the user approves the current plan, skip the revised planning block and continue to implementation - -"> -Task: -Task context: -Current plan: -Plan feedback: -Additional context: - - -- Store the revised delegated result as `` and continue the review loop -- If the revised planner result is blocked or unusable, store that blocker as ``, then STOP and report it before continuing the review loop -- Repeat this review step until the user approves or stops -- If the user does not approve implementation, store `plan approval not granted` as ``, then STOP without changing `` - -### Delegate Implementation - - -Plan: -Task: -Task context: -Additional context: - - -- Store the delegated result as `` -- If `` is incomplete, blocked, or fails validation, store the issue as ``, then STOP and report it without marking the task complete - -### Delegate Commit - - -Task: -Additional context: - - -- Store the delegated result as `` -- If `` does not succeed, store the commit status as ``, then STOP and report it without marking the task complete +- Store an `@`-prefixed file as `` and remaining guidance as `` +- Default `` to `@TODO.md` -### Mark Complete And Loop +### Load Next Todo -- After the implementation and commit both succeed, update the matching checklist item in `` from unchecked to checked while preserving the rest of the file -- Save the updated todo file -- Return to `### Load Todo Context` and repeat the workflow for the next pending task +- Prefer attached content, otherwise load `` +- Select the first unchecked markdown checklist item as `` and preserve nearby context as `` +- STOP with completion when no pending tasks remain -### Output +### Plan Task -When presenting a task plan for approval, display: -``` -Todo: -Task: +- Inspect relevant repository context and shape a scoped implementation plan from ``, ``, and `` +- Store it as `` +- Show the plan and ask one `Plan Review` question with `Implement` and `Revise`, with custom answers enabled +- Apply revision feedback and repeat until approved; STOP without editing when approval is not granted -Plan: - -``` +### Implement Task -If the workflow pauses before marking the task complete, display: -``` -Todo paused: -Task: -Reason: +<%~ include("@dev-flow") %> +- Implement the approved `` +- Run relevant validation and STOP without marking complete if implementation or validation is incomplete -No additional steps are required. -``` +### Load And Commit Task Changes + +<%~ include("@change-summary", { config: it.config, rules: "- pass `uncommitted: true` to get uncommitted changes only" }) %> +- STOP without marking complete if `` contains no files +<%~ include("@commit") %> + +### Mark Complete And Loop + +- After commit succeeds, change the matching checklist item to checked while preserving the file +- Return to `### Load Next Todo` + +### Output When all pending tasks are complete, display: ``` diff --git a/packages/core/components/branch.md b/packages/core/components/branch.md new file mode 100644 index 0000000..694a830 --- /dev/null +++ b/packages/core/components/branch.md @@ -0,0 +1,15 @@ +### Check Branch + +- Store the current branch from `` as `` when available +- If `` contains no files, store `` as `nothing to branch from` and skip branch creation +- If `` starts with a conventional work category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, store `` as `kept ` and skip branch creation + +### Create Branch + +When branch creation was not skipped: +- Choose a conventional category such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` from the change themes and `` +- Generate a concise kebab-case slug from the same context +- Create and checkout `/` with `git checkout -b` +- If that name exists, retry once with a short numeric suffix +- Store the checked-out branch as `` and `` as `created ` +- If branch creation fails, STOP and report the blocker diff --git a/packages/core/components/change-summary.md b/packages/core/components/change-summary.md index aa19d95..7370668 100644 --- a/packages/core/components/change-summary.md +++ b/packages/core/components/change-summary.md @@ -1,17 +1,20 @@ -#### Step 1: Load Changes +<% if (it.load !== false) { -%> +#### Load Changes + - call `<%= it.config.tools.changes_load.name %>` <%= it.rules ?? "" %> - Store the returned result as `` -- Use `` as the source of truth; no additional git analysis commands are needed -- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits that are ahead of the resolved base branch -- Do not infer scope from the branch names alone and do not describe work that exists only on the base branch +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +<% } -%> +#### Analyze And Summarize Changes -#### Step 2: Analyze Files -- Review the paths, statuses, and diffs from `` only as file-level context for the commits in scope +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context - Identify the nature of changes (added, modified, deleted) -- Note lines added/removed per file - -#### Step 3: Group and Summarize -- For branch comparisons, build the summary from `.commits` first and use file diffs only to verify or refine what those commits changed - Group related changes into logical themes - Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base diff --git a/packages/core/components/load-pr.md b/packages/core/components/load-pr.md index 6e181e6..8bad135 100644 --- a/packages/core/components/load-pr.md +++ b/packages/core/components/load-pr.md @@ -3,9 +3,6 @@ - Otherwise, call `<%= it.config.tools.pr_load.name %>` with no arguments - Do not run separate git or GitHub commands just to discover the PR before calling `<%= it.config.tools.pr_load.name %>` - Store the result as `<%= it.result %>` -- Store the PR head branch as `` from `<%= it.result %>.pr.headRefName` when it is available -- Run `git branch --show-current` and store the trimmed result as `` when it is available -- Run `git rev-parse HEAD` and store the trimmed result as `` when it is available - Treat the loaded PR body, discussion, review history, and any attachments or linked artifacts returned by the loader as part of the source context - Review attached images, screenshots, videos, PDFs, and other linked files whenever they can affect the requested fix, review outcome, reproduction steps, or acceptance criteria - If any relevant attachment cannot be accessed, note that gap and continue only when the remaining PR context is still sufficient to proceed reliably diff --git a/packages/core/components/pr-branch-update.md b/packages/core/components/pr-branch-update.md new file mode 100644 index 0000000..52f72d1 --- /dev/null +++ b/packages/core/components/pr-branch-update.md @@ -0,0 +1,15 @@ +### Align Local Branch + +- Store `` as `` +- STOP if `` is unavailable +- Run `gh pr checkout ` before inspecting or modifying code +- Store the active branch as `` and STOP unless it equals `` + +### Update Branch From Base + +- Store `` as `` and STOP if it is unavailable +- Run `git fetch origin `, then store `origin/` as `` +- Run `git merge-base --is-ancestor HEAD` to confirm whether the PR branch contains the latest base +- If the branch is behind, merge `` into `` without rebasing or force-pushing; resolve conflicts using repository context, complete the merge, push the merge commit, and store its hash as `` +- If the branch is current, store `` as `already up to date` +- STOP before making PR fixes if the fetch, merge, conflict resolution, or push cannot be completed safely diff --git a/packages/core/components/pr-create.md b/packages/core/components/pr-create.md new file mode 100644 index 0000000..5e8de1b --- /dev/null +++ b/packages/core/components/pr-create.md @@ -0,0 +1,41 @@ +### Check PR Blockers + +- Store the current branch from `` as `` when available +- Store `` by preferring ``, otherwise use the base implied by `.comparison` +- If `.comparison` is `uncommitted`, STOP and report that changes must be committed or stashed +- If `` equals ``, STOP and report that PR creation requires a work branch +- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR + +<% if (it.analyze !== false) { -%> +<%~ include("@change-summary", { config: it.config, load: false }) %> +<% } -%> + +### Resolve Ticket + +- Preserve an already defined `` or `` +- If `` is defined, store `` as `provided` +- Otherwise, if ticket handling was explicitly skipped, store `` as `skip` +- Otherwise, if automatic ticket creation was requested, store `` as `auto` +- Otherwise, when `question` is available, ask exactly one `Provide Ticket` question with `Automatically Create` and `Skip` options and custom answers enabled +- When `question` is unavailable, default to `skip` +- Normalize a custom ticket reference as `` with mode `provided`; never infer `skip` when the user can be asked + +### Prepare Ticket Reference + +When `` is `auto`: +<%~ include("@changes-summary", { config: it.config }) %> +- Use `<%= it.config.tools.ticket_sync.name %>` with `assignees: ["@me"]` and store the created issue URL as `` + +Otherwise, preserve the provided `` or store the literal `SKIPPED` for mode `skip`. + +<%~ include("@push", { config: it.config }) %> + +### Create PR + +- Generate a concise title of at most 70 characters as `` +- Generate a compact description focused on intent and scope +- Build 2-4 outcome-focused checklist sections followed by `Validation` +- Use `<%= it.config.tools.pr_sync.name %>` to create the PR with `` as `base`, `` as `head`, and `assignees: ["@me"]` +- Set `body` with `## Ticket`, `## Description`, and `## Checklist` in that order +- Omit review, replies, commentBody, and commitId +- Store the created or existing PR URL as `` and whether it already existed as `` diff --git a/packages/core/components/pr-fix.md b/packages/core/components/pr-fix.md new file mode 100644 index 0000000..9f12bf3 --- /dev/null +++ b/packages/core/components/pr-fix.md @@ -0,0 +1,48 @@ +### Load PR Changes + +Call `<%= it.config.tools.changes_load.name %>` with `base: `, `head: `, and positive `depthHint: ` when available. Store as ``. + +### Analyze And Implement Fixes + +- Treat unresolved review threads, review state changes, ``, and CI details in `` as candidate feedback +- Use `` to understand the current PR scope +- Separate true course corrections from noise, resolved feedback, and superseded feedback +- Fix critical correctness, security, contract, and required-CI issues first +- Follow existing patterns and make focused, minimal changes +- Store the modified-file count as `` + +### Validate Fixes + +- Run the most relevant available validation +<% for (const line of it.config.shared.validation) { -%> +- <%= line %> +<% } -%> +- Store details as `` and the outcome as `` (`yes` or `no`) +- STOP before commit, push, or replies when validation fails + +### Review Fixes + +<% if (!it.auto) { -%> +- If `` is `auto`, skip this review gate and continue to commit and push +- Present the fix summary, changed-file count, and validation results +- If changes were made, ask one `Review Fixes` question with `Go Ahead` and `Revise`; apply custom revision feedback and repeat implementation and validation until approved +- If no changes were made, ask one `Need Feedback` question with `Revise` and `Stop Here` +- STOP if approval is required but `question` is unavailable +<% } else { -%> +- Continue without an approval prompt +- If actionable work produced no changes and `` is `already up to date`, STOP to avoid looping without progress +<% } -%> + +### Commit And Push Fixes + +- If fixes produced uncommitted changes, stage the focused changes and create a conventional commit +- If the base update already created a merge commit and there are no additional changes, do not create an empty commit +- Push the branch, setting its upstream when necessary +- Store push status as `` +- STOP if commit or push fails + +### Respond To Threads + +- Only after commit and push succeed, use `<%= it.config.tools.pr_sync.name %>` to post short factual replies to addressed feedback +- Reply with `replies` keyed by the addressed comment IDs; use `commentBody` only for general CI feedback +- Store the number of addressed threads as `` diff --git a/packages/core/components/push.md b/packages/core/components/push.md new file mode 100644 index 0000000..3c123f4 --- /dev/null +++ b/packages/core/components/push.md @@ -0,0 +1,7 @@ +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error diff --git a/packages/core/components/summarize-changes.md b/packages/core/components/summarize-changes.md deleted file mode 100644 index 3226f56..0000000 --- a/packages/core/components/summarize-changes.md +++ /dev/null @@ -1,8 +0,0 @@ -### Summarize Changes - -- Note the comparison mode, base branch, and current branch from the result -- If the comparison is not `uncommitted`, use only the commits in `.commits` as the branch-work scope -- Review commit messages when they are available to understand the delivery narrative -- Read the most relevant changed source files to understand the changes introduced by those commits -- Do not describe work that exists only on the base branch or that is outside the commits ahead of base -- Group related changes into themes for the final summary diff --git a/packages/core/components/ticket-planning.md b/packages/core/components/ticket-planning.md new file mode 100644 index 0000000..1b551b3 --- /dev/null +++ b/packages/core/components/ticket-planning.md @@ -0,0 +1,42 @@ +### Interpret Arguments + +- If `` looks like a ticket reference or URL, store it as `` +- Otherwise, treat `` as `` +- If `` includes planning focus areas, constraints, or notes beyond the main request, store them as `` +- If no `` are provided, derive the current request from the conversation and store it as `` + +### Load Planning Context + +- If `` is defined: +<%~ include("@load-ticket", { config: it.config, source: "", result: "", comments: true }) %> +- Otherwise, treat the relevant request and conversation context as `` +- If `` is empty or missing, STOP and report that planning context could not be determined + +### Interpret Planning Context + +- From `` and ``, derive: + - `` - the current planning task or request + - `` - earlier context that still applies + - `` - technical details already proposed in the discussion + - `` - only the issues that are still unresolved +- Use the current request to determine `` +- Do not discard earlier comments when they still define constraints, business rules, implementation decisions, migration rules, naming, sequencing, or scoping limits + +### Inspect Repo Context + +- If the request is technical and repository context is available, perform light targeted reconnaissance before finalizing the plan +- Inspect the relevant code, schema, config, UI patterns, and tests needed to validate `` and ground the plan +- Confirm current behavior and existing patterns instead of relying on ticket text alone +- If relevant repo context cannot be found or verified, note that gap and avoid false certainty + +### Shape the Plan + +- Turn ``, ``, ``, ``, and repo findings into: + - `` - a short, useful title + - `` - a brief description of the intended outcome, scope, important constraints, and material technical direction + - `` - concise requirement checklist items + - `` - validation checklist items +- Preserve good technical details from the ticket or conversation when they are valid +- Improve incomplete technical details when repo inspection provides a better grounded direction +- Do not replace material technical guidance with generic outcome language +- Avoid placeholder-like labels or awkward title formats such as `Ticket`, `Description`, or `Ticket : Description` diff --git a/packages/core/index.ts b/packages/core/index.ts index 1064336..fdda70c 100644 --- a/packages/core/index.ts +++ b/packages/core/index.ts @@ -22,9 +22,8 @@ export type { } from "./lib/config.ts"; export { createTools } from "./tools/index.ts"; export { createChangesLoadTool } from "./tools/changes-load.ts"; -export { createCommandExpansionTool, resolveCommandExpansion } from "./tools/dispatch.ts"; -export type { CommandExpansion } from "./tools/dispatch.ts"; export { createPrLoadTool } from "./tools/pr-load.ts"; +export { createPrLoadReviewTool } from "./tools/pr-load-review.ts"; export { createPrSyncTool } from "./tools/pr-sync.ts"; export { createTicketLoadTool } from "./tools/ticket-load.ts"; export { createTicketSyncTool } from "./tools/ticket-sync.ts"; diff --git a/packages/core/kompass.jsonc b/packages/core/kompass.jsonc index ad61bfa..6260572 100644 --- a/packages/core/kompass.jsonc +++ b/packages/core/kompass.jsonc @@ -13,19 +13,24 @@ "commands": { "ask": { "enabled": true }, "branch": { "enabled": true }, + "branch/inline": { "enabled": true }, "commit": { "enabled": true }, + "commit/inline": { "enabled": true }, "commit-and-push": { "enabled": true }, + "commit-and-push/inline": { "enabled": true }, "dev": { "enabled": true }, "learn": { "enabled": true }, - "loop/pr/fix": { "enabled": true }, "merge": { "enabled": true }, "pr/create": { "enabled": true }, + "pr/create/inline": { "enabled": true }, "pr/fix": { "enabled": true }, + "pr/fix/loop": { "enabled": true }, "pr/review": { "enabled": true }, "review": { "enabled": true }, "skill/create": { "enabled": true }, "skill/optimize": { "enabled": true }, "ship": { "enabled": true }, + "ship/inline": { "enabled": true }, "rmslop": { "enabled": true }, "todo": { "enabled": true }, "ticket/ask": { "enabled": true }, @@ -37,15 +42,14 @@ "agents": { "worker": { "enabled": true }, - "navigator": { "enabled": true }, "planner": { "enabled": true }, "reviewer": { "enabled": true }, }, "tools": { "changes_load": { "enabled": true }, - "command_expansion": { "enabled": true }, "pr_load": { "enabled": true }, + "pr_load_review": { "enabled": true }, "pr_sync": { "enabled": true }, "ticket_load": { "enabled": true }, "ticket_sync": { "enabled": true }, @@ -53,13 +57,18 @@ "components": { "change-summary": { "enabled": true }, + "branch": { "enabled": true }, "changes-summary": { "enabled": true }, "commit": { "enabled": true }, "dev-flow": { "enabled": true }, "load-pr": { "enabled": true }, "load-ticket": { "enabled": true }, + "pr-create": { "enabled": true }, + "pr-branch-update": { "enabled": true }, + "pr-fix": { "enabled": true }, + "push": { "enabled": true }, "skill-authoring": { "enabled": true }, - "summarize-changes": { "enabled": true }, + "ticket-planning": { "enabled": true }, }, "defaults": { diff --git a/packages/core/lib/config.ts b/packages/core/lib/config.ts index c5d94a5..97ec9f3 100644 --- a/packages/core/lib/config.ts +++ b/packages/core/lib/config.ts @@ -15,8 +15,8 @@ export interface AgentDefinition { export const DEFAULT_TOOL_NAMES = [ "changes_load", - "command_expansion", "pr_load", + "pr_load_review", "pr_sync", "ticket_sync", "ticket_load", @@ -25,19 +25,24 @@ export const DEFAULT_TOOL_NAMES = [ export const DEFAULT_COMMAND_NAMES = [ "ask", "branch", + "branch/inline", "commit", + "commit/inline", "commit-and-push", + "commit-and-push/inline", "dev", "learn", - "loop/pr/fix", "merge", "pr/create", + "pr/create/inline", "pr/fix", + "pr/fix/loop", "pr/review", "review", "skill/create", "skill/optimize", "ship", + "ship/inline", "rmslop", "todo", "ticket/ask", @@ -47,17 +52,22 @@ export const DEFAULT_COMMAND_NAMES = [ "ticket/plan-and-sync", ] as const; -export const DEFAULT_AGENT_NAMES = ["worker", "navigator", "planner", "reviewer"] as const; +export const DEFAULT_AGENT_NAMES = ["worker", "planner", "reviewer"] as const; export const DEFAULT_COMPONENT_NAMES = [ "change-summary", + "branch", "changes-summary", "commit", "dev-flow", "load-pr", "load-ticket", + "pr-create", + "pr-branch-update", + "pr-fix", + "push", "skill-authoring", - "summarize-changes", + "ticket-planning", ] as const; export type ToolName = (typeof DEFAULT_TOOL_NAMES)[number]; @@ -94,19 +104,24 @@ export interface KompassConfig { commands?: { ask?: CommandConfig; branch?: CommandConfig; + "branch/inline"?: CommandConfig; commit?: CommandConfig; + "commit/inline"?: CommandConfig; "commit-and-push"?: CommandConfig; + "commit-and-push/inline"?: CommandConfig; dev?: CommandConfig; learn?: CommandConfig; - "loop/pr/fix"?: CommandConfig; merge?: CommandConfig; "pr/create"?: CommandConfig; + "pr/create/inline"?: CommandConfig; "pr/fix"?: CommandConfig; + "pr/fix/loop"?: CommandConfig; "pr/review"?: CommandConfig; review?: CommandConfig; "skill/create"?: CommandConfig; "skill/optimize"?: CommandConfig; ship?: CommandConfig; + "ship/inline"?: CommandConfig; rmslop?: CommandConfig; todo?: CommandConfig; "ticket/ask"?: CommandConfig; @@ -119,28 +134,32 @@ export interface KompassConfig { }; agents?: { worker?: AgentConfig; - navigator?: AgentConfig; planner?: AgentConfig; reviewer?: AgentConfig; enabled?: string[]; }; tools?: { changes_load?: ToolConfig; - command_expansion?: ToolConfig; pr_load?: ToolConfig; + pr_load_review?: ToolConfig; pr_sync?: ToolConfig; ticket_sync?: ToolConfig; ticket_load?: ToolConfig; }; components?: { "change-summary"?: ComponentConfig; + branch?: ComponentConfig; "changes-summary"?: ComponentConfig; commit?: ComponentConfig; "dev-flow"?: ComponentConfig; "load-pr"?: ComponentConfig; "load-ticket"?: ComponentConfig; + "pr-create"?: ComponentConfig; + "pr-branch-update"?: ComponentConfig; + "pr-fix"?: ComponentConfig; + push?: ComponentConfig; "skill-authoring"?: ComponentConfig; - "summarize-changes"?: ComponentConfig; + "ticket-planning"?: ComponentConfig; enabled?: string[]; paths?: Record; }; @@ -169,14 +188,13 @@ export interface MergedKompassConfig { agents: { worker: AgentDefinition; enabled: string[]; - navigator: AgentDefinition; reviewer: AgentDefinition; planner: AgentDefinition; }; tools: { changes_load: ToolConfig; - command_expansion: ToolConfig; pr_load: ToolConfig; + pr_load_review: ToolConfig; pr_sync: ToolConfig; ticket_sync: ToolConfig; ticket_load: ToolConfig; @@ -434,12 +452,6 @@ const defaultAgentReviewer: AgentDefinition = { permission: { edit: "deny", question: "allow", todowrite: "allow" }, }; -const defaultAgentNavigator: AgentDefinition = { - description: "Coordinate structured multi-step workflows and run focused slash-command steps in the current session.", - promptPath: "agents/navigator.md", - permission: { edit: "deny", task: "allow", question: "allow", todowrite: "allow" }, -}; - const defaultAgentPlanner: AgentDefinition = { description: "Turn requests or tickets into scoped implementation plans.", promptPath: "agents/planner.md", @@ -448,19 +460,24 @@ const defaultAgentPlanner: AgentDefinition = { const defaultComponentPaths: Record = { "change-summary": "components/change-summary.md", + branch: "components/branch.md", "changes-summary": "components/changes-summary.md", "commit": "components/commit.md", "dev-flow": "components/dev-flow.md", "load-pr": "components/load-pr.md", "load-ticket": "components/load-ticket.md", + "pr-create": "components/pr-create.md", + "pr-branch-update": "components/pr-branch-update.md", + "pr-fix": "components/pr-fix.md", + push: "components/push.md", "skill-authoring": "components/skill-authoring.md", - "summarize-changes": "components/summarize-changes.md", + "ticket-planning": "components/ticket-planning.md", }; const defaultToolConfig: Record = { changes_load: { enabled: true }, - command_expansion: { enabled: true }, pr_load: { enabled: true }, + pr_load_review: { enabled: true }, pr_sync: { enabled: true }, ticket_sync: { enabled: true }, ticket_load: { enabled: true }, @@ -563,8 +580,6 @@ export function mergeWithDefaults( config: KompassConfig | null, ): MergedKompassConfig { const { enabled: _workerEnabled, ...workerOverrides } = config?.agents?.worker ?? {}; - const { enabled: _navigatorEnabled, ...navigatorOverrides } = - config?.agents?.navigator ?? {}; const { enabled: _reviewerEnabled, ...reviewerOverrides } = config?.agents?.reviewer ?? {}; const { enabled: _plannerEnabled, ...plannerOverrides } = config?.agents?.planner ?? {}; @@ -601,17 +616,16 @@ export function mergeWithDefaults( DEFAULT_AGENT_NAMES, ), worker: { ...defaultAgentWorker, ...workerOverrides }, - navigator: { ...defaultAgentNavigator, ...navigatorOverrides }, reviewer: { ...defaultAgentReviewer, ...reviewerOverrides }, planner: { ...defaultAgentPlanner, ...plannerOverrides }, }, tools: { changes_load: { ...defaultToolConfig.changes_load, ...config?.tools?.changes_load }, - command_expansion: { - ...defaultToolConfig.command_expansion, - ...config?.tools?.command_expansion, - }, pr_load: { ...defaultToolConfig.pr_load, ...config?.tools?.pr_load }, + pr_load_review: { + ...defaultToolConfig.pr_load_review, + ...config?.tools?.pr_load_review, + }, pr_sync: { ...defaultToolConfig.pr_sync, ...config?.tools?.pr_sync }, ticket_sync: { ...defaultToolConfig.ticket_sync, ...config?.tools?.ticket_sync }, ticket_load: { ...defaultToolConfig.ticket_load, ...config?.tools?.ticket_load }, diff --git a/packages/core/test/changes-load.e2e.test.ts b/packages/core/test/changes-load.e2e.test.ts index 537a6bf..9539c03 100644 --- a/packages/core/test/changes-load.e2e.test.ts +++ b/packages/core/test/changes-load.e2e.test.ts @@ -243,6 +243,31 @@ describe("changes_load e2e", () => { assert.equal(result.commits, undefined); }); + test("defers oversized diffs while preserving the file manifest", async () => { + const repo = await createRepo(); + const original = Array.from({ length: 1_500 }, (_, index) => `old-${index}`).join("\n") + "\n"; + const updated = Array.from({ length: 1_500 }, (_, index) => `new-${index}`).join("\n") + "\n"; + await commitFile(repo, "first.txt", original, "init"); + await commitFile(repo, "second.txt", original, "add second file"); + await git(repo, ["checkout", "-b", "feature"]); + await writeFile(path.join(repo, "first.txt"), updated, "utf8"); + await writeFile(path.join(repo, "second.txt"), updated, "utf8"); + await git(repo, ["add", "."]); + await git(repo, ["commit", "-m", "large changes"]); + + const result = await runChangesLoad(repo, { base: "main", head: "HEAD" }); + + assert.ok(result.deferredDiffs); + assert.equal(result.diffsComplete, false); + assert.equal(result.deferredDiffs.required, true); + assert.equal(result.files[0].diff, undefined); + assert.equal(result.files[0].diffDeferred, true); + assert.ok(Buffer.byteLength(JSON.stringify(result), "utf8") <= 50 * 1024); + assert.equal(result.files.length, 2); + assert.match(result.deferredDiffs.loadWith, /Do not report the diff load as complete/); + assert.match(result.deferredDiffs.loadWith, /every deferred diff/); + }); + }); async function createRepo() { diff --git a/packages/core/test/commands.test.ts b/packages/core/test/commands.test.ts index 65cd704..8b7257b 100644 --- a/packages/core/test/commands.test.ts +++ b/packages/core/test/commands.test.ts @@ -28,18 +28,56 @@ describe("resolveCommands", () => { const commands = await resolveCommands(process.cwd()); const template = commands["pr/fix"]?.template ?? ""; - assert.match(template, /Run `gh pr checkout ` before analyzing repository files or making code changes for this PR/); - assert.match(template, /Do not inspect or modify local code for this PR until `` equals ``/); + assert.match(template, /Run `gh pr checkout ` before inspecting or modifying code/); + assert.match(template, /STOP unless it equals ``/); + assert.match(template, /git merge-base --is-ancestor HEAD/); + assert.match(template, /merge `` into `` without rebasing or force-pushing/); assert.doesNotMatch(template, /`` differs from `` or `` differs from ``/); }); - test("orchestrates loop pr fix through ci and delegated auto fixes", async () => { + test("runs pr fix loop inline with incremental review loading", async () => { const commands = await resolveCommands(process.cwd()); - const template = commands["loop/pr/fix"]?.template ?? ""; + const template = commands["pr/fix/loop"]?.template ?? ""; assert.match(template, /gh pr checks --watch/); - assert.match(template, /command="pr\/fix"/); - assert.match(template, /auto /); + assert.match(template, /pr_load_review/); + assert.match(template, /since: /); + assert.doesNotMatch(template, / { + const commands = await resolveCommands(process.cwd()); + + assert.equal(commands["branch/inline"]?.subtask, false); + assert.equal(commands["commit/inline"]?.subtask, false); + assert.equal(commands["commit-and-push/inline"]?.subtask, false); + assert.equal(commands["pr/create/inline"]?.subtask, false); + assert.equal(commands["ship/inline"]?.subtask, false); + assert.match(commands["branch/inline"]?.template ?? "", /Do not call `changes_load`/); + assert.match(commands["commit/inline"]?.template ?? "", /Reuse the current session's known uncommitted changes/); + assert.match(commands["commit-and-push/inline"]?.template ?? "", /Do not call `changes_load`/); + assert.match(commands["commit-and-push/inline"]?.template ?? "", /git push -u origin /); + assert.match(commands["pr/create/inline"]?.template ?? "", /Retain the authoritative branch comparison load/); + assert.match(commands["pr/create/inline"]?.template ?? "", /call `changes_load`/); + assert.match(commands["ship/inline"]?.template ?? "", /Do not call `changes_load` before the branch and commit phases/); + assert.doesNotMatch(commands.commit?.template ?? "", /Reuse the current session's known uncommitted changes/); + }); + + test("analyzes each loaded PR comparison once", async () => { + const commands = await resolveCommands(process.cwd()); + const marker = /#### Analyze And Summarize Changes/g; + + assert.equal(commands["pr/create"]?.template.match(marker)?.length, 1); + assert.equal(commands.ship?.template.match(marker)?.length, 2); + }); + + test("uses declared subtask mode instead of the CI fallback for templates", async () => { + const commands = await resolveCommands(process.cwd(), { ci: true }); + + assert.equal(commands.commit?.subtask, false); + assert.match(commands.commit?.template ?? "", /call `changes_load`/); + assert.doesNotMatch(commands.commit?.template ?? "", /Reuse the current session's known uncommitted changes/); + assert.match(commands["commit/inline"]?.template ?? "", /Reuse the current session's known uncommitted changes/); + }); }); diff --git a/packages/core/test/config.test.ts b/packages/core/test/config.test.ts index 5169df3..24c5459 100644 --- a/packages/core/test/config.test.ts +++ b/packages/core/test/config.test.ts @@ -241,7 +241,6 @@ describe("object-based config", () => { }, agents: { worker: { permission: { question: "deny", bash: "allow" } }, - navigator: { permission: { task: "deny", todowrite: "deny" } }, reviewer: { enabled: false }, }, components: { @@ -259,10 +258,6 @@ describe("object-based config", () => { question: "deny", bash: "allow", }); - assert.deepEqual(config.agents.navigator.permission, { - task: "deny", - todowrite: "deny", - }); assert.equal(config.agents.enabled.includes("reviewer"), false); assert.equal(config.components.enabled.includes("dev-flow"), false); assert.equal(config.components.paths.commit, "components/custom-commit.md"); @@ -270,7 +265,7 @@ describe("object-based config", () => { }); describe("command defaults", () => { - test("enables worker and navigator agents by default", () => { + test("enables worker agent by default", () => { const config = mergeWithDefaults(null); assert.equal(config.agents.enabled.includes("worker"), true); @@ -278,14 +273,7 @@ describe("command defaults", () => { question: "allow", todowrite: "allow", }); - assert.equal(config.agents.enabled.includes("navigator"), true); assert.deepEqual(config.shared.validation, []); - assert.deepEqual(config.agents.navigator.permission, { - edit: "deny", - task: "allow", - question: "allow", - todowrite: "allow", - }); }); test("enables todo command by default", () => { @@ -293,4 +281,16 @@ describe("command defaults", () => { assert.equal(config.commands.enabled.includes("todo"), true); }); + + test("enables inline variants and the nested PR fix loop by default", () => { + const config = mergeWithDefaults(null); + + assert.equal(config.commands.enabled.includes("branch/inline"), true); + assert.equal(config.commands.enabled.includes("commit/inline"), true); + assert.equal(config.commands.enabled.includes("commit-and-push/inline"), true); + assert.equal(config.commands.enabled.includes("pr/create/inline"), true); + assert.equal(config.commands.enabled.includes("ship/inline"), true); + assert.equal(config.commands.enabled.includes("pr/fix/loop"), true); + assert.equal(config.commands.enabled.includes("loop/pr/fix"), false); + }); }); diff --git a/packages/core/test/dispatch.test.ts b/packages/core/test/dispatch.test.ts deleted file mode 100644 index 0500872..0000000 --- a/packages/core/test/dispatch.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { describe, test } from "node:test"; -import assert from "node:assert/strict"; -import os from "node:os"; -import path from "node:path"; - -import { resolveCommandExpansion } from "../index.ts"; - -process.env.HOME = path.join(os.tmpdir(), `kompass-test-home-${process.pid}-core-dispatch`); - -describe("resolveCommandExpansion", () => { - test("expands known slash commands", async () => { - const result = await resolveCommandExpansion(process.cwd(), { command: "review", body: "auth bug" }); - - assert.equal(result.command, "review"); - assert.equal(result.body, "auth bug"); - assert.equal(result.expanded, true); - assert.match(result.prompt, /\s*auth bug\s*<\/arguments>/); - }); - - test("expands planner commands without carrying routing state", async () => { - const result = await resolveCommandExpansion(process.cwd(), { - command: "ticket/plan", - body: "auth bug", - }); - - assert.equal(result.command, "ticket/plan"); - assert.equal(result.body, "auth bug"); - assert.equal(result.expanded, true); - }); - - test("returns the expanded prompt at tool level", async () => { - const { createCommandExpansionTool } = await import("../index.ts"); - const tool = createCommandExpansionTool(process.cwd()); - const output = await tool.execute( - { command: "review", body: "auth bug" }, - { worktree: process.cwd(), directory: process.cwd() }, - ); - - assert.match(output, /## Goal/); - assert.match(output, /auth bug/); - }); - - test("keeps unknown slash commands dispatchable without expansion", async () => { - const result = await resolveCommandExpansion(process.cwd(), { command: "unknown", body: "auth bug" }); - - assert.deepEqual(result, { - command: "unknown", - body: "auth bug", - prompt: "/unknown\nauth bug", - expanded: false, - }); - }); - - test("rejects missing commands", async () => { - await assert.rejects( - resolveCommandExpansion(process.cwd(), { command: " ", body: "auth bug" }), - /requires a command/, - ); - }); -}); diff --git a/packages/core/test/pr-load.test.ts b/packages/core/test/pr-load.test.ts index 8257800..215e327 100644 --- a/packages/core/test/pr-load.test.ts +++ b/packages/core/test/pr-load.test.ts @@ -4,6 +4,7 @@ import assert from "node:assert/strict"; import { createToolContextForDirectory } from "../scripts/_tool-runner.ts"; import type { Shell, ShellPromise } from "../tools/shared.ts"; import { createPrLoadTool } from "../tools/pr-load.ts"; +import { createPrLoadReviewTool } from "../tools/pr-load-review.ts"; describe("pr_load", () => { test("normalizes threads and keeps multiline ranges", async () => { @@ -393,6 +394,35 @@ describe("pr_load", () => { assert.equal(result.pr.commitCount, 0); }); + + test("loads only review activity after the checkpoint", async () => { + const shell = createMockShell([ + { contains: "gh pr view 7 --json number,url", stdout: JSON.stringify({ number: 7, url: "https://github.com/acme/repo/pull/7" }) }, + { contains: "gh repo view --json nameWithOwner", stdout: JSON.stringify({ nameWithOwner: "acme/repo" }) }, + { contains: "gh api user", stdout: JSON.stringify({ login: "review-bot" }) }, + { contains: "pulls/7/reviews?per_page=100", stdout: JSON.stringify([[{ + id: 1, state: "COMMENTED", body: "new", submitted_at: "2026-03-07T00:00:02Z", user: { login: "octo" }, + }]]) }, + { contains: "issues/7/comments?per_page=100&since=2026-03-07T00%3A00%3A00Z", stdout: JSON.stringify([[{ + id: 2, body: "updated", created_at: "2026-03-06T00:00:00Z", updated_at: "2026-03-07T00:00:03Z", user: { login: "octo" }, + }]]) }, + { contains: "gh api graphql", stdout: JSON.stringify({ data: { repository: { pullRequest: { reviewThreads: { + pageInfo: { hasNextPage: false, endCursor: null }, + nodes: [{ id: "thread-1", isResolved: false, isOutdated: false, path: "x.ts", line: 1, comments: { nodes: [{ databaseId: 3, body: "new", createdAt: "2026-03-07T00:00:04Z", updatedAt: "2026-03-07T00:00:04Z", author: { login: "octo" } }] } }], + } } } } }) }, + ]); + + const output = await createPrLoadReviewTool(shell).execute( + { pr: "7", since: "2026-03-07T00:00:00Z" }, + createToolContextForDirectory("/tmp/repo"), + ); + const result = JSON.parse(output); + + assert.equal(result.reviews.length, 1); + assert.equal(result.issueComments.length, 1); + assert.equal(result.threads.length, 1); + assert.ok(result.loadedAt); + }); }); function createMockShell( diff --git a/packages/core/tools/changes-load.ts b/packages/core/tools/changes-load.ts index debbc90..aebf73a 100644 --- a/packages/core/tools/changes-load.ts +++ b/packages/core/tools/changes-load.ts @@ -14,9 +14,12 @@ import { type ToolExecutionContext, } from "./shared.ts"; +const MAX_RESULT_BYTES = 50 * 1024; + export function createChangesLoadTool($: Shell) { return { - description: "Load branch changes against a base branch", + description: + "Load changed files and diffs against a base branch. If deferredDiffs is present, the diff load is incomplete: inspect every deferred diff before reporting completion unless the caller explicitly requested metadata only.", args: { base: { type: "string", optional: true, description: "Base branch or ref" }, head: { @@ -54,7 +57,7 @@ export function createChangesLoadTool($: Shell) { return await loadTemporaryIndexDiffs($, ctx.worktree, indexPath, files); }); - return stringifyJson({ + return serializeChangesResult({ comparison: "uncommitted", ...(branch ? { branch } : {}), files: filesWithDiff, @@ -105,7 +108,7 @@ export function createChangesLoadTool($: Shell) { : await loadFileDiffs($, ctx.worktree, baseRef, headRef, parsedFiles); const commits = parseCommitList(log.text()); - return stringifyJson({ + return serializeChangesResult({ comparison: `${baseRef}...${headRef}`, ...(branch ? { branch } : {}), files: filesWithDiff, @@ -120,6 +123,34 @@ export function createChangesLoadTool($: Shell) { }>; } +function serializeChangesResult(result: Record & { files: Array> }) { + const output = stringifyJson(result); + if (Buffer.byteLength(output, "utf8") <= MAX_RESULT_BYTES) return output; + + let deferredCount = 0; + const files = result.files.map((file) => { + if (typeof file.diff !== "string") return file; + + deferredCount += 1; + const metadata = { ...file }; + delete metadata.diff; + return { ...metadata, diffDeferred: true }; + }); + + return stringifyJson({ + ...result, + files, + diffsComplete: false, + deferredDiffs: { + count: deferredCount, + reason: "diffs omitted because the complete tool result exceeded 50 KiB", + required: true, + loadWith: + "Do not report the diff load as complete. Inspect every deferred diff directly, one file at a time, using the returned comparison and file paths, unless the caller explicitly requested metadata only.", + }, + }); +} + function normalizeDepthHint(depthHint?: number) { const candidate = depthHint; return typeof candidate === "number" && Number.isInteger(candidate) diff --git a/packages/core/tools/dispatch.ts b/packages/core/tools/dispatch.ts deleted file mode 100644 index 0c5a56c..0000000 --- a/packages/core/tools/dispatch.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { resolveCommands } from "../commands/index.ts"; -import type { AgentName, CommandName, ToolName } from "../lib/config.ts"; -import type { ToolDefinition, ToolExecutionContext } from "./shared.ts"; - -export type CommandExpansion = { - command: string; - body: string; - prompt: string; - expanded: boolean; -}; - -type ResolveCommandExpansionOptions = { - names?: { - tools?: Partial>; - commands?: Partial>; - agents?: Partial>; - }; -}; - -type CommandExpansionInput = { - command: string; - body?: string; -}; - -function renderSlashCommand(command: string, body: string) { - const trimmedBody = body.trim(); - return trimmedBody ? `/${command}\n${trimmedBody}` : `/${command}`; -} - -function expandCommandTemplate(template: string, commandBody: string) { - const trimmedBody = commandBody.trim(); - const positionalArguments = trimmedBody ? trimmedBody.split(/\s+/) : []; - - let expandedTemplate = template.replaceAll("$ARGUMENTS", trimmedBody); - - for (const [index, argument] of positionalArguments.entries()) { - expandedTemplate = expandedTemplate.replaceAll(`$${index + 1}`, argument); - } - - return expandedTemplate; -} - -export async function resolveCommandExpansion( - projectRoot: string, - input: CommandExpansionInput, - options?: ResolveCommandExpansionOptions, -): Promise { - const normalizedCommand = input.command.trim(); - const normalizedBody = input.body?.trim() ?? ""; - - if (!normalizedCommand) { - throw new Error("command_expansion requires a command"); - } - - const commands = await resolveCommands(projectRoot, { names: options?.names }); - const definition = commands[normalizedCommand]; - - if (!definition) { - return { - command: normalizedCommand, - body: normalizedBody, - prompt: renderSlashCommand(normalizedCommand, normalizedBody), - expanded: false, - }; - } - - const prompt = expandCommandTemplate(definition.template, normalizedBody); - - return { - command: normalizedCommand, - body: normalizedBody, - prompt, - expanded: true, - }; -} - -export function createCommandExpansionTool( - projectRoot: string, - options?: ResolveCommandExpansionOptions, -) { - return { - description: "Expand a delegated command body into a runnable prompt", - args: { - command: { - type: "string", - description: "Command name to resolve, without the leading slash", - }, - body: { - type: "string", - optional: true, - description: "Literal body content from the delegate block", - }, - }, - async execute( - args: { command: string; body?: string }, - _ctx: ToolExecutionContext, - ) { - const resolved = await resolveCommandExpansion(projectRoot, args, options); - return resolved.prompt; - }, - } satisfies ToolDefinition<{ command: string; body?: string }>; -} diff --git a/packages/core/tools/index.ts b/packages/core/tools/index.ts index e61fe87..efcafe7 100644 --- a/packages/core/tools/index.ts +++ b/packages/core/tools/index.ts @@ -5,8 +5,8 @@ import { mergeWithDefaults, } from "../lib/config.ts"; import { createChangesLoadTool } from "./changes-load.ts"; -import { createCommandExpansionTool } from "./dispatch.ts"; import { createPrLoadTool } from "./pr-load.ts"; +import { createPrLoadReviewTool } from "./pr-load-review.ts"; import { createPrSyncTool } from "./pr-sync.ts"; import { createTicketLoadTool } from "./ticket-load.ts"; import { createTicketSyncTool } from "./ticket-sync.ts"; @@ -14,8 +14,8 @@ import type { Shell, ToolDefinition } from "./shared.ts"; const toolCreators: Record ToolDefinition> = { changes_load: ($) => createChangesLoadTool($), - command_expansion: (_, projectRoot) => createCommandExpansionTool(projectRoot), pr_load: ($) => createPrLoadTool($), + pr_load_review: ($) => createPrLoadReviewTool($), pr_sync: ($) => createPrSyncTool($), ticket_sync: ($) => createTicketSyncTool($), ticket_load: ($) => createTicketLoadTool($), diff --git a/packages/core/tools/pr-load-review.ts b/packages/core/tools/pr-load-review.ts new file mode 100644 index 0000000..be2e200 --- /dev/null +++ b/packages/core/tools/pr-load-review.ts @@ -0,0 +1,61 @@ +import { loadRepoName, stringifyJson, type Shell, type ToolDefinition, type ToolExecutionContext } from "./shared.ts"; +import { + loadPaginatedArray, + loadReviewThreads, + loadViewerLogin, + simplifyIssueComments, + simplifyReviews, + simplifyThreads, +} from "./pr-load.ts"; + +function after(value: unknown, since: number) { + return typeof value === "string" && Date.parse(value) > since; +} + +export function createPrLoadReviewTool($: Shell) { + return { + description: "Load PR reviews, comments, and threads updated after a timestamp", + args: { + pr: { type: "string", optional: true, description: "PR number or URL" }, + since: { type: "string", description: "Exclusive ISO-8601 review checkpoint" }, + }, + async execute( + args: { pr?: string; since: string }, + ctx: ToolExecutionContext, + ) { + const sinceTime = Date.parse(args.since); + if (!Number.isFinite(sinceTime)) { + throw new Error("since must be a valid ISO-8601 timestamp"); + } + + const loadedAt = new Date().toISOString(); + const proc = args.pr + ? await $`gh pr view ${args.pr} --json number,url`.cwd(ctx.worktree).quiet().nothrow() + : await $`gh pr view --json number,url`.cwd(ctx.worktree).quiet().nothrow(); + if (proc.exitCode !== 0) throw new Error(proc.stderr.toString() || "Failed to resolve PR"); + + const pr = JSON.parse(proc.text()); + const repo = await loadRepoName($, ctx.worktree); + const [owner, repoName] = repo.split("/"); + const viewerLogin = await loadViewerLogin($, ctx.worktree); + const encodedSince = encodeURIComponent(args.since); + const reviews = simplifyReviews(await loadPaginatedArray( + $, + ctx.worktree, + `repos/${repo}/pulls/${pr.number}/reviews?per_page=100`, + )).filter((review) => after(review.submittedAt, sinceTime)); + const issueComments = simplifyIssueComments(await loadPaginatedArray( + $, + ctx.worktree, + `repos/${repo}/issues/${pr.number}/comments?per_page=100&since=${encodedSince}`, + )).filter((comment) => after(comment.updatedAt ?? comment.createdAt, sinceTime)); + const threads = simplifyThreads( + await loadReviewThreads($, ctx.worktree, owner, repoName, pr.number), + ).filter((thread) => thread.comments.some( + (comment: { updatedAt?: string; createdAt?: string }) => after(comment.updatedAt ?? comment.createdAt, sinceTime), + )); + + return stringifyJson({ loadedAt, repo, viewerLogin, pr, reviews, issueComments, threads }); + }, + } satisfies ToolDefinition<{ pr?: string; since: string }>; +} diff --git a/packages/core/tools/pr-load.ts b/packages/core/tools/pr-load.ts index 6e201a8..cabf09f 100644 --- a/packages/core/tools/pr-load.ts +++ b/packages/core/tools/pr-load.ts @@ -33,7 +33,7 @@ function countPullRequestCommits(commits: unknown) { return 0; } -async function loadPaginatedArray($: Shell, cwd: string, endpoint: string) { +export async function loadPaginatedArray($: Shell, cwd: string, endpoint: string) { const proc = await $`gh api --paginate --slurp ${endpoint}`.cwd(cwd).quiet().nothrow(); if (proc.exitCode !== 0) { @@ -44,7 +44,7 @@ async function loadPaginatedArray($: Shell, cwd: string, endpoint: string) { return pages.flatMap((page) => (Array.isArray(page) ? page : [page])); } -async function loadReviewThreads($: Shell, cwd: string, owner: string, repo: string, number: number) { +export async function loadReviewThreads($: Shell, cwd: string, owner: string, repo: string, number: number) { const threads: any[] = []; let cursor: string | undefined; @@ -82,7 +82,7 @@ async function loadReviewThreads($: Shell, cwd: string, owner: string, repo: str return threads; } -async function loadViewerLogin($: Shell, cwd: string) { +export async function loadViewerLogin($: Shell, cwd: string) { const isGitHubActions = process.env.GITHUB_ACTIONS?.trim() === "true"; const workflowToken = process.env.GITHUB_TOKEN?.trim(); if (isGitHubActions && workflowToken) { @@ -153,7 +153,7 @@ function simplifyPullRequest(info: any) { }; } -function simplifyReviews(reviews: any[]) { +export function simplifyReviews(reviews: any[]) { return reviews .map((review) => ({ id: review.id, @@ -166,7 +166,7 @@ function simplifyReviews(reviews: any[]) { .filter((review) => review.state === "APPROVED" || typeof review.body === "string"); } -function simplifyIssueComments(comments: any[]) { +export function simplifyIssueComments(comments: any[]) { return comments.map((comment) => ({ id: comment.id, author: comment.user?.login, @@ -176,7 +176,7 @@ function simplifyIssueComments(comments: any[]) { })); } -function simplifyThreads(threads: any[]) { +export function simplifyThreads(threads: any[]) { return threads.map((thread) => ({ id: thread.id, path: thread.path, @@ -210,6 +210,7 @@ export function createPrLoadTool($: Shell) { }, ctx: ToolExecutionContext, ) { + const loadedAt = new Date().toISOString(); const proc = args.pr ? await $`gh pr view ${args.pr} --json ${prJsonKeys}` .cwd(ctx.worktree) @@ -241,6 +242,7 @@ export function createPrLoadTool($: Shell) { ); const threads = await loadReviewThreads($, ctx.worktree, owner, repoName, info.number); return stringifyJson({ + loadedAt, repo, viewerLogin, pr: simplifyPullRequest(info), diff --git a/packages/opencode/.opencode/agents/navigator.md b/packages/opencode/.opencode/agents/navigator.md deleted file mode 100644 index 61b5af0..0000000 --- a/packages/opencode/.opencode/agents/navigator.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -description: Coordinate structured multi-step workflows and run focused - slash-command steps in the current session. -permission: - edit: deny - task: allow - question: allow - todowrite: allow ---- - -You coordinate structured, multi-step workflows. - -## Rules - -- Follow the active command and provided context. -- Manage step order, stored state, approvals, and stop conditions yourself. -- Load only the context needed for the current step. -- Execute required user-interaction steps exactly as the command defines them; if a required interaction tool is unavailable, use the command's non-interactive fallback. -- If a step is blocked, incomplete, or fails, stop and report it clearly. - -## Delegation - -When you see a `...` block, you MUST make TWO tool calls in sequence: - -1. **Expand**: Call `kompass_command_expansion` with `command` from the tag and `body` set to the rendered block content -2. **Delegate**: IMMEDIATELY call `task` with `subagent_type: AGENT_NAME` and `prompt` set to the expanded text from step 1 - -**CRITICAL RULES:** -- These are TWO SEPARATE tool calls. You must call BOTH. -- DO NOT execute the expanded content yourself. Your job is to DELEGATE via `task`. -- The `task` result IS the delegated result. Use it as the source of truth. -- If you don't call `task`, the delegation is incomplete and will fail. - -- Treat each `` block as literal input; do not rewrite or interpret before expansion. -- Run `` blocks sequentially unless the workflow clearly makes them independent. -- If a `` block is malformed, the expansion fails, or the delegated `task` fails, stop and report it clearly. - -## Output - -- Follow any explicit command output exactly. -- Otherwise report what finished and whether the workflow is continuing, paused, blocked, or complete. diff --git a/packages/opencode/.opencode/agents/reviewer.md b/packages/opencode/.opencode/agents/reviewer.md index 76786b4..0d4d30b 100644 --- a/packages/opencode/.opencode/agents/reviewer.md +++ b/packages/opencode/.opencode/agents/reviewer.md @@ -22,6 +22,7 @@ Before reviewing, always check repository guidance: - In CI or shallow clones, pass explicit base and head refs - For branch comparisons, treat the returned commit list as the authoritative scope: review the commits ahead of base and use file diffs only as supporting context - Scan the summary first to understand scope, file states, and risk clusters + - If the result reports deferred diffs, inspect them directly one file at a time using the returned comparison and changed paths - Never switch branches, create local review branches, or otherwise mutate `HEAD`; if a loader fails, prefer reporting the blocker over changing checkout state 2. **Read Code**: Read every changed file individually before finalizing diff --git a/packages/opencode/.opencode/commands/branch.md b/packages/opencode/.opencode/commands/branch.md index 38d5921..831b590 100644 --- a/packages/opencode/.opencode/commands/branch.md +++ b/packages/opencode/.opencode/commands/branch.md @@ -26,40 +26,41 @@ $ARGUMENTS ### Load Changes -#### Step 1: Load Changes +#### Load Changes + - call `kompass_changes_load` - pass `uncommitted: true` to get uncommitted changes only - Store the returned result as `` -- Use `` as the source of truth; no additional git analysis commands are needed -- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits that are ahead of the resolved base branch -- Do not infer scope from the branch names alone and do not describe work that exists only on the base branch - -#### Step 2: Analyze Files -- Review the paths, statuses, and diffs from `` only as file-level context for the commits in scope +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context - Identify the nature of changes (added, modified, deleted) -- Note lines added/removed per file - -#### Step 3: Group and Summarize -- For branch comparisons, build the summary from `.commits` first and use file diffs only to verify or refine what those commits changed - Group related changes into logical themes - Summarize the "what" and "why" (not the "how") -- Store the loaded change result as `` +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base - Store the current branch as `` when it is available -### Check Blockers +### Check Branch -- If `` contains no files, STOP and report that there is nothing to branch from -- If `` already starts with a conventional work-branch category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, STOP and report that branching was skipped because the current branch already looks like a work branch +- Store the current branch from `` as `` when available +- If `` contains no files, store `` as `nothing to branch from` and skip branch creation +- If `` starts with a conventional work category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, store `` as `kept ` and skip branch creation ### Create Branch -- Choose a branch category from the summarized change themes and `` -- Prefer conventional categories such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` -- Store the chosen category as `` -- Generate a concise kebab-case slug from the summarized change themes and `` when available, then store it as `` +When branch creation was not skipped: +- Choose a conventional category such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` from the change themes and `` +- Generate a concise kebab-case slug from the same context - Create and checkout `/` with `git checkout -b` -- If that name already exists, retry once with a short numeric suffix -- Store the checked-out branch as `` +- If that name exists, retry once with a short numeric suffix +- Store the checked-out branch as `` and `` as `created ` +- If branch creation fails, STOP and report the blocker ### Output @@ -81,7 +82,7 @@ No additional steps are required. When the branch is created, display: ``` -Created branch: +Created branch: From: diff --git a/packages/opencode/.opencode/commands/branch/inline.md b/packages/opencode/.opencode/commands/branch/inline.md new file mode 100644 index 0000000..d6138fe --- /dev/null +++ b/packages/opencode/.opencode/commands/branch/inline.md @@ -0,0 +1,75 @@ +--- +description: Create a branch using context from the current session +agent: worker +subtask: false +--- + +## Goal + +Create and switch to a categorized branch whose name summarizes the current uncommitted work. Reuse the invoking session's change context instead of loading it again. + +## Additional Context + +Use `` to steer the branch category and slug while keeping the final name short, descriptive, and aligned with the change type. + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- If `` provides wording that should influence the branch name, store it as `` +- Otherwise, leave `` undefined + +### Load Changes + +- Reuse the current session's known uncommitted file set and diffs as `` +- Do not call `kompass_changes_load`; if session context is insufficient, inspect worktree status and relevant diffs to establish the complete remaining uncommitted file set without broadening scope +- Run `git branch --show-current` and store the result as `` + +### Check Branch + +- Store the current branch from `` as `` when available +- If `` contains no files, store `` as `nothing to branch from` and skip branch creation +- If `` starts with a conventional work category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, store `` as `kept ` and skip branch creation + +### Create Branch + +When branch creation was not skipped: +- Choose a conventional category such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` from the change themes and `` +- Generate a concise kebab-case slug from the same context +- Create and checkout `/` with `git checkout -b` +- If that name exists, retry once with a short numeric suffix +- Store the checked-out branch as `` and `` as `created ` +- If branch creation fails, STOP and report the blocker + +### Output + +If there is nothing to branch from, display: +``` +Nothing to branch from + +No additional steps are required. +``` + +If branching is skipped because the current branch already looks like a work branch, display: +``` +Branching skipped because the current branch already looks like a work branch. + +Current branch: + +No additional steps are required. +``` + +When the branch is created, display: +``` +Created branch: + +From: + +No additional steps are required. +``` diff --git a/packages/opencode/.opencode/commands/commit-and-push.md b/packages/opencode/.opencode/commands/commit-and-push.md index b451bd2..26f62fa 100644 --- a/packages/opencode/.opencode/commands/commit-and-push.md +++ b/packages/opencode/.opencode/commands/commit-and-push.md @@ -26,24 +26,24 @@ $ARGUMENTS ### Load Changes -#### Step 1: Load Changes +#### Load Changes + - call `kompass_changes_load` - pass `uncommitted: true` to get uncommitted changes only - Store the returned result as `` -- Use `` as the source of truth; no additional git analysis commands are needed -- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits that are ahead of the resolved base branch -- Do not infer scope from the branch names alone and do not describe work that exists only on the base branch - -#### Step 2: Analyze Files -- Review the paths, statuses, and diffs from `` only as file-level context for the commits in scope +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context - Identify the nature of changes (added, modified, deleted) -- Note lines added/removed per file - -#### Step 3: Group and Summarize -- For branch comparisons, build the summary from `.commits` first and use file diffs only to verify or refine what those commits changed - Group related changes into logical themes - Summarize the "what" and "why" (not the "how") -- Store the loaded change result as `` +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base ### Check Blockers @@ -75,13 +75,15 @@ type: summary 5. Create the commit with `` 6. Store the created commit hash as `` 7. Only run `git status` if the commit fails and needs diagnosis -- Store the created commit hash as `` ### Push to Remote +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` - Run `git push` and use its output as the source of truth -- If the current branch has no upstream set, retry with `git push -u origin ` -- Store the successful destination as `` +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` - If push fails, STOP and report the push error ### Output diff --git a/packages/opencode/.opencode/commands/commit-and-push/inline.md b/packages/opencode/.opencode/commands/commit-and-push/inline.md new file mode 100644 index 0000000..e664130 --- /dev/null +++ b/packages/opencode/.opencode/commands/commit-and-push/inline.md @@ -0,0 +1,92 @@ +--- +description: Commit and push using context from the current session +agent: worker +subtask: false +--- + +## Goal + +Create a commit and immediately push it to the remote repository. Reuse the invoking session's change context instead of loading it again. + +## Additional Context + +Consider `` when analyzing changes and writing the commit message. + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- If `` provides guidance for the commit message, store it as `` +- Otherwise, leave `` undefined + +### Load Changes + +- Reuse the current session's known uncommitted file set and diffs as `` +- Do not call `kompass_changes_load`; if session context is insufficient, inspect worktree status and relevant diffs to establish the complete remaining uncommitted file set without broadening scope + +### Check Blockers + +- If `` contains no files, STOP and report that there is nothing to commit or push + +### Create Commit + +### Message Format +- Prefer this format unless the change is tiny: + +```text +type: summary + +- change +- change +- change +``` + +- Keep the subject concise and under 72 characters +- Use conventional commit format: "feat:", "fix:", "refactor:", "docs:", etc. +- For non-trivial changes, add 2-5 short bullets with the main grouped changes +- Use a one-line commit only when a body would add no value + +### Commit Phase +1. Use the loaded change data as the source of truth for what will be committed +2. Stage changes with `git add` (use `-A` for all, or specific files) +3. Generate the commit message and store it as `` +4. Preserve the blank line between subject and bullets when present +5. Create the commit with `` +6. Store the created commit hash as `` +7. Only run `git status` if the commit fails and needs diagnosis + +### Push to Remote + +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error + +### Output + +If there is nothing to commit, display: +``` +Nothing to commit or push + +No additional steps are required. +``` + +When complete, display: +``` +Created commit ``: + + + +Pushed to + +No additional steps are required. +``` diff --git a/packages/opencode/.opencode/commands/commit.md b/packages/opencode/.opencode/commands/commit.md index 5db8e1d..353d054 100644 --- a/packages/opencode/.opencode/commands/commit.md +++ b/packages/opencode/.opencode/commands/commit.md @@ -26,24 +26,24 @@ $ARGUMENTS ### Load Changes -#### Step 1: Load Changes +#### Load Changes + - call `kompass_changes_load` - pass `uncommitted: true` to get uncommitted changes only - Store the returned result as `` -- Use `` as the source of truth; no additional git analysis commands are needed -- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits that are ahead of the resolved base branch -- Do not infer scope from the branch names alone and do not describe work that exists only on the base branch - -#### Step 2: Analyze Files -- Review the paths, statuses, and diffs from `` only as file-level context for the commits in scope +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context - Identify the nature of changes (added, modified, deleted) -- Note lines added/removed per file - -#### Step 3: Group and Summarize -- For branch comparisons, build the summary from `.commits` first and use file diffs only to verify or refine what those commits changed - Group related changes into logical themes - Summarize the "what" and "why" (not the "how") -- Store the loaded change result as `` +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base ### Check Blockers @@ -75,7 +75,6 @@ type: summary 5. Create the commit with `` 6. Store the created commit hash as `` 7. Only run `git status` if the commit fails and needs diagnosis -- Store the created commit hash as `` ### Output diff --git a/packages/opencode/.opencode/commands/commit/inline.md b/packages/opencode/.opencode/commands/commit/inline.md new file mode 100644 index 0000000..023ec68 --- /dev/null +++ b/packages/opencode/.opencode/commands/commit/inline.md @@ -0,0 +1,80 @@ +--- +description: Commit changes using context from the current session +agent: worker +subtask: false +--- + +## Goal + +Create a commit with an appropriate message summarizing the uncommitted changes. Reuse the invoking session's change context instead of loading it again. + +## Additional Context + +Consider `` when analyzing changes and writing the commit message. + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- If `` provides guidance for the commit message, store it as `` +- Otherwise, leave `` undefined + +### Load Changes + +- Reuse the current session's known uncommitted changes as `` +- Do not call `kompass_changes_load`; inspect the worktree only when the session context does not identify which files remain uncommitted + +### Check Blockers + +- If `` contains no files, STOP and report that there is nothing to commit + +### Create Commit + +### Message Format +- Prefer this format unless the change is tiny: + +```text +type: summary + +- change +- change +- change +``` + +- Keep the subject concise and under 72 characters +- Use conventional commit format: "feat:", "fix:", "refactor:", "docs:", etc. +- For non-trivial changes, add 2-5 short bullets with the main grouped changes +- Use a one-line commit only when a body would add no value + +### Commit Phase +1. Use the loaded change data as the source of truth for what will be committed +2. Stage changes with `git add` (use `-A` for all, or specific files) +3. Generate the commit message and store it as `` +4. Preserve the blank line between subject and bullets when present +5. Create the commit with `` +6. Store the created commit hash as `` +7. Only run `git status` if the commit fails and needs diagnosis + +### Output + +If there is nothing to commit, display: +``` +Nothing to commit + +No additional steps are required. +``` + +When the commit is created, display: +``` +Created commit ``: + + + +No additional steps are required. +``` diff --git a/packages/opencode/.opencode/commands/dev.md b/packages/opencode/.opencode/commands/dev.md index b0720e6..9857eb6 100644 --- a/packages/opencode/.opencode/commands/dev.md +++ b/packages/opencode/.opencode/commands/dev.md @@ -1,6 +1,6 @@ --- description: Implement a request and prepare it for PR creation -agent: navigator +agent: worker --- ## Goal diff --git a/packages/opencode/.opencode/commands/learn.md b/packages/opencode/.opencode/commands/learn.md index 95937d9..de23427 100644 --- a/packages/opencode/.opencode/commands/learn.md +++ b/packages/opencode/.opencode/commands/learn.md @@ -1,6 +1,7 @@ --- description: Extract learnings from session to AGENTS.md files agent: worker +subtask: false --- ## Goal diff --git a/packages/opencode/.opencode/commands/loop/pr/fix.md b/packages/opencode/.opencode/commands/loop/pr/fix.md deleted file mode 100644 index 907c8d0..0000000 --- a/packages/opencode/.opencode/commands/loop/pr/fix.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -description: Watch PR CI and comments, repeatedly fixing both without approval prompts -agent: navigator ---- - -## Goal - -Continuously watch a pull request, fix CI failures and PR feedback, commit, push, reply, and repeat until the PR is clean. - -## Additional Context - -Use `` to constrain which feedback should be handled, how aggressive the fix pass should be, or which CI checks matter when the PR has optional checks. -- This command is intentionally non-interactive: do not ask for approval before delegated fix work, commits, pushes, or PR replies. -- CI failures are part of the loop: capture them as actionable work, fix them, push, then watch CI again. - -## Workflow - -### Arguments - - -$ARGUMENTS - - -### Interpret Arguments - -- If `` looks like a PR number or URL, store it as `` -- If `` includes extra fix guidance, CI guidance, or scope constraints, store it as `` -- If empty, leave `` undefined and let `kompass_pr_load` resolve the default PR context -- Initialize `` as `0` - -### Load PR Context - -- Use `kompass_pr_load` as the source of truth for PR selection -- If `` is defined, call `kompass_pr_load` with `pr: ` -- Otherwise, call `kompass_pr_load` with no arguments -- Do not run separate git or GitHub commands just to discover the PR before calling `kompass_pr_load` -- Store the result as `` -- Store the PR head branch as `` from `.pr.headRefName` when it is available -- Run `git branch --show-current` and store the trimmed result as `` when it is available -- Run `git rev-parse HEAD` and store the trimmed result as `` when it is available -- Treat the loaded PR body, discussion, review history, and any attachments or linked artifacts returned by the loader as part of the source context -- Review attached images, screenshots, videos, PDFs, and other linked files whenever they can affect the requested fix, review outcome, reproduction steps, or acceptance criteria -- If any relevant attachment cannot be accessed, note that gap and continue only when the remaining PR context is still sufficient to proceed reliably - -- Store `` as `` -- Store `` as `` -- STOP if `` or `` is unavailable - -### Watch CI And Comments - -- Run `gh pr checks --watch` to wait for the latest PR checks to finish -- If the command exits successfully, store `` as `green` -- If there are no checks configured for the PR, store `` as `no checks` -- If the command reports failing, cancelled, timed out, missing, or inconclusive checks, store `` with that state and capture the failing check names, URLs, and failure output as `` -- Do not STOP only because CI failed; failed checks are actionable feedback for this loop - -### Reload PR Feedback - -Call `kompass_pr_load` with `` and store the refreshed result as ``. - -- Review ``, ``, and `` -- Identify open, unresolved, actionable reviewer feedback that has not already been answered by the author or superseded by later commits -- Combine actionable reviewer feedback and `` into `` -- Store the number of actionable reviewer items as `` -- Store the number of actionable CI failures as `` -- If `` and `` are both `0`, continue to `### Output` - -### Delegate Fix Pass - - -auto - -Fix all actionable PR review feedback and CI failures from the latest loop pass. -CI status: -CI failures: -Actionable work: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked, incomplete, reports failing validation, or reports that push or PR replies failed, STOP and report the fix blocker -- If `` reports that no changes were made for actionable work, STOP and report that manual follow-up is needed to avoid looping on unchanged CI or feedback -- Otherwise, increment `` by `1` and return to `### Load PR Context` - -### Output - -If stopped by a delegated fix blocker, display: -``` -PR loop blocked for # - -- CI status: -- Fix passes completed: -- Blocker: - -No additional steps are required. -``` - -When complete, display: -``` -PR loop complete for # - -- CI status: -- CI failures remaining: 0 -- Actionable feedback remaining: 0 -- Fix passes completed: - -No additional steps are required. -``` diff --git a/packages/opencode/.opencode/commands/pr/create.md b/packages/opencode/.opencode/commands/pr/create.md index 1764e4d..d392e71 100644 --- a/packages/opencode/.opencode/commands/pr/create.md +++ b/packages/opencode/.opencode/commands/pr/create.md @@ -5,16 +5,11 @@ agent: worker ## Goal -Create a pull request for the current branch, handling the entire workflow from change detection to PR submission. +Create a pull request for the current branch from its committed changes. ## Additional Context -Consider `` when analyzing changes and writing the PR description. -- Always include the `Ticket`, `Description`, and `Checklist` sections in that order. -- Use the literal `SKIPPED` when ticket mention was skipped. -- Keep the description focused on intent, not implementation details. -- Mark checklist validation items as completed if validation was performed. -- Uncommitted changes and being on the base branch block PR creation entirely. +Use `` when writing the PR. Include `Ticket`, `Description`, and `Checklist` sections in that order, and use `SKIPPED` when ticket mention is skipped. ## Workflow @@ -26,94 +21,54 @@ $ARGUMENTS ### Interpret Arguments -- **Branch name**: If `` looks like a branch reference (e.g., "main", "origin/develop"), store it as `` -- **Ticket directive**: If `` clearly requests ticket auto-creation, store `` as `auto` -- **Ticket reference**: If `` includes a ticket URL or clear ticket reference, store it as `` and store `` as `provided` -- **Skip ticket**: If `` clearly says to skip ticket mention, store `` as `skip` -- **Additional context**: If `` provides guidance (focus areas, related issues, notes), store it as `` -- **Empty**: If no `` provided, proceed with defaults +- Store a branch reference as `` +- Store ticket auto-creation as `` = `auto`, an explicit ticket reference as ``, or an explicit skip as `` = `skip` +- Store remaining guidance as `` -### Load & Analyze Changes +### Load And Analyze Changes + +#### Load Changes -#### Step 1: Load Changes - call `kompass_changes_load` -- If `` is defined: call `kompass_changes_load` with the `base` parameter set to `` -- Otherwise: call `kompass_changes_load` with no parameters -- Never pass `uncommitted: true` in this command +- If `` is defined, pass it as `base`; otherwise call the tool with no parameters +- Never pass `uncommitted: true` - Store the returned result as `` -- Use `` as the source of truth; no additional git analysis commands are needed -- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits that are ahead of the resolved base branch -- Do not infer scope from the branch names alone and do not describe work that exists only on the base branch - -#### Step 2: Analyze Files -- Review the paths, statuses, and diffs from `` only as file-level context for the commits in scope +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context - Identify the nature of changes (added, modified, deleted) -- Note lines added/removed per file - -#### Step 3: Group and Summarize -- For branch comparisons, build the summary from `.commits` first and use file diffs only to verify or refine what those commits changed - Group related changes into logical themes - Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base -- Store the loaded change result as `` -- Store the current branch from `` as `` when it is available -- Store the effective base branch as `` by preferring `` when it was provided, otherwise using the base branch implied by `.comparison` -- When `.comparison` is not `uncommitted`, describe the PR from the commits ahead of ``, not from the raw branch comparison string by itself - -### Check Blockers - -- If `.comparison` is "uncommitted": - - STOP immediately - - Report: "There are uncommitted changes. Please commit or stash them before creating a PR." - - List the changed files from `` - - Do NOT proceed further -- Treat this as a blocker only when `kompass_changes_load` returns `comparison: "uncommitted"` from the default call above; never force that mode during PR creation -- If `` equals ``: - - STOP immediately - - Report: "You are currently on the base branch (). Please checkout a feature branch before creating a PR." - - Suggest: `git checkout -b ` - - Do NOT proceed further -- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR +### Check PR Blockers -### Summarize Changes +- Store the current branch from `` as `` when available +- Store `` by preferring ``, otherwise use the base implied by `.comparison` +- If `.comparison` is `uncommitted`, STOP and report that changes must be committed or stashed +- If `` equals ``, STOP and report that PR creation requires a work branch +- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR -- Note the comparison mode, base branch, and current branch from the result -- If the comparison is not `uncommitted`, use only the commits in `.commits` as the branch-work scope -- Review commit messages when they are available to understand the delivery narrative -- Read the most relevant changed source files to understand the changes introduced by those commits -- Do not describe work that exists only on the base branch or that is outside the commits ahead of base -- Group related changes into themes for the final summary ### Resolve Ticket -- If `` is already `auto`, `provided`, or `skip`, do not ask a follow-up question -- Otherwise, if the `question` tool is available, this step is mandatory whenever the user did not already provide ticket handling through ``: - - Ask exactly one `question` before creating a ticket or PR - - This includes the common case where no ticket-related argument was provided at all - - Do not infer, assume, or default to any ticket mode while the `question` tool is available - - Never choose `skip` unless the user explicitly selects `Skip` or explicitly asks to skip ticket mention in `` - - Do not proceed to `Prepare Ticket Reference`, `Push Branch`, or `Create PR` until the answer is resolved - - Ask with: - - header `Provide Ticket` - - question `Provide Ticket` - - options: - - `Automatically Create` - create a fresh ticket from the summarized branch work - - `Skip` - mention `SKIPPED` in the PR body - - custom answers enabled so the user can paste a ticket URL or ticket reference directly -- Otherwise, if the `question` tool is not available: - - Do not ask a follow-up question - - Only in this case may the workflow continue without user input - - Store `` as `skip` - - Store `` as `SKIPPED` - - Continue without blocking -- Normalize the result into one of these paths: - - `Automatically Create` => `` = `auto` - - custom ticket URL or reference => `` = `provided` and store the answer as `` - - `Skip` => `` = `skip` +- Preserve an already defined `` or `` +- If `` is defined, store `` as `provided` +- Otherwise, if ticket handling was explicitly skipped, store `` as `skip` +- Otherwise, if automatic ticket creation was requested, store `` as `auto` +- Otherwise, when `question` is available, ask exactly one `Provide Ticket` question with `Automatically Create` and `Skip` options and custom answers enabled +- When `question` is unavailable, default to `skip` +- Normalize a custom ticket reference as `` with mode `provided`; never infer `skip` when the user can be asked ### Prepare Ticket Reference -When `` is `auto`, create the ticket before creating the PR: +When `` is `auto`: - Reuse the same change themes, rationale, and reviewer-facing validation goals from the current summary work - For branch comparisons, ensure every theme is supported by commits in `.commits`; use file diffs only as supporting context - Generate a concise title (max 70 chars) that reflects the delivered outcome @@ -127,82 +82,40 @@ When `` is `auto`, create the ticket before creating the PR: - Do not restate the full diff - Do not use execution-status notes such as `Validation not run in this session` as checklist items - If `kompass_changes_load` reports uncommitted work, make that clear in the ticket wording -- Use `kompass_ticket_sync` with `refUrl` unset -- Set `assignees` to `[@me]` so the created ticket is assigned to yourself as the author -- Store the created issue reference or URL as `` +- Use `kompass_ticket_sync` with `assignees: ["@me"]` and store the created issue URL as `` -Otherwise: -- If `` is `provided`, use the provided ticket value as `` -- If `` is `skip`, store the literal `SKIPPED` as `` +Otherwise, preserve the provided `` or store the literal `SKIPPED` for mode `skip`. ### Push Branch -Run `git push` and use its output as the source of truth. - -- Do not run extra git commands just to decide whether to push -- If the branch was pushed during this run, report `Push: yes` -- If `git push` reports no push was needed, report `Push: no` -- If `Push: yes`, also report `Pushed: → origin/` -- Store the push status line as `` -- When a push occurs, store the pushed ref line as `` +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error ### Create PR -Use `kompass_pr_sync` to create the pull request: -- This step is PR creation only -- Omit `review`, `replies`, `commentBody`, and `commitId` entirely unless you are intentionally updating or reviewing an existing PR instead of creating one -- Generate a concise title (max 70 chars) summarizing the change and store it as `` -- Generate a short description that briefly describes the intent and scope -- Pass `` as `head` when it is available so PR creation does not depend on local upstream inference -- Set `assignees` to `[@me]` so the created PR is assigned to yourself as the author -- Generate a compact checklist that mirrors the same human-facing structure used for the ticket summary: - - group delivered work into 2-4 functional or outcome-focused sections - - use concise section names instead of generic labels like `Changes` - - end with one `Validation` section containing reviewer-facing confirmation steps - - do not use execution-status notes as checklist items -- Render the PR body with this exact structure by setting `body` directly: - - `## Ticket`, followed by `` on the next line - - `## Description`, followed by the short description - - `## Checklist`, followed by the checklist items and any subsection headings -- Use `` as the base branch when it is defined -- Do NOT restate the full diff -- Do NOT rely on the branch diff alone to describe the PR; the description must match the commits ahead of `` -- Keep it compact and directional -- Store the returned URL as `` -- If `kompass_pr_sync` reports that a PR already exists for the branch, treat the result as an existing PR -- Track whether the branch was pushed during this run and report that status in the final response +- Generate a concise title of at most 70 characters as `` +- Generate a compact description focused on intent and scope +- Build 2-4 outcome-focused checklist sections followed by `Validation` +- Use `kompass_pr_sync` to create the PR with `` as `base`, `` as `head`, and `assignees: ["@me"]` +- Set `body` with `## Ticket`, `## Description`, and `## Checklist` in that order +- Omit review, replies, commentBody, and commitId +- Store the created or existing PR URL as `` and whether it already existed as `` ### Output -If PR creation stops because there is nothing to include, display: -``` -Nothing to include in a PR - -No additional steps are required. -``` - -When a new PR is created, display: +When complete, display: ``` Created PR: URL: -Branch: +Branch: -> Ticket: - - +Push: No additional steps are required. ``` -If a PR already exists for the branch, display: -``` -PR already exists - -URL: -Branch: -Ticket: - - - -No additional steps are required. -``` +If `` is true, replace the first line with `PR already exists`. diff --git a/packages/opencode/.opencode/commands/pr/create/inline.md b/packages/opencode/.opencode/commands/pr/create/inline.md new file mode 100644 index 0000000..f62f7eb --- /dev/null +++ b/packages/opencode/.opencode/commands/pr/create/inline.md @@ -0,0 +1,123 @@ +--- +description: Create a PR in the current session +agent: worker +subtask: false +--- + +## Goal + +Create a pull request for the current branch from its committed changes. Run in the invoking session while loading the final branch comparison as authoritative state. + +## Additional Context + +Use `` and relevant invoking-session context when writing the PR. Include `Ticket`, `Description`, and `Checklist` sections in that order, and use `SKIPPED` when ticket mention is skipped. + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- Store a branch reference as `` +- Store ticket auto-creation as `` = `auto`, an explicit ticket reference as ``, or an explicit skip as `` = `skip` +- Store remaining guidance as `` + +### Load And Analyze Changes + +- Retain the authoritative branch comparison load even though this command runs in the invoking session; do not infer the final base, commit scope, or diff from session memory +#### Load Changes + +- call `kompass_changes_load` +- If `` is defined, pass it as `base`; otherwise call the tool with no parameters +- Never pass `uncommitted: true` +- Store the returned result as `` +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base + +### Check PR Blockers + +- Store the current branch from `` as `` when available +- Store `` by preferring ``, otherwise use the base implied by `.comparison` +- If `.comparison` is `uncommitted`, STOP and report that changes must be committed or stashed +- If `` equals ``, STOP and report that PR creation requires a work branch +- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR + + +### Resolve Ticket + +- Preserve an already defined `` or `` +- If `` is defined, store `` as `provided` +- Otherwise, if ticket handling was explicitly skipped, store `` as `skip` +- Otherwise, if automatic ticket creation was requested, store `` as `auto` +- Otherwise, when `question` is available, ask exactly one `Provide Ticket` question with `Automatically Create` and `Skip` options and custom answers enabled +- When `question` is unavailable, default to `skip` +- Normalize a custom ticket reference as `` with mode `provided`; never infer `skip` when the user can be asked + +### Prepare Ticket Reference + +When `` is `auto`: +- Reuse the same change themes, rationale, and reviewer-facing validation goals from the current summary work +- For branch comparisons, ensure every theme is supported by commits in `.commits`; use file diffs only as supporting context +- Generate a concise title (max 70 chars) that reflects the delivered outcome +- Generate a `description` that briefly describes what was accomplished and why it matters +- Generate checklists with: + - 2-4 functional sections named after user-facing areas or outcomes, not generic labels like `Changes` + - concise, outcome-focused items under each section that describe what changed for a human reader + - one final `Validation` section with reviewer-facing confirmation steps that start with `Verify that...`, `Confirm that...`, or `Check that...` +- Keep section names and items concise, human-friendly, and function-oriented +- Merge tiny themes together instead of creating a section per file or implementation detail +- Do not restate the full diff +- Do not use execution-status notes such as `Validation not run in this session` as checklist items +- If `kompass_changes_load` reports uncommitted work, make that clear in the ticket wording +- Use `kompass_ticket_sync` with `assignees: ["@me"]` and store the created issue URL as `` + +Otherwise, preserve the provided `` or store the literal `SKIPPED` for mode `skip`. + +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error + +### Create PR + +- Generate a concise title of at most 70 characters as `` +- Generate a compact description focused on intent and scope +- Build 2-4 outcome-focused checklist sections followed by `Validation` +- Use `kompass_pr_sync` to create the PR with `` as `base`, `` as `head`, and `assignees: ["@me"]` +- Set `body` with `## Ticket`, `## Description`, and `## Checklist` in that order +- Omit review, replies, commentBody, and commitId +- Store the created or existing PR URL as `` and whether it already existed as `` + +### Output + +When complete, display: +``` +Created PR: + +URL: +Branch: -> +Ticket: +Push: + +No additional steps are required. +``` + +If `` is true, replace the first line with `PR already exists`. diff --git a/packages/opencode/.opencode/commands/pr/fix.md b/packages/opencode/.opencode/commands/pr/fix.md index 3b281b6..2001746 100644 --- a/packages/opencode/.opencode/commands/pr/fix.md +++ b/packages/opencode/.opencode/commands/pr/fix.md @@ -5,13 +5,11 @@ agent: worker ## Goal -Address feedback or CI failures on a pull request by making fixes and responding to review threads. +Address feedback or CI failures on a pull request, validate the fixes, push them, and respond. ## Additional Context -Use `` when prioritizing which review feedback or CI failure to address first and when deciding how much scope to take on in this pass. -- Default `/pr/fix` behavior is review-first: show the proposed fix, gather feedback, and loop until the user approves before committing, pushing, or replying on the PR. -- Treat `/pr/fix auto` as the explicit opt-in to skip the approval loop and proceed directly from passing validation to commit, push, and PR replies. +Use `` to prioritize feedback and scope. Default behavior requires review; `auto` explicitly skips approval. ## Workflow @@ -23,11 +21,9 @@ $ARGUMENTS ### Interpret Arguments -- If `` clearly requests automatic completion (for example `auto`), store `` as `auto` -- If `` looks like a PR number (e.g., "123") or URL, store it as `` -- If `` includes extra fix guidance, scope constraints, or priorities, store it as `` -- Otherwise, store `` as `review` -- If empty, leave `` undefined and let `kompass_pr_load` resolve the default PR context +- Store automatic completion requests as `` = `auto`; otherwise use `review` +- Store a PR number or URL as `` and remaining guidance as `` +- Leave `` undefined when absent ### Load PR Context @@ -36,145 +32,77 @@ $ARGUMENTS - Otherwise, call `kompass_pr_load` with no arguments - Do not run separate git or GitHub commands just to discover the PR before calling `kompass_pr_load` - Store the result as `` -- Store the PR head branch as `` from `.pr.headRefName` when it is available -- Run `git branch --show-current` and store the trimmed result as `` when it is available -- Run `git rev-parse HEAD` and store the trimmed result as `` when it is available - Treat the loaded PR body, discussion, review history, and any attachments or linked artifacts returned by the loader as part of the source context - Review attached images, screenshots, videos, PDFs, and other linked files whenever they can affect the requested fix, review outcome, reproduction steps, or acceptance criteria - If any relevant attachment cannot be accessed, note that gap and continue only when the remaining PR context is still sufficient to proceed reliably ### Align Local Branch -- If `` is unavailable, STOP and report that the PR head branch could not be determined -- Run `gh pr checkout ` before analyzing repository files or making code changes for this PR -- After checkout, store the active branch as `` -- If checkout fails or times out, STOP and report that the PR branch could not be checked out locally; do not retry checkout unless the user explicitly asks -- Do not inspect or modify local code for this PR until `` equals `` +- Store `` as `` +- STOP if `` is unavailable +- Run `gh pr checkout ` before inspecting or modifying code +- Store the active branch as `` and STOP unless it equals `` -### Load Changes +### Update Branch From Base -Call `kompass_changes_load` with `base: `, `head: `, and `depthHint: ` only when it is a positive integer. Store as ``. +- Store `` as `` and STOP if it is unavailable +- Run `git fetch origin `, then store `origin/` as `` +- Run `git merge-base --is-ancestor HEAD` to confirm whether the PR branch contains the latest base +- If the branch is behind, merge `` into `` without rebasing or force-pushing; resolve conflicts using repository context, complete the merge, push the merge commit, and store its hash as `` +- If the branch is current, store `` as `already up to date` +- STOP before making PR fixes if the fetch, merge, conflict resolution, or push cannot be completed safely -### Analyze Feedback +### Load PR Changes -Separate true course corrections from noise or already-resolved feedback: -1. Review `` for open, unresolved conversations -2. Check `` for state changes (CHANGES_REQUESTED, etc.) -3. Include any CI failures, logs, failing check names, or reproduction details provided in `` as actionable feedback -4. Use `` to understand the current PR diff before deciding what to adjust -5. Prioritize critical issues (bugs, security, broken contracts, failing required checks) -6. Identify which files need changes +Call `kompass_changes_load` with `base: `, `head: `, and positive `depthHint: ` when available. Store as ``. -Do not blindly follow every suggestion—some may lead you off course. +### Analyze And Implement Fixes -### Implement Fixes +- Treat unresolved review threads, review state changes, ``, and CI details in `` as candidate feedback +- Use `` to understand the current PR scope +- Separate true course corrections from noise, resolved feedback, and superseded feedback +- Fix critical correctness, security, contract, and required-CI issues first +- Follow existing patterns and make focused, minimal changes +- Store the modified-file count as `` -1. Fix critical navigation issues first -2. Follow existing code patterns and conventions -3. Use `` as the working branch for every local code read or edit in this command -4. Make focused, minimal changes -5. When maintaining your current heading despite a suggestion, be prepared to explain why -6. Store the modified-file count as `` +### Validate Fixes -### Validate Changes - -Run the most relevant available validation for the fixes: +- Run the most relevant available validation - Prefer project-native checks such as changed-area tests, linting, type checking, build verification, or other documented validation steps when they exist - If a category of validation is not available in the project, note it explicitly instead of inventing a command -- Confirm the fixes address the feedback -- Store the collected validation details as `` -- Store the overall validation outcome as `` with value `yes` or `no` - -### Review Fixes With User - -- If `` is `no`, STOP and report that validation is failing before any commit, push, or PR response happens -- If `` is `auto`, skip this review gate and continue directly to `### Commit And Push Updates` -- Otherwise, this review step is mandatory before any commit, push, or PR reply: - - Present the implemented fix summary, changed file count, and validation results - - If `` is greater than `0`, ask exactly one `question` with: - - header `Review Fixes` - - question `Do these PR fixes look good to commit, push, and respond on the PR?` - - options: - - `Go Ahead` - commit, push, and respond to the PR now - - `Revise` - update the fix based on user feedback before committing - - Keep custom answers enabled so the user can provide concrete feedback - - If `` is `0`, ask exactly one `question` with: - - header `Need Feedback` - - question `I did not make any changes for this PR feedback or CI failure. What should I revise or investigate next?` - - options: - - `Revise` - provide feedback for another pass - - `Stop Here` - stop without committing, pushing, or replying on the PR - - Keep custom answers enabled so the user can provide concrete feedback -- Normalize the answer into one of these paths: - - If `` is greater than `0`: - - `Go Ahead` => continue to `### Commit And Push Updates` - - `Revise` or custom feedback => store the feedback as ``, then continue to `### Apply Review Feedback` - - If `` is `0`: - - `Stop Here` => STOP and report that no changes were made, so nothing was committed, pushed, or sent to the PR - - `Revise` or custom feedback => store the feedback as ``, then continue to `### Apply Review Feedback` -- Repeat this review step until the user selects `Go Ahead` after a pass that produces changes, or explicitly selects `Stop Here` when no changes were made -- If the `question` tool is unavailable while `` is `review`, STOP and report that approval is required before commit, push, or PR replies - -### Apply Review Feedback - -- Use `` to refine the implementation without widening scope unless the feedback explicitly asks for it -- Return to `### Implement Fixes`, then rerun validation and the review step - -### Commit And Push Updates - -If validation passes: -1. Stage changes: `git add -A` -2. Create commit (use `commit` tool or `git commit`) -3. Push branch: `git push` -4. Store push status as `` with value `yes` or `no` - -### Respond to Threads - -Only after commit and push succeed, reply to addressed threads: -- Keep replies short and factual—clear signals, no chatter -- Use `kompass_pr_sync` to post comments or replies: +- Store details as `` and the outcome as `` (`yes` or `no`) +- STOP before commit, push, or replies when validation fails -``` -# General PR comment -kompass_pr_sync refUrl="" commentBody="" +### Review Fixes -# Reply to a specific review thread (use comment.id from threads.comments) -kompass_pr_sync refUrl="" replies=[{"inReplyTo": , "body": ""}] +- If `` is `auto`, skip this review gate and continue to commit and push +- Present the fix summary, changed-file count, and validation results +- If changes were made, ask one `Review Fixes` question with `Go Ahead` and `Revise`; apply custom revision feedback and repeat implementation and validation until approved +- If no changes were made, ask one `Need Feedback` question with `Revise` and `Stop Here` +- STOP if approval is required but `question` is unavailable -# Follow-up inline review comment on a specific line -kompass_pr_sync refUrl="" commitId="" review={"comments": [{"path": "", "line": , "body": ""}]} -``` +### Commit And Push Fixes -Confirm which feedback was addressed and which was intentionally not followed. -- Store the number of resolved threads as `` - -### Output - -When waiting for approval or revision feedback, display: -``` -Review fixes for PR # - -- Changes made: files modified -- Validation passing: -- Validation details: -``` +- If fixes produced uncommitted changes, stage the focused changes and create a conventional commit +- If the base update already created a merge commit and there are no additional changes, do not create an empty commit +- Push the branch, setting its upstream when necessary +- Store push status as `` +- STOP if commit or push fails -If the workflow stops after a no-change pass, display: -``` -No changes made for PR # +### Respond To Threads -- Changes made: 0 files modified -- Validation passing: -- Validation details: +- Only after commit and push succeed, use `kompass_pr_sync` to post short factual replies to addressed feedback +- Reply with `replies` keyed by the addressed comment IDs; use `commentBody` only for general CI feedback +- Store the number of addressed threads as `` -No additional steps are required. -``` +### Output -When fixes are complete, display exactly this final completion summary and stop. Do not continue with extra analysis, planning, or follow-up tasks unless the workflow is blocked or the user asked for more: +When fixes are complete, display: ``` PR fix complete for # - Changes made: files modified +- Base update: - Threads resolved: - Validation passing: - Validation details: diff --git a/packages/opencode/.opencode/commands/pr/fix/loop.md b/packages/opencode/.opencode/commands/pr/fix/loop.md new file mode 100644 index 0000000..18d3e56 --- /dev/null +++ b/packages/opencode/.opencode/commands/pr/fix/loop.md @@ -0,0 +1,133 @@ +--- +description: Watch PR CI and comments, repeatedly fixing both without approval prompts +agent: worker +--- + +## Goal + +Continuously watch a pull request, fix CI failures and new review feedback, push, reply, and repeat until clean. + +## Additional Context + +- Use `` to constrain feedback and CI handling +- This workflow is non-interactive and must not ask for approval +- Preserve the initial PR snapshot and use incremental review checkpoints on later passes + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- Store a PR number or URL as `` and remaining guidance as `` +- Initialize `` as `0` + +### Load Initial PR Context + +- Use `kompass_pr_load` as the source of truth for PR selection +- If `` is defined, call `kompass_pr_load` with `pr: ` +- Otherwise, call `kompass_pr_load` with no arguments +- Do not run separate git or GitHub commands just to discover the PR before calling `kompass_pr_load` +- Store the result as `` +- Treat the loaded PR body, discussion, review history, and any attachments or linked artifacts returned by the loader as part of the source context +- Review attached images, screenshots, videos, PDFs, and other linked files whenever they can affect the requested fix, review outcome, reproduction steps, or acceptance criteria +- If any relevant attachment cannot be accessed, note that gap and continue only when the remaining PR context is still sufficient to proceed reliably +- Store ``, ``, and `` from ``, ``, and `` +- Store the initial reviews, issue comments, and threads as `` +- STOP if any required value is unavailable + +### Align Branch With Base + +### Align Local Branch + +- Store `` as `` +- STOP if `` is unavailable +- Run `gh pr checkout ` before inspecting or modifying code +- Store the active branch as `` and STOP unless it equals `` + +### Update Branch From Base + +- Store `` as `` and STOP if it is unavailable +- Run `git fetch origin `, then store `origin/` as `` +- Run `git merge-base --is-ancestor HEAD` to confirm whether the PR branch contains the latest base +- If the branch is behind, merge `` into `` without rebasing or force-pushing; resolve conflicts using repository context, complete the merge, push the merge commit, and store its hash as `` +- If the branch is current, store `` as `already up to date` +- STOP before making PR fixes if the fetch, merge, conflict resolution, or push cannot be completed safely + +### Watch CI + +- Run `gh pr checks --watch` +- Store success or no configured checks as `` +- Capture failing, cancelled, timed out, missing, or inconclusive checks as `` without stopping + +### Load Incremental Feedback + +- Call `kompass_pr_load_review` with `pr: ` and `since: ` +- Store the result as `` and advance `` to `` +- Merge new reviews, issue comments, and whole changed threads into ``, deduplicating by stable IDs +- Combine open actionable feedback and `` into `` +- If there is no actionable feedback and no actionable CI failure, continue to `### Output` + +### Load PR Changes + +Call `kompass_changes_load` with `base: `, `head: `, and positive `depthHint: ` when available. Store as ``. + +### Analyze And Implement Fixes + +- Treat unresolved review threads, review state changes, ``, and CI details in `` as candidate feedback +- Use `` to understand the current PR scope +- Separate true course corrections from noise, resolved feedback, and superseded feedback +- Fix critical correctness, security, contract, and required-CI issues first +- Follow existing patterns and make focused, minimal changes +- Store the modified-file count as `` + +### Validate Fixes + +- Run the most relevant available validation +- Prefer project-native checks such as changed-area tests, linting, type checking, build verification, or other documented validation steps when they exist +- If a category of validation is not available in the project, note it explicitly instead of inventing a command +- Store details as `` and the outcome as `` (`yes` or `no`) +- STOP before commit, push, or replies when validation fails + +### Review Fixes + +- Continue without an approval prompt +- If actionable work produced no changes and `` is `already up to date`, STOP to avoid looping without progress + +### Commit And Push Fixes + +- If fixes produced uncommitted changes, stage the focused changes and create a conventional commit +- If the base update already created a merge commit and there are no additional changes, do not create an empty commit +- Push the branch, setting its upstream when necessary +- Store push status as `` +- STOP if commit or push fails + +### Respond To Threads + +- Only after commit and push succeed, use `kompass_pr_sync` to post short factual replies to addressed feedback +- Reply with `replies` keyed by the addressed comment IDs; use `commentBody` only for general CI feedback +- Store the number of addressed threads as `` + +### Continue Loop + +- Increment `` and return to `### Align Branch With Base` +- Do not call `kompass_pr_load` again during this loop + +### Output + +When complete, display: +``` +PR loop complete for # + +- CI status: +- Base update: +- CI failures remaining: 0 +- Actionable feedback remaining: 0 +- Fix passes completed: + +No additional steps are required. +``` diff --git a/packages/opencode/.opencode/commands/pr/review.md b/packages/opencode/.opencode/commands/pr/review.md index be3ec43..d339ac0 100644 --- a/packages/opencode/.opencode/commands/pr/review.md +++ b/packages/opencode/.opencode/commands/pr/review.md @@ -32,9 +32,6 @@ $ARGUMENTS - Otherwise, call `kompass_pr_load` with no arguments - Do not run separate git or GitHub commands just to discover the PR before calling `kompass_pr_load` - Store the result as `` -- Store the PR head branch as `` from `.pr.headRefName` when it is available -- Run `git branch --show-current` and store the trimmed result as `` when it is available -- Run `git rev-parse HEAD` and store the trimmed result as `` when it is available - Treat the loaded PR body, discussion, review history, and any attachments or linked artifacts returned by the loader as part of the source context - Review attached images, screenshots, videos, PDFs, and other linked files whenever they can affect the requested fix, review outcome, reproduction steps, or acceptance criteria - If any relevant attachment cannot be accessed, note that gap and continue only when the remaining PR context is still sufficient to proceed reliably diff --git a/packages/opencode/.opencode/commands/ship.md b/packages/opencode/.opencode/commands/ship.md index dee2dd6..9eec3b8 100644 --- a/packages/opencode/.opencode/commands/ship.md +++ b/packages/opencode/.opencode/commands/ship.md @@ -1,15 +1,15 @@ --- description: Ship branch work through commit and PR creation -agent: navigator +agent: worker --- ## Goal -Ship the current work by dispatching branch creation, commit creation, and PR creation in the current session. +Ship the current work through branch creation, commit creation, and PR creation in one workflow. ## Additional Context -Use `` to steer delegated branch naming. Use `` to refine the delegated commit and PR summaries. Pass `` through to PR creation when it was provided. +Use `` for branch naming and `` for commit and PR summaries. Reuse loaded state within this command instead of reloading it between phases. ## Workflow @@ -22,61 +22,160 @@ $ARGUMENTS ### Interpret Arguments - Initialize ``, ``, and `` as empty -- If `` is empty, proceed with defaults -- If the trimmed `` is only a branch reference (for example `main` or `origin/develop`), store it as `` and leave the context fields empty -- Otherwise, store `` as both `` and `` - -### Delegate Branch Creation - - -Branch naming guidance: - - -- Store the delegated result as `` -- If `` says there was nothing to branch from, continue on the current branch -- If `` says branching was skipped because the current branch already looks like a work branch, continue on the current branch -- If `` is blocked or incomplete, STOP and report the branch blocker -- Otherwise, continue with the created branch - -### Delegate Commit - - -Additional context: - - -- Store the delegated result as `` -- If `` says there was nothing to commit, continue without creating a new commit -- If `` is blocked or incomplete, STOP and report the commit blocker -- Otherwise, continue with the created commit - -### Delegate PR Creation - - -Base branch: -Additional context: - +- If `` is only a branch reference, store it as `` +- Otherwise, store it as both `` and `` + +### Load Uncommitted Changes Once + +#### Load Changes + +- call `kompass_changes_load` +- pass `uncommitted: true` to get uncommitted changes only +- Store the returned result as `` +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base +- Reuse `` for branch naming and commit creation + +### Check Branch + +- Store the current branch from `` as `` when available +- If `` contains no files, store `` as `nothing to branch from` and skip branch creation +- If `` starts with a conventional work category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, store `` as `kept ` and skip branch creation + +### Create Branch + +When branch creation was not skipped: +- Choose a conventional category such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` from the change themes and `` +- Generate a concise kebab-case slug from the same context +- Create and checkout `/` with `git checkout -b` +- If that name exists, retry once with a short numeric suffix +- Store the checked-out branch as `` and `` as `created ` +- If branch creation fails, STOP and report the blocker + +### Create Commit + +- If `` contains files, create the commit from the already loaded ``: +### Message Format +- Prefer this format unless the change is tiny: + +```text +type: summary + +- change +- change +- change +``` -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the PR blocker -- If `` says there is nothing to include in a PR, STOP and report that there is nothing to ship -- Otherwise, continue with the created or existing PR +- Keep the subject concise and under 72 characters +- Use conventional commit format: "feat:", "fix:", "refactor:", "docs:", etc. +- For non-trivial changes, add 2-5 short bullets with the main grouped changes +- Use a one-line commit only when a body would add no value + +### Commit Phase +1. Use the loaded change data as the source of truth for what will be committed +2. Stage changes with `git add` (use `-A` for all, or specific files) +3. Generate the commit message and store it as `` +4. Preserve the blank line between subject and bullets when present +5. Create the commit with `` +6. Store the created commit hash as `` +7. Only run `git status` if the commit fails and needs diagnosis +- Store `` as the created hash and message +- If `` contains no files, store `` as `no new commit` + +### Load Branch Changes + +- Call `kompass_changes_load` with `base: ` when defined, otherwise with no arguments +- Store the new result as ``; this post-commit comparison is required for PR creation + +### Check PR Blockers + +- Store the current branch from `` as `` when available +- Store `` by preferring ``, otherwise use the base implied by `.comparison` +- If `.comparison` is `uncommitted`, STOP and report that changes must be committed or stashed +- If `` equals ``, STOP and report that PR creation requires a work branch +- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR + +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base + +### Resolve Ticket + +- Preserve an already defined `` or `` +- If `` is defined, store `` as `provided` +- Otherwise, if ticket handling was explicitly skipped, store `` as `skip` +- Otherwise, if automatic ticket creation was requested, store `` as `auto` +- Otherwise, when `question` is available, ask exactly one `Provide Ticket` question with `Automatically Create` and `Skip` options and custom answers enabled +- When `question` is unavailable, default to `skip` +- Normalize a custom ticket reference as `` with mode `provided`; never infer `skip` when the user can be asked + +### Prepare Ticket Reference + +When `` is `auto`: +- Reuse the same change themes, rationale, and reviewer-facing validation goals from the current summary work +- For branch comparisons, ensure every theme is supported by commits in `.commits`; use file diffs only as supporting context +- Generate a concise title (max 70 chars) that reflects the delivered outcome +- Generate a `description` that briefly describes what was accomplished and why it matters +- Generate checklists with: + - 2-4 functional sections named after user-facing areas or outcomes, not generic labels like `Changes` + - concise, outcome-focused items under each section that describe what changed for a human reader + - one final `Validation` section with reviewer-facing confirmation steps that start with `Verify that...`, `Confirm that...`, or `Check that...` +- Keep section names and items concise, human-friendly, and function-oriented +- Merge tiny themes together instead of creating a section per file or implementation detail +- Do not restate the full diff +- Do not use execution-status notes such as `Validation not run in this session` as checklist items +- If `kompass_changes_load` reports uncommitted work, make that clear in the ticket wording +- Use `kompass_ticket_sync` with `assignees: ["@me"]` and store the created issue URL as `` + +Otherwise, preserve the provided `` or store the literal `SKIPPED` for mode `skip`. + +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error + +### Create PR + +- Generate a concise title of at most 70 characters as `` +- Generate a compact description focused on intent and scope +- Build 2-4 outcome-focused checklist sections followed by `Validation` +- Use `kompass_pr_sync` to create the PR with `` as `base`, `` as `head`, and `assignees: ["@me"]` +- Set `body` with `## Ticket`, `## Description`, and `## Checklist` in that order +- Omit review, replies, commentBody, and commitId +- Store the created or existing PR URL as `` and whether it already existed as `` ### Output -If there is nothing to ship, display: -``` -Nothing to ship - -No additional steps are required. -``` - When complete, display: ``` Ship flow complete Branch: Commit: -PR: +PR: No additional steps are required. ``` diff --git a/packages/opencode/.opencode/commands/ship/inline.md b/packages/opencode/.opencode/commands/ship/inline.md new file mode 100644 index 0000000..330b584 --- /dev/null +++ b/packages/opencode/.opencode/commands/ship/inline.md @@ -0,0 +1,165 @@ +--- +description: Ship branch work using context from the current session +agent: worker +subtask: false +--- + +## Goal + +Ship the current work through branch creation, commit creation, and PR creation in one workflow. Reuse the invoking session's change context for the initial branch and commit phases. + +## Additional Context + +Use `` for branch naming and `` for commit and PR summaries. Reuse loaded state within this command instead of reloading it between phases. + +## Workflow + +### Arguments + + +$ARGUMENTS + + +### Interpret Arguments + +- Initialize ``, ``, and `` as empty +- If `` is only a branch reference, store it as `` +- Otherwise, store it as both `` and `` + +### Load Uncommitted Changes Once + +- Reuse the current session's known uncommitted changes as `` for branch naming and commit creation +- Do not call `kompass_changes_load` before the branch and commit phases; inspect the worktree only when the session context does not identify which files remain uncommitted + +### Check Branch + +- Store the current branch from `` as `` when available +- If `` contains no files, store `` as `nothing to branch from` and skip branch creation +- If `` starts with a conventional work category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, store `` as `kept ` and skip branch creation + +### Create Branch + +When branch creation was not skipped: +- Choose a conventional category such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` from the change themes and `` +- Generate a concise kebab-case slug from the same context +- Create and checkout `/` with `git checkout -b` +- If that name exists, retry once with a short numeric suffix +- Store the checked-out branch as `` and `` as `created ` +- If branch creation fails, STOP and report the blocker + +### Create Commit + +- If `` contains files, create the commit from the already loaded ``: +### Message Format +- Prefer this format unless the change is tiny: + +```text +type: summary + +- change +- change +- change +``` + +- Keep the subject concise and under 72 characters +- Use conventional commit format: "feat:", "fix:", "refactor:", "docs:", etc. +- For non-trivial changes, add 2-5 short bullets with the main grouped changes +- Use a one-line commit only when a body would add no value + +### Commit Phase +1. Use the loaded change data as the source of truth for what will be committed +2. Stage changes with `git add` (use `-A` for all, or specific files) +3. Generate the commit message and store it as `` +4. Preserve the blank line between subject and bullets when present +5. Create the commit with `` +6. Store the created commit hash as `` +7. Only run `git status` if the commit fails and needs diagnosis +- Store `` as the created hash and message +- If `` contains no files, store `` as `no new commit` + +### Load Branch Changes + +- Call `kompass_changes_load` with `base: ` when defined, otherwise with no arguments +- Store the new result as ``; this post-commit comparison is required for PR creation + +### Check PR Blockers + +- Store the current branch from `` as `` when available +- Store `` by preferring ``, otherwise use the base implied by `.comparison` +- If `.comparison` is `uncommitted`, STOP and report that changes must be committed or stashed +- If `` equals ``, STOP and report that PR creation requires a work branch +- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR + +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base + +### Resolve Ticket + +- Preserve an already defined `` or `` +- If `` is defined, store `` as `provided` +- Otherwise, if ticket handling was explicitly skipped, store `` as `skip` +- Otherwise, if automatic ticket creation was requested, store `` as `auto` +- Otherwise, when `question` is available, ask exactly one `Provide Ticket` question with `Automatically Create` and `Skip` options and custom answers enabled +- When `question` is unavailable, default to `skip` +- Normalize a custom ticket reference as `` with mode `provided`; never infer `skip` when the user can be asked + +### Prepare Ticket Reference + +When `` is `auto`: +- Reuse the same change themes, rationale, and reviewer-facing validation goals from the current summary work +- For branch comparisons, ensure every theme is supported by commits in `.commits`; use file diffs only as supporting context +- Generate a concise title (max 70 chars) that reflects the delivered outcome +- Generate a `description` that briefly describes what was accomplished and why it matters +- Generate checklists with: + - 2-4 functional sections named after user-facing areas or outcomes, not generic labels like `Changes` + - concise, outcome-focused items under each section that describe what changed for a human reader + - one final `Validation` section with reviewer-facing confirmation steps that start with `Verify that...`, `Confirm that...`, or `Check that...` +- Keep section names and items concise, human-friendly, and function-oriented +- Merge tiny themes together instead of creating a section per file or implementation detail +- Do not restate the full diff +- Do not use execution-status notes such as `Validation not run in this session` as checklist items +- If `kompass_changes_load` reports uncommitted work, make that clear in the ticket wording +- Use `kompass_ticket_sync` with `assignees: ["@me"]` and store the created issue URL as `` + +Otherwise, preserve the provided `` or store the literal `SKIPPED` for mode `skip`. + +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error + +### Create PR + +- Generate a concise title of at most 70 characters as `` +- Generate a compact description focused on intent and scope +- Build 2-4 outcome-focused checklist sections followed by `Validation` +- Use `kompass_pr_sync` to create the PR with `` as `base`, `` as `head`, and `assignees: ["@me"]` +- Set `body` with `## Ticket`, `## Description`, and `## Checklist` in that order +- Omit review, replies, commentBody, and commitId +- Store the created or existing PR URL as `` and whether it already existed as `` + +### Output + +When complete, display: +``` +Ship flow complete + +Branch: +Commit: +PR: + +No additional steps are required. +``` diff --git a/packages/opencode/.opencode/commands/ticket/create.md b/packages/opencode/.opencode/commands/ticket/create.md index b663ffd..8522773 100644 --- a/packages/opencode/.opencode/commands/ticket/create.md +++ b/packages/opencode/.opencode/commands/ticket/create.md @@ -27,41 +27,32 @@ $ARGUMENTS ### Load & Analyze Changes -#### Step 1: Load Changes +#### Load Changes + - call `kompass_changes_load` - If `` is defined: call `kompass_changes_load` with the `base` parameter set to `` - Otherwise: call `kompass_changes_load` with no parameters - Store the returned result as `` -- Use `` as the source of truth; no additional git analysis commands are needed -- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits that are ahead of the resolved base branch -- Do not infer scope from the branch names alone and do not describe work that exists only on the base branch - -#### Step 2: Analyze Files -- Review the paths, statuses, and diffs from `` only as file-level context for the commits in scope +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context - Identify the nature of changes (added, modified, deleted) -- Note lines added/removed per file - -#### Step 3: Group and Summarize -- For branch comparisons, build the summary from `.commits` first and use file diffs only to verify or refine what those commits changed - Group related changes into logical themes - Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base -- Store the loaded change result as `` - When `.comparison` is not `uncommitted`, describe the ticket from the commits ahead of the resolved base branch, not from branch names alone ### Check Blockers - If `` contains no files, STOP and report that there is no work to summarize in a ticket -### Summarize Changes - -- Note the comparison mode, base branch, and current branch from the result -- If the comparison is not `uncommitted`, use only the commits in `.commits` as the branch-work scope -- Review commit messages when they are available to understand the delivery narrative -- Read the most relevant changed source files to understand the changes introduced by those commits -- Do not describe work that exists only on the base branch or that is outside the commits ahead of base -- Group related changes into themes for the final summary - ### Create Ticket Use `kompass_ticket_sync` with `refUrl` unset to create the ticket: diff --git a/packages/opencode/.opencode/commands/ticket/dev.md b/packages/opencode/.opencode/commands/ticket/dev.md index 41eb77f..c3bb9fc 100644 --- a/packages/opencode/.opencode/commands/ticket/dev.md +++ b/packages/opencode/.opencode/commands/ticket/dev.md @@ -1,15 +1,15 @@ --- description: Implement a ticket and create a PR -agent: navigator +agent: worker --- ## Goal -Implement a ticket by orchestrating development, branching, commit-and-push, and PR creation. +Implement a ticket, create a branch and commit, push it, and create a pull request in one workflow. ## Additional Context -Use `` to refine scope, sequencing, and tradeoffs across the delegated `/dev`, `/branch`, `/commit-and-push`, and `/pr/create` steps. +Use `` to refine scope and delivery. Reuse loaded change state across adjacent phases. ## Workflow @@ -21,9 +21,8 @@ $ARGUMENTS ### Interpret Arguments -- Interpret `` as `` (ticket reference, URL, file path, or raw request) -- If `` includes extra delivery guidance, scope constraints, or notes, store them as `` -- If `` is empty, derive it from the conversation before continuing +- Store the ticket reference, URL, file, or request as `` +- Store extra delivery guidance as `` ### Load Ticket Context @@ -32,9 +31,10 @@ $ARGUMENTS - Treat the loaded ticket body, discussion, and any attachments or linked artifacts returned by the loader as part of the source context - Review attached images, PDFs, and other linked files whenever they can affect requirements, acceptance criteria, reproduction steps, design direction, or the requested answer - If any relevant attachment cannot be accessed, note that gap and continue only when the remaining ticket context is still sufficient to proceed reliably -- Store the ticket reference for PR creation as `` by preferring the original reference, otherwise using the canonical ticket URL from `` when one is available, otherwise using `SKIPPED` -- Store a concise ticket summary as `` -- If `` cannot be loaded, STOP and report that the ticket source is missing or invalid +- Store a concise `` and canonical `` when available +- STOP if ticket context cannot be loaded + +### Implement Ticket ### Development Flow Navigation Guide @@ -43,62 +43,162 @@ $ARGUMENTS - Prefer the smallest course correction that fully reaches the destination - Validate the path with targeted checks before handing off to PR creation - Surface any detours or follow-up destinations that should stay off the current route +- Implement the smallest complete change for `` and `` +- Run the most relevant available validation +- Prefer project-native checks such as changed-area tests, linting, type checking, build verification, or other documented validation steps when they exist +- If a category of validation is not available in the project, note it explicitly instead of inventing a command +- Store results as `` and STOP if required validation fails + +### Load Uncommitted Changes Once + +#### Load Changes + +- call `kompass_changes_load` +- pass `uncommitted: true` to get uncommitted changes only +- Store the returned result as `` +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base +- Set `` to `` + +### Check Branch + +- Store the current branch from `` as `` when available +- If `` contains no files, store `` as `nothing to branch from` and skip branch creation +- If `` starts with a conventional work category such as `feature/`, `fix/`, `refactor/`, `docs/`, `test/`, `chore/`, `feat/`, `bugfix/`, `hotfix/`, `perf/`, `build/`, or `ci/`, store `` as `kept ` and skip branch creation + +### Create Branch + +When branch creation was not skipped: +- Choose a conventional category such as `feature`, `fix`, `refactor`, `docs`, `test`, or `chore` from the change themes and `` +- Generate a concise kebab-case slug from the same context +- Create and checkout `/` with `git checkout -b` +- If that name exists, retry once with a short numeric suffix +- Store the checked-out branch as `` and `` as `created ` +- If branch creation fails, STOP and report the blocker + +### Commit Changes + +- If `` contains files: +### Message Format +- Prefer this format unless the change is tiny: + +```text +type: summary + +- change +- change +- change +``` -### Delegate Implementation - - -Ticket reference: -Ticket context: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the implementation blocker - -### Delegate Branch Creation - - -Branch naming guidance: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the branch blocker -- If `` says branching was skipped because the current branch already looks like a work branch, continue - -### Delegate Commit And Push - - -Ticket reference: -Ticket summary: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the commit or push blocker -- If `` says there was nothing to commit or push, continue to PR creation so already-committed branch work can still be shipped - -### Delegate PR Creation - - -Ticket reference: -Ticket context: -Additional context: - - -- Store the delegated result as `` -- If `` is blocked or incomplete, STOP and report the PR blocker -- Otherwise, continue and store the resulting PR URL as `` +- Keep the subject concise and under 72 characters +- Use conventional commit format: "feat:", "fix:", "refactor:", "docs:", etc. +- For non-trivial changes, add 2-5 short bullets with the main grouped changes +- Use a one-line commit only when a body would add no value + +### Commit Phase +1. Use the loaded change data as the source of truth for what will be committed +2. Stage changes with `git add` (use `-A` for all, or specific files) +3. Generate the commit message and store it as `` +4. Preserve the blank line between subject and bullets when present +5. Create the commit with `` +6. Store the created commit hash as `` +7. Only run `git status` if the commit fails and needs diagnosis +- Otherwise, continue so previously committed ticket work can still be shipped + +### Load Branch Changes + +- Call `kompass_changes_load` with no parameters and store the result as `` +- Store `` as `provided` when `` exists, otherwise `skip` + +### Check PR Blockers + +- Store the current branch from `` as `` when available +- Store `` by preferring ``, otherwise use the base implied by `.comparison` +- If `.comparison` is `uncommitted`, STOP and report that changes must be committed or stashed +- If `` equals ``, STOP and report that PR creation requires a work branch +- If `` contains no files and no commits, STOP and report that there is nothing to include in a PR + +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base + +### Resolve Ticket + +- Preserve an already defined `` or `` +- If `` is defined, store `` as `provided` +- Otherwise, if ticket handling was explicitly skipped, store `` as `skip` +- Otherwise, if automatic ticket creation was requested, store `` as `auto` +- Otherwise, when `question` is available, ask exactly one `Provide Ticket` question with `Automatically Create` and `Skip` options and custom answers enabled +- When `question` is unavailable, default to `skip` +- Normalize a custom ticket reference as `` with mode `provided`; never infer `skip` when the user can be asked + +### Prepare Ticket Reference + +When `` is `auto`: +- Reuse the same change themes, rationale, and reviewer-facing validation goals from the current summary work +- For branch comparisons, ensure every theme is supported by commits in `.commits`; use file diffs only as supporting context +- Generate a concise title (max 70 chars) that reflects the delivered outcome +- Generate a `description` that briefly describes what was accomplished and why it matters +- Generate checklists with: + - 2-4 functional sections named after user-facing areas or outcomes, not generic labels like `Changes` + - concise, outcome-focused items under each section that describe what changed for a human reader + - one final `Validation` section with reviewer-facing confirmation steps that start with `Verify that...`, `Confirm that...`, or `Check that...` +- Keep section names and items concise, human-friendly, and function-oriented +- Merge tiny themes together instead of creating a section per file or implementation detail +- Do not restate the full diff +- Do not use execution-status notes such as `Validation not run in this session` as checklist items +- If `kompass_changes_load` reports uncommitted work, make that clear in the ticket wording +- Use `kompass_ticket_sync` with `assignees: ["@me"]` and store the created issue URL as `` + +Otherwise, preserve the provided `` or store the literal `SKIPPED` for mode `skip`. + +### Push Branch + +- If `` is not defined, run `git branch --show-current` and store the trimmed result as `` +- Run `git push` and use its output as the source of truth +- If the current branch has no upstream, retry with `git push -u origin ` +- Store whether a push occurred as `` and the successful destination as `` +- If push fails, STOP and report the push error + +### Create PR + +- Generate a concise title of at most 70 characters as `` +- Generate a compact description focused on intent and scope +- Build 2-4 outcome-focused checklist sections followed by `Validation` +- Use `kompass_pr_sync` to create the PR with `` as `base`, `` as `head`, and `assignees: ["@me"]` +- Set `body` with `## Ticket`, `## Description`, and `## Checklist` in that order +- Omit review, replies, commentBody, and commitId +- Store the created or existing PR URL as `` and whether it already existed as `` ### Output -When the ticket work is complete, display: +When complete, display: ``` Implemented ticket: -Implementation: -Branch: -Commit and push: +Validation: +Branch: +Commit: PR: No additional steps are required. diff --git a/packages/opencode/.opencode/commands/todo.md b/packages/opencode/.opencode/commands/todo.md index b315678..c010b30 100644 --- a/packages/opencode/.opencode/commands/todo.md +++ b/packages/opencode/.opencode/commands/todo.md @@ -1,19 +1,17 @@ --- description: Work through a todo file task by task -agent: navigator +agent: worker --- ## Goal -Work through a todo file one pending item at a time by planning, getting approval, implementing, committing, and marking completed tasks. +Work through a todo file one pending item at a time by planning, getting approval, implementing, committing, and marking it complete. ## Additional Context - Keep the loop focused on one checklist item at a time -- Do not merge separate todo items unless the file explicitly frames them as one task -- If implementation reveals scope that materially changes the approved plan, pause and re-plan before marking the task complete -- Use `` to prioritize tradeoffs, constraints, or validation expectations during planning and implementation -- Delegate planner and worker steps through literal `` blocks and use the delegated results as the source of truth for planning, implementation, and commit steps. +- Pause and revise the plan when implementation materially changes approved scope +- Use `` for constraints and validation expectations ## Workflow @@ -25,112 +23,87 @@ $ARGUMENTS ### Interpret Arguments -- If `` contains a file reference prefixed with `@`, store that value as `` -- If `` includes execution guidance, scope constraints, or notes beyond the file reference, store them as `` -- If no file reference is provided, default `` to `@TODO.md` - -### Load Todo Context - -- Prefer the file content already provided by the user's file mention or attachment for `` -- Only load `` yourself if that content is not already available in context -- If the file cannot be loaded, STOP and report that `` could not be found or read -- Treat markdown checklist items with unchecked boxes as pending tasks, preserving file order -- Ignore headings, checked items, and non-checklist lines when selecting work -- If there are no pending tasks, STOP and report that `` has no remaining work -- Store the first pending task text as `` -- Store any nearby checklist context that materially clarifies `` as `` - -### Check Blockers - -- If the first pending item is unclear, let the planner identify missing details or questions when it can do so safely from `` and `` -- Only STOP here when the task is too ambiguous to plan at all and the workflow cannot produce a meaningful plan or targeted clarification request - -### Delegate Planning - - -Task: -Task context: -Additional context: - - -- Store the delegated result as `` -- If the planner is blocked or cannot produce a usable plan, store the blocker as ``, then STOP and report that planning blocker - -### Review Plan With User - -- Show `` and `` to the user before any implementation work starts -- Ask one `question` with: - - header `Plan Review` - - question `Does this plan look good to implement?` - - options: - - `Implement` - proceed with the current plan - - `Revise` - update the plan based on feedback -- custom answers enabled so the user can provide specific plan changes -- If the user requests changes, store that feedback as `` -- Only run the revised planning block below when the user requests changes -- If the user approves the current plan, skip the revised planning block and continue to implementation - - -Task: -Task context: -Current plan: -Plan feedback: -Additional context: - - -- Store the revised delegated result as `` and continue the review loop -- If the revised planner result is blocked or unusable, store that blocker as ``, then STOP and report it before continuing the review loop -- Repeat this review step until the user approves or stops -- If the user does not approve implementation, store `plan approval not granted` as ``, then STOP without changing `` - -### Delegate Implementation - - -Plan: -Task: -Task context: -Additional context: - - -- Store the delegated result as `` -- If `` is incomplete, blocked, or fails validation, store the issue as ``, then STOP and report it without marking the task complete - -### Delegate Commit - - -Task: -Additional context: - - -- Store the delegated result as `` -- If `` does not succeed, store the commit status as ``, then STOP and report it without marking the task complete +- Store an `@`-prefixed file as `` and remaining guidance as `` +- Default `` to `@TODO.md` -### Mark Complete And Loop +### Load Next Todo -- After the implementation and commit both succeed, update the matching checklist item in `` from unchecked to checked while preserving the rest of the file -- Save the updated todo file -- Return to `### Load Todo Context` and repeat the workflow for the next pending task +- Prefer attached content, otherwise load `` +- Select the first unchecked markdown checklist item as `` and preserve nearby context as `` +- STOP with completion when no pending tasks remain -### Output +### Plan Task -When presenting a task plan for approval, display: -``` -Todo: -Task: +- Inspect relevant repository context and shape a scoped implementation plan from ``, ``, and `` +- Store it as `` +- Show the plan and ask one `Plan Review` question with `Implement` and `Revise`, with custom answers enabled +- Apply revision feedback and repeat until approved; STOP without editing when approval is not granted -Plan: - -``` +### Implement Task -If the workflow pauses before marking the task complete, display: -``` -Todo paused: -Task: -Reason: +### Development Flow Navigation Guide -No additional steps are required. +- Orient yourself using the normalized request context before editing +- Survey the codebase before plotting the implementation +- Prefer the smallest course correction that fully reaches the destination +- Validate the path with targeted checks before handing off to PR creation +- Surface any detours or follow-up destinations that should stay off the current route +- Implement the approved `` +- Run relevant validation and STOP without marking complete if implementation or validation is incomplete + +### Load And Commit Task Changes + +#### Load Changes + +- call `kompass_changes_load` +- pass `uncommitted: true` to get uncommitted changes only +- Store the returned result as `` +- If `.deferredDiffs` is present, inspect the needed deferred diffs directly one file at a time using the returned comparison and changed paths +#### Analyze And Summarize Changes + +- Use `` as the source of truth; do not run additional git commands to rediscover its comparison +- Note the comparison mode, base branch, and current branch from `` +- When `.comparison` is not `uncommitted`, treat `.commits` as the authoritative scope of work: only summarize commits ahead of the resolved base branch +- Review commit messages when available to understand the delivery narrative +- Review paths, statuses, line counts, and diffs from `` as file-level context for the commits in scope +- Read only the most relevant changed source files when the diff does not provide enough context +- Identify the nature of changes (added, modified, deleted) +- Group related changes into logical themes +- Summarize the "what" and "why" (not the "how") +- Do not infer scope from branch names or describe work that exists only on the base branch or outside the commits ahead of base +- STOP without marking complete if `` contains no files +### Message Format +- Prefer this format unless the change is tiny: + +```text +type: summary + +- change +- change +- change ``` +- Keep the subject concise and under 72 characters +- Use conventional commit format: "feat:", "fix:", "refactor:", "docs:", etc. +- For non-trivial changes, add 2-5 short bullets with the main grouped changes +- Use a one-line commit only when a body would add no value + +### Commit Phase +1. Use the loaded change data as the source of truth for what will be committed +2. Stage changes with `git add` (use `-A` for all, or specific files) +3. Generate the commit message and store it as `` +4. Preserve the blank line between subject and bullets when present +5. Create the commit with `` +6. Store the created commit hash as `` +7. Only run `git status` if the commit fails and needs diagnosis + +### Mark Complete And Loop + +- After commit succeeds, change the matching checklist item to checked while preserving the file +- Return to `### Load Next Todo` + +### Output + When all pending tasks are complete, display: ``` Todo complete: diff --git a/packages/opencode/.opencode/kompass.jsonc b/packages/opencode/.opencode/kompass.jsonc index d3b5250..fcd25f6 100644 --- a/packages/opencode/.opencode/kompass.jsonc +++ b/packages/opencode/.opencode/kompass.jsonc @@ -13,19 +13,25 @@ "branch": { "enabled": true }, + "branch/inline": { + "enabled": true + }, "commit": { "enabled": true }, + "commit/inline": { + "enabled": true + }, "commit-and-push": { "enabled": true }, - "dev": { + "commit-and-push/inline": { "enabled": true }, - "learn": { + "dev": { "enabled": true }, - "loop/pr/fix": { + "learn": { "enabled": true }, "merge": { @@ -34,9 +40,15 @@ "pr/create": { "enabled": true }, + "pr/create/inline": { + "enabled": true + }, "pr/fix": { "enabled": true }, + "pr/fix/loop": { + "enabled": true + }, "pr/review": { "enabled": true }, @@ -52,6 +64,9 @@ "ship": { "enabled": true }, + "ship/inline": { + "enabled": true + }, "rmslop": { "enabled": true }, @@ -78,9 +93,6 @@ "worker": { "enabled": true }, - "navigator": { - "enabled": true - }, "planner": { "enabled": true }, @@ -92,10 +104,10 @@ "changes_load": { "enabled": true }, - "command_expansion": { + "pr_load": { "enabled": true }, - "pr_load": { + "pr_load_review": { "enabled": true }, "pr_sync": { diff --git a/packages/opencode/README.md b/packages/opencode/README.md index fa25895..57782ef 100644 --- a/packages/opencode/README.md +++ b/packages/opencode/README.md @@ -18,9 +18,9 @@ Kompass keeps AI coding agents on course with token-efficient, composable workfl ## Bundled Surface -- Commands cover direct work (`/ask`, `/commit`, `/merge`, `/skill/create`, `/skill/optimize`), orchestration (`/dev`, `/ship`, `/todo`, `/loop/pr/fix`), ticket planning/sync, and PR review/shipping flows. -- Agents are intentionally narrow: `worker` is generic, `planner` is no-edit planning, `navigator` owns multi-step orchestration, and `reviewer` is a no-edit review specialist. -- Structured tools keep workflows grounded in repo and GitHub state: `changes_load`, `command_expansion` (resolve a slash command and return the expanded prompt for immediate delegation), `pr_load`, `pr_sync`, `ticket_load`, `ticket_sync`. +- Commands cover direct work (`/ask`, `/commit`, `/merge`, `/skill/create`, `/skill/optimize`), orchestration (`/dev`, `/ship`, `/todo`, `/pr/fix/loop`), ticket planning/sync, and PR review/shipping flows. `/branch/inline`, `/commit/inline`, `/commit-and-push/inline`, `/pr/create/inline`, and `/ship/inline` reuse the invoking session instead of starting a subtask. +- Agents are intentionally narrow: `worker` handles implementation and multi-step workflows, `planner` is no-edit planning, and `reviewer` is a no-edit review specialist. +- Structured tools keep workflows grounded in repo and GitHub state: `changes_load`, `pr_load`, `pr_load_review`, `pr_sync`, `ticket_load`, `ticket_sync`. - Reusable command-template components live in `packages/core/components/` and are documented in the components reference. ## Prerequisites diff --git a/packages/opencode/index.ts b/packages/opencode/index.ts index f44eb46..b26527f 100644 --- a/packages/opencode/index.ts +++ b/packages/opencode/index.ts @@ -5,8 +5,8 @@ import { promisify } from "node:util"; import { createChangesLoadTool, - createCommandExpansionTool, createPrLoadTool, + createPrLoadReviewTool, createPrSyncTool, createTicketLoadTool, createTicketSyncTool, @@ -15,24 +15,18 @@ import { type Shell, type ShellPromise, } from "../core/index.ts"; -import { loadConfiguredNames, loadMergedKompassConfig } from "./cache.ts"; +import { loadMergedKompassConfig } from "./cache.ts"; import { applyAgentsConfig, applyCommandsConfig } from "./config.ts"; import { createPluginLogger, getErrorDetails, type PluginLogger } from "./logging.ts"; import { getConfiguredOpenCodeToolName, } from "./tool-names.ts"; -const AGENT_HANDOFF_MARKER = "generate a prompt and call the task tool with subagent:"; const execFileAsync = promisify(execFile); -type ToolExecuteBeforeHook = NonNullable; -type ToolExecuteBeforeInput = Parameters[0]; -type ToolExecuteBeforeOutput = Parameters[1]; type CommandExecuteBeforeHook = NonNullable; type CommandExecuteBeforeInput = Parameters[0]; type CommandExecuteBeforeOutput = Parameters[1]; -type ChatMessageHook = NonNullable; -type ChatMessageOutput = Parameters[1]; type OpenCodeToolCreator = ( client: PluginInput["client"], config: MergedKompassConfig, @@ -152,14 +146,6 @@ function createNodeShell(defaultDirectory: string): Shell { }; } -export type TaskToolExecution = { - prompt: string; - raw_prompt?: string; - description?: string; - subagent_type?: string; - command?: string; -}; - export type CommandExecution = { command: string; arguments: string; @@ -182,28 +168,6 @@ function logObservedFailure( }); } -export async function getTaskToolExecution( - input: ToolExecuteBeforeInput, - output: ToolExecuteBeforeOutput, -): Promise { - if (input.tool !== "task") return; - if (!output.args || typeof output.args !== "object") return; - - const args = output.args as Record; - const prompt = getString(args.prompt); - const command = getString(args.command); - - if (!prompt && !command) return; - - return { - prompt: prompt ?? command ?? "", - raw_prompt: prompt, - description: getString(args.description), - subagent_type: getString(args.subagent_type), - command, - }; -} - export function getCommandExecution( input: CommandExecuteBeforeInput, output: CommandExecuteBeforeOutput, @@ -222,19 +186,6 @@ export function getCommandExecution( }; } -export function removeSyntheticAgentHandoff(output: ChatMessageOutput): boolean { - const filteredParts = output.parts.filter((part) => !( - part.type === "text" && - part.synthetic === true && - part.text.toLowerCase().includes(AGENT_HANDOFF_MARKER) - )); - - if (filteredParts.length === output.parts.length) return false; - - output.parts.splice(0, output.parts.length, ...filteredParts); - return true; -} - const opencodeToolCreators: Record = { changes_load(_: PluginInput["client"], __: MergedKompassConfig, _projectRoot: string, shell: Shell) { const definition = createChangesLoadTool(shell); @@ -253,34 +204,23 @@ const opencodeToolCreators: Record = { execute: (args, context) => definition.execute(args, context), }); }, - command_expansion(_client: PluginInput["client"], config: MergedKompassConfig, projectRoot: string, _shell: Shell) { + pr_load(_: PluginInput["client"], __: MergedKompassConfig, _projectRoot: string, shell: Shell) { + const definition = createPrLoadTool(shell); return tool({ - description: "Expand a delegated command body into a runnable prompt for immediate task execution.", + description: definition.description, args: { - command: tool.schema.string().describe("Command name to execute, without the leading slash"), - body: tool.schema.string().describe("Literal body content from the delegate block").optional(), - }, - execute: async (args, context) => { - const names = await loadConfiguredNames(projectRoot); - const definition = createCommandExpansionTool(projectRoot, { names }); - - context.metadata({ - title: `Command /${args.command.trim()}`, - metadata: { - command: args.command, - }, - }); - - return definition.execute(args, context); + pr: tool.schema.string().describe("PR number or URL").optional(), }, + execute: (args, context) => definition.execute(args, context), }); }, - pr_load(_: PluginInput["client"], __: MergedKompassConfig, _projectRoot: string, shell: Shell) { - const definition = createPrLoadTool(shell); + pr_load_review(_: PluginInput["client"], __: MergedKompassConfig, _projectRoot: string, shell: Shell) { + const definition = createPrLoadReviewTool(shell); return tool({ description: definition.description, args: { pr: tool.schema.string().describe("PR number or URL").optional(), + since: tool.schema.string().describe("Exclusive ISO-8601 review checkpoint"), }, execute: (args, context) => definition.execute(args, context), }); @@ -432,25 +372,6 @@ export const OpenCodeCompassPlugin: Plugin = async (input: PluginInput) => { await runConfigStep("agents", () => applyAgentsConfig(cfg, worktree, { logger })); await runConfigStep("commands", () => applyCommandsConfig(cfg, worktree, { logger })); }, - async "chat.message"(input, output) { - try { - const removedSyntheticHandoff = removeSyntheticAgentHandoff(output); - - if (!removedSyntheticHandoff) return; - - logger.info("Removed synthetic agent handoff text", { - sessionID: input.sessionID, - messageID: input.messageID, - agent: input.agent, - }); - } catch (error) { - logObservedFailure(logger, "chat.message hook failed", error, { - sessionID: input.sessionID, - messageID: input.messageID, - agent: input.agent, - }); - } - }, async "command.execute.before"(input, output) { try { const commandExecution = getCommandExecution(input, output); @@ -466,21 +387,6 @@ export const OpenCodeCompassPlugin: Plugin = async (input: PluginInput) => { }); } }, - async "tool.execute.before"(input, output) { - try { - const taskExecution = await getTaskToolExecution(input, output); - - if (!taskExecution) return; - - logger.info("Executing Kompass task tool", taskExecution as Record); - } catch (error) { - logObservedFailure(logger, "tool.execute.before hook failed", error, { - tool: input.tool, - callID: input.callID, - sessionID: input.sessionID, - }); - } - }, }; }; diff --git a/packages/opencode/kompass.jsonc b/packages/opencode/kompass.jsonc index ad61bfa..6260572 100644 --- a/packages/opencode/kompass.jsonc +++ b/packages/opencode/kompass.jsonc @@ -13,19 +13,24 @@ "commands": { "ask": { "enabled": true }, "branch": { "enabled": true }, + "branch/inline": { "enabled": true }, "commit": { "enabled": true }, + "commit/inline": { "enabled": true }, "commit-and-push": { "enabled": true }, + "commit-and-push/inline": { "enabled": true }, "dev": { "enabled": true }, "learn": { "enabled": true }, - "loop/pr/fix": { "enabled": true }, "merge": { "enabled": true }, "pr/create": { "enabled": true }, + "pr/create/inline": { "enabled": true }, "pr/fix": { "enabled": true }, + "pr/fix/loop": { "enabled": true }, "pr/review": { "enabled": true }, "review": { "enabled": true }, "skill/create": { "enabled": true }, "skill/optimize": { "enabled": true }, "ship": { "enabled": true }, + "ship/inline": { "enabled": true }, "rmslop": { "enabled": true }, "todo": { "enabled": true }, "ticket/ask": { "enabled": true }, @@ -37,15 +42,14 @@ "agents": { "worker": { "enabled": true }, - "navigator": { "enabled": true }, "planner": { "enabled": true }, "reviewer": { "enabled": true }, }, "tools": { "changes_load": { "enabled": true }, - "command_expansion": { "enabled": true }, "pr_load": { "enabled": true }, + "pr_load_review": { "enabled": true }, "pr_sync": { "enabled": true }, "ticket_load": { "enabled": true }, "ticket_sync": { "enabled": true }, @@ -53,13 +57,18 @@ "components": { "change-summary": { "enabled": true }, + "branch": { "enabled": true }, "changes-summary": { "enabled": true }, "commit": { "enabled": true }, "dev-flow": { "enabled": true }, "load-pr": { "enabled": true }, "load-ticket": { "enabled": true }, + "pr-create": { "enabled": true }, + "pr-branch-update": { "enabled": true }, + "pr-fix": { "enabled": true }, + "push": { "enabled": true }, "skill-authoring": { "enabled": true }, - "summarize-changes": { "enabled": true }, + "ticket-planning": { "enabled": true }, }, "defaults": { diff --git a/packages/opencode/scripts/compile.ts b/packages/opencode/scripts/compile.ts index b5ce0a4..bc5c75f 100644 --- a/packages/opencode/scripts/compile.ts +++ b/packages/opencode/scripts/compile.ts @@ -88,6 +88,7 @@ async function main() { const frontmatter = YAML.stringify({ description: command.description, agent: command.agent, + ...(command.subtask === false ? { subtask: false } : {}), }); const content = ensureTrailingNewline( `---\n${frontmatter}---\n\n${command.template}`, diff --git a/packages/opencode/test/agents-config.test.ts b/packages/opencode/test/agents-config.test.ts index c9aa3ca..7c5f9c9 100644 --- a/packages/opencode/test/agents-config.test.ts +++ b/packages/opencode/test/agents-config.test.ts @@ -34,16 +34,6 @@ describe("applyAgentsConfig", () => { todowrite: "allow", }); assert.equal(cfg.agent.worker?.mode, undefined); - assert.equal( - cfg.agent.navigator?.description, - "Coordinate structured multi-step workflows and run focused slash-command steps in the current session.", - ); - assert.deepEqual(cfg.agent.navigator?.permission, { - edit: "deny", - task: "allow", - question: "allow", - todowrite: "allow", - }); assert.deepEqual(cfg.agent.reviewer?.permission, { edit: "deny", question: "allow", @@ -55,10 +45,7 @@ describe("applyAgentsConfig", () => { todowrite: "allow", }); assert.equal(cfg.agent.worker?.prompt, undefined); - assert.match(cfg.agent.navigator?.prompt ?? "", /structured, multi-step workflows/i); - assert.match(cfg.agent.navigator?.prompt ?? "", /call `?kompass_command_expansion`?/i); - assert.match(cfg.agent.navigator?.prompt ?? "", /manage step order/i); - assert.match(cfg.agent.navigator?.prompt ?? "", / { + test("reads the expanded command prompt from text parts", () => { + const execution = getCommandExecution( + { + command: "review", + sessionID: "session-2", + arguments: "auth bug", + }, + { + parts: [ + { + id: "part-1", + sessionID: "session-2", + messageID: "message-1", + type: "text", + text: "expanded command prompt", + }, + ], + }, + ); + + assert.deepEqual(execution, { + command: "review", + arguments: "auth bug", + prompt: "expanded command prompt", + }); + }); + + test("ignores command executions without text parts", () => { + const execution = getCommandExecution( + { + command: "review", + sessionID: "session-2", + arguments: "auth bug", + }, + { + parts: [ + { + id: "part-1", + sessionID: "session-2", + messageID: "message-1", + type: "subtask", + prompt: "/review auth bug", + description: "Run review command", + agent: "general", + }, + ], + }, + ); + + assert.equal(execution, undefined); + }); +}); diff --git a/packages/opencode/test/commands-config.test.ts b/packages/opencode/test/commands-config.test.ts index 66fe753..5e4a62d 100644 --- a/packages/opencode/test/commands-config.test.ts +++ b/packages/opencode/test/commands-config.test.ts @@ -34,14 +34,19 @@ describe("applyCommandsConfig", () => { const expectedCommands = [ "ask", "branch", - "loop/pr/fix", + "branch/inline", + "commit/inline", + "commit-and-push/inline", "merge", "pr/create", + "pr/create/inline", "pr/review", "pr/fix", + "pr/fix/loop", "skill/create", "skill/optimize", "ship", + "ship/inline", "ticket/ask", "ticket/create", "ticket/plan", @@ -73,14 +78,14 @@ describe("applyCommandsConfig", () => { assert.equal(cfg.command!["ticket/plan-and-sync"]?.agent, "planner"); assert.equal(cfg.command!["ask"]?.agent, "worker"); assert.equal(cfg.command!["ticket/ask"]?.agent, "worker"); - assert.equal(cfg.command!["dev"]?.agent, "navigator"); - assert.equal(cfg.command!["loop/pr/fix"]?.agent, "navigator"); - assert.equal(cfg.command!["ship"]?.agent, "navigator"); - assert.equal(cfg.command!["todo"]?.agent, "navigator"); - assert.equal(cfg.command!["ticket/dev"]?.agent, "navigator"); + assert.equal(cfg.command!["dev"]?.agent, "worker"); + assert.equal(cfg.command!["pr/fix/loop"]?.agent, "worker"); + assert.equal(cfg.command!["ship"]?.agent, "worker"); + assert.equal(cfg.command!["todo"]?.agent, "worker"); + assert.equal(cfg.command!["ticket/dev"]?.agent, "worker"); assert.ok(cfg.command!["pr/review"]?.description); assert.ok(cfg.command!["dev"]?.template); - assert.ok(cfg.command!["loop/pr/fix"]?.template); + assert.ok(cfg.command!["pr/fix/loop"]?.template); assert.ok(cfg.command!["branch"]?.template); }); }); @@ -189,7 +194,7 @@ describe("applyCommandsConfig", () => { assert.ok(cfg.command?.["open-pr"]); assert.equal(cfg.command?.["pr/create"], undefined); - assert.match(cfg.command?.ship.template ?? "", /command="open-pr"/); + assert.doesNotMatch(cfg.command?.ship.template ?? "", / { await applyCommandsConfig(cfg as never, process.cwd()); assert.ok(cfg.command); - assert.equal(cfg.command!["pr/fix"]?.subtask, false); + assert.equal(cfg.command!["pr/fix"]?.subtask, true); assert.equal(cfg.command!["pr/review"]?.subtask, true); assert.equal(cfg.command!["dev"]?.subtask, true); - assert.equal(cfg.command!["loop/pr/fix"]?.subtask, true); + assert.equal(cfg.command!["pr/fix/loop"]?.subtask, true); assert.equal(cfg.command!["ship"]?.subtask, true); + assert.equal(cfg.command!["branch/inline"]?.subtask, false); + assert.equal(cfg.command!["commit/inline"]?.subtask, false); + assert.equal(cfg.command!["commit-and-push/inline"]?.subtask, false); + assert.equal(cfg.command!["pr/create/inline"]?.subtask, false); + assert.equal(cfg.command!["ship/inline"]?.subtask, false); assert.equal(cfg.command!["todo"]?.subtask, true); }); @@ -395,8 +405,13 @@ describe("applyCommandsConfig", () => { assert.equal(cfg.command!["pr/fix"]?.subtask, false); assert.equal(cfg.command!["pr/review"]?.subtask, false); assert.equal(cfg.command!["dev"]?.subtask, false); - assert.equal(cfg.command!["loop/pr/fix"]?.subtask, false); + assert.equal(cfg.command!["pr/fix/loop"]?.subtask, false); assert.equal(cfg.command!["ship"]?.subtask, false); + assert.equal(cfg.command!["branch/inline"]?.subtask, false); + assert.equal(cfg.command!["commit/inline"]?.subtask, false); + assert.equal(cfg.command!["commit-and-push/inline"]?.subtask, false); + assert.equal(cfg.command!["pr/create/inline"]?.subtask, false); + assert.equal(cfg.command!["ship/inline"]?.subtask, false); assert.equal(cfg.command!["todo"]?.subtask, false); }); }); @@ -452,6 +467,7 @@ describe("applyCommandsConfig", () => { // All default commands should have templates loaded assert.ok(cfg.command!["dev"]?.template); assert.ok(cfg.command!["pr/create"]?.template); + assert.ok(cfg.command!["pr/create/inline"]?.template); assert.ok(cfg.command!["ticket/create"]?.template); assert.ok(cfg.command!["ask"]?.template); assert.ok(cfg.command!["pr/review"]?.template); @@ -461,13 +477,16 @@ describe("applyCommandsConfig", () => { assert.ok(cfg.command!["pr/fix"]?.template); assert.ok(cfg.command!["skill/create"]?.template); assert.ok(cfg.command!["skill/optimize"]?.template); - assert.ok(cfg.command!["loop/pr/fix"]?.template); + assert.ok(cfg.command!["pr/fix/loop"]?.template); assert.ok(cfg.command!["ship"]?.template); + assert.ok(cfg.command!["branch/inline"]?.template); + assert.ok(cfg.command!["commit-and-push/inline"]?.template); + assert.ok(cfg.command!["ship/inline"]?.template); assert.ok(cfg.command!["ticket/dev"]?.template); assert.ok(cfg.command!["review"]?.template); }); - test("embeds literal delegate blocks in ship command", async () => { + test("embeds inline reusable phases in ship command", async () => { delete process.env.CI; const cfg: { command?: Record } = {}; @@ -477,17 +496,11 @@ describe("applyCommandsConfig", () => { const shipTemplate = cfg.command!["ship"].template; assert.match(shipTemplate, /## Goal/); - assert.match(shipTemplate, /Ship the current work by dispatching/); - assert.match(shipTemplate, /Delegate Branch Creation/); - assert.match(shipTemplate, //); - assert.match(shipTemplate, /\nBranch naming guidance: \n<\/delegate>/); - assert.match(shipTemplate, /Store the delegated result as ``/); - assert.match(shipTemplate, //); - assert.match(shipTemplate, /\nAdditional context: \n<\/delegate>/); - assert.match(shipTemplate, /Store the delegated result as ``/); - assert.match(shipTemplate, //); - assert.match(shipTemplate, /\nBase branch: \nAdditional context: \n<\/delegate>/); - assert.match(shipTemplate, /Store the delegated result as ``/); + assert.match(shipTemplate, /Load Uncommitted Changes Once/); + assert.match(shipTemplate, /Check Branch/); + assert.match(shipTemplate, /Create Commit/); + assert.match(shipTemplate, /Create PR/); + assert.doesNotMatch(shipTemplate, / { assert.match(prCreateTemplate, /## Goal/); assert.match(prCreateTemplate, /Create a pull request/); assert.match(prCreateTemplate, /Interpret Arguments/); - assert.match(prCreateTemplate, /Load & Analyze Changes/); + assert.match(prCreateTemplate, /Load And Analyze Changes/); assert.doesNotMatch(prCreateTemplate, /<%/); }); @@ -580,27 +593,17 @@ describe("applyCommandsConfig", () => { // Should have replaced components assert.match(ticketDevTemplate, /Development Flow Navigation Guide/); - // PR Author content is now inline in pr/create, not embedded here assert.match(ticketDevTemplate, /## Goal/); assert.match(ticketDevTemplate, /Implement a ticket/); - assert.match(ticketDevTemplate, //); - assert.match(ticketDevTemplate, /\nTicket reference: \nTicket context: \nAdditional context: \n<\/delegate>/); - assert.match(ticketDevTemplate, /Store the delegated result as ``/); - assert.match(ticketDevTemplate, //); - assert.match(ticketDevTemplate, /\nBranch naming guidance: \nAdditional context: \n<\/delegate>/); - assert.match(ticketDevTemplate, /Store the delegated result as ``/); - assert.match(ticketDevTemplate, //); - assert.match(ticketDevTemplate, /\nTicket reference: \nTicket summary: \nAdditional context: \n<\/delegate>/); - assert.match(ticketDevTemplate, /Store the delegated result as ``/); - assert.match(ticketDevTemplate, //); - assert.match(ticketDevTemplate, /\nTicket reference: \nTicket context: \nAdditional context: \n<\/delegate>/); - assert.match(ticketDevTemplate, /Store the delegated result as ``/); - assert.doesNotMatch(ticketDevTemplate, / { + test("embeds inline planning and implementation in todo command", async () => { delete process.env.CI; const cfg: { command?: Record } = {}; @@ -611,18 +614,11 @@ describe("applyCommandsConfig", () => { assert.match(todoTemplate, /## Goal/); assert.match(todoTemplate, /Work through a todo file one pending item at a time by planning/); - assert.match(todoTemplate, //); - assert.match(todoTemplate, /\nTask: \nTask context: \nAdditional context: \n<\/delegate>/); - assert.match(todoTemplate, /Store the delegated result as ``/); - assert.match(todoTemplate, //); - assert.match(todoTemplate, /Current plan: \nPlan feedback: /); - assert.match(todoTemplate, /\nPlan: \nTask: \nTask context: \nAdditional context: \n<\/delegate>/); - assert.match(todoTemplate, /Store the revised delegated result as ``/); - assert.match(todoTemplate, //); - assert.match(todoTemplate, /\nTask: \nAdditional context: \n<\/delegate>/); - assert.match(todoTemplate, /Store the delegated result as ``/); - assert.match(todoTemplate, /Store the delegated result as ``/); - assert.match(todoTemplate, /Todo: /); + assert.match(todoTemplate, /Plan Task/); + assert.match(todoTemplate, /Implement Task/); + assert.match(todoTemplate, /Load And Commit Task Changes/); + assert.doesNotMatch(todoTemplate, //); assert.doesNotMatch(todoTemplate, / { - test("keeps raw task prompts unchanged", async () => { - const output = { - args: { - prompt: "/review auth bug", - description: "Run review command", - subagent_type: "reviewer", - command: "@reviewer /review auth bug", - }, - }; - const execution = await getTaskToolExecution( - { - tool: "task", - sessionID: "session-1", - callID: "call-1", - }, - output, - ); - - assert.equal(execution?.prompt, "/review auth bug"); - assert.equal(execution?.raw_prompt, "/review auth bug"); - assert.equal(execution?.description, "Run review command"); - assert.equal(execution?.subagent_type, "reviewer"); - assert.equal(execution?.command, "@reviewer /review auth bug"); - }); - - test("prefers the raw prompt over command metadata", async () => { - const output = { - args: { - prompt: "/review auth bug with multiline\nextra context", - description: "Run review command", - subagent_type: "reviewer", - command: "@reviewer /review auth bug", - }, - }; - - const execution = await getTaskToolExecution( - { - tool: "task", - sessionID: "session-1", - callID: "call-1", - }, - output, - ); - - assert.equal(execution?.prompt, "/review auth bug with multiline\nextra context"); - assert.equal(execution?.command, "@reviewer /review auth bug"); - }); - - test("ignores non-task tool calls", async () => { - const execution = await getTaskToolExecution( - { - tool: "bash", - sessionID: "session-1", - callID: "call-1", - }, - { - args: { - prompt: "should not be read", - }, - }, - ); - - assert.equal(execution, undefined); - }); - - test("ignores task tool calls without a prompt or command", async () => { - const execution = await getTaskToolExecution( - { - tool: "task", - sessionID: "session-1", - callID: "call-1", - }, - { - args: { - description: "Fix auth bug", - subagent_type: "planner", - }, - }, - ); - - assert.equal(execution, undefined); - }); - - test("returns the raw task prompt when the command is unknown", async () => { - const execution = await getTaskToolExecution( - { - tool: "task", - sessionID: "session-1", - callID: "call-1", - }, - { - args: { - prompt: "/unknown auth bug", - command: "/unknown auth bug", - }, - }, - ); - - assert.deepEqual(execution, { - prompt: "/unknown auth bug", - raw_prompt: "/unknown auth bug", - command: "/unknown auth bug", - description: undefined, - subagent_type: undefined, - }); - }); - - test("falls back to command metadata when prompt is missing", async () => { - const output = { - args: { - prompt: undefined, - command: "/branch Branch naming guidance: fix login redirect", - description: "Create feature branch", - subagent_type: "worker", - }, - }; - - const execution = await getTaskToolExecution( - { - tool: "task", - sessionID: "session-1", - callID: "call-1", - }, - output, - ); - - assert.equal(execution?.prompt, "/branch Branch naming guidance: fix login redirect"); - assert.equal(execution?.command, "/branch Branch naming guidance: fix login redirect"); - assert.equal(output.args.prompt, undefined); - }); -}); - -describe("getCommandExecution", () => { - test("reads the expanded command prompt from text parts", () => { - const execution = getCommandExecution( - { - command: "review", - sessionID: "session-2", - arguments: "auth bug", - }, - { - parts: [ - { - id: "part-1", - sessionID: "session-2", - messageID: "message-1", - type: "text", - text: "expanded command prompt", - }, - ], - }, - ); - - assert.deepEqual(execution, { - command: "review", - arguments: "auth bug", - prompt: "expanded command prompt", - }); - }); - - test("ignores command executions without text parts", () => { - const execution = getCommandExecution( - { - command: "review", - sessionID: "session-2", - arguments: "auth bug", - }, - { - parts: [ - { - id: "part-1", - sessionID: "session-2", - messageID: "message-1", - type: "subtask", - prompt: "/review auth bug", - description: "Run review command", - agent: "general", - }, - ], - }, - ); - - assert.equal(execution, undefined); - }); -}); - -describe("removeSyntheticAgentHandoff", () => { - test("removes the legacy synthetic agent handoff text", () => { - const output = { - parts: [ - { - id: "part-1", - sessionID: "session-3", - messageID: "message-1", - type: "text", - text: "Please generate a prompt and call the task tool with subagent: planner", - synthetic: true, - }, - { - id: "part-2", - sessionID: "session-3", - messageID: "message-1", - type: "text", - text: "keep this", - }, - ], - }; - - const removed = removeSyntheticAgentHandoff(output as never); - - assert.equal(removed, true); - assert.equal(output.parts.length, 1); - assert.equal(output.parts[0]?.text, "keep this"); - }); - - test("keeps non-synthetic text untouched", () => { - const output = { - parts: [ - { - id: "part-1", - sessionID: "session-4", - messageID: "message-1", - type: "text", - text: "Summarize the task tool output above and continue with your task.", - }, - ], - }; - - const removed = removeSyntheticAgentHandoff(output as never); - - assert.equal(removed, false); - assert.equal(output.parts.length, 1); - }); -}); diff --git a/packages/opencode/test/tool-registration.test.ts b/packages/opencode/test/tool-registration.test.ts index cdc6b7f..03d8f8a 100644 --- a/packages/opencode/test/tool-registration.test.ts +++ b/packages/opencode/test/tool-registration.test.ts @@ -132,14 +132,14 @@ describe("createOpenCodeTools", () => { const tools = await createOpenCodeTools(createMockClient() as never, process.cwd()); assert.ok(tools.kompass_changes_load); - assert.ok(tools.kompass_command_expansion); assert.ok(tools.kompass_pr_load); + assert.ok(tools.kompass_pr_load_review); assert.ok(tools.kompass_pr_sync); assert.ok(tools.kompass_ticket_load); assert.ok(tools.kompass_ticket_sync); assert.equal(tools.changes_load, undefined); - assert.equal(tools.command_expansion, undefined); assert.equal(tools.pr_load, undefined); + assert.equal(tools.pr_load_review, undefined); assert.equal(tools.pr_sync, undefined); assert.equal(tools.ticket_load, undefined); assert.equal(tools.ticket_sync, undefined); @@ -178,8 +178,8 @@ describe("createOpenCodeTools", () => { `{ "tools": { "changes_load": { "enabled": false }, - "command_expansion": { "enabled": false }, "pr_load": { "enabled": false }, + "pr_load_review": { "enabled": false }, "pr_sync": { "enabled": false }, "ticket_sync": { "enabled": true, @@ -212,9 +212,6 @@ describe("createOpenCodeTools", () => { `{ // jsonc config should work "tools": { - "command_expansion": { - "enabled": false - }, "pr_load": { "enabled": true, "name": "pull_request_context", @@ -286,60 +283,6 @@ describe("createOpenCodeTools", () => { }); }); - test("command_expansion returns expanded prompts for delegated task execution", async () => { - await withTempHome(async () => { - const client = createMockClient(); - const tools = await createOpenCodeTools(client as never, process.cwd()); - - const output = await (tools.kompass_command_expansion as any).execute( - { command: "review", body: "auth bug" }, - { - sessionID: "session-1", - messageID: "message-1", - agent: "worker", - directory: process.cwd(), - worktree: process.cwd(), - abort: new AbortController().signal, - metadata() {}, - ask: async () => {}, - }, - ); - - assert.equal(client.sessionCommands.length, 0); - assert.equal(client.sessionPromptAsyncs.length, 0); - assert.match(String(output), /kompass_changes_load/); - assert.doesNotMatch(String(output), /`changes_load`/); - assert.match(String(output), /auth bug/); - assert.equal(client.sessionPrompts.length, 0); - }); - }); - - test("command tool rejects missing commands", async () => { - await withTempHome(async () => { - const client = createMockClient(); - const tools = await createOpenCodeTools(client as never, process.cwd()); - - await assert.rejects( - (tools.kompass_command_expansion as any).execute( - { command: " ", body: "Investigate the redirect bug" }, - { - sessionID: "session-2", - messageID: "message-2", - agent: "worker", - directory: process.cwd(), - worktree: process.cwd(), - abort: new AbortController().signal, - metadata() {}, - ask: async () => {}, - }, - ), - /requires a command/, - ); - assert.equal(client.sessionCommands.length, 0); - assert.equal(client.sessionPrompts.length, 0); - }); - }); - test("plugin registers shell-backed tools that execute in the worktree", async () => { await withTempHome(async () => { const tempDir = await createTempGitRepo(); @@ -366,53 +309,4 @@ describe("createOpenCodeTools", () => { }); }); - test("does not expand slash commands in the task hook", async () => { - await withTempHome(async () => { - const client = createMockClient(); - const tempDir = await mkdtemp(path.join(os.tmpdir(), "kompass-tools-bad-config-")); - - try { - await mkdir(path.join(tempDir, ".opencode"), { recursive: true }); - await writeFile( - path.join(tempDir, ".opencode", "kompass.jsonc"), - `{ - "shared": { - "prApprove": true, - }`, - ); - - const plugin = await OpenCodeCompassPlugin({ - $: (() => { - throw new Error("not implemented"); - }) as never, - client: client as never, - directory: tempDir, - worktree: tempDir, - } as never); - - const output = { - args: { - prompt: "/review auth bug", - command: "/review auth bug", - }, - }; - - await plugin["tool.execute.before"]?.( - { - tool: "task", - sessionID: "session-1", - callID: "call-1", - } as never, - output as never, - ); - - assert.equal(output.args.prompt, "/review auth bug"); - assert.ok(client.logs.some((entry) => entry.body?.message?.includes("Skipping Kompass tool registration"))); - assert.ok(client.logs.some((entry) => entry.body?.message?.includes("Executing Kompass task tool"))); - } finally { - await rm(tempDir, { recursive: true, force: true }); - } - }); - }); - }); diff --git a/packages/web/src/components/CommandShowcase.astro b/packages/web/src/components/CommandShowcase.astro index d6e9e84..8dfc2be 100644 --- a/packages/web/src/components/CommandShowcase.astro +++ b/packages/web/src/components/CommandShowcase.astro @@ -47,15 +47,14 @@ const scenarios: CommandScenario[] = [ }, { id: 'branch', - label: '/branch', - command: '/branch docs cleanup', + label: '/branch/inline', + command: '/branch/inline docs cleanup', agentName: 'Worker', task: 'Create a categorized branch from current work', group: 'workflow', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Summarize uncommitted work, check whether the current branch already looks like a work branch, then generate a short categorized name.' }, + { id: 'thinking', phase: 'thinking', content: 'Reuse current-session change context, check the live branch and worktree, then generate a short categorized name.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ - { tool: 'changes_load', args: 'uncommitted: true', status: 'complete' }, { tool: 'bash', args: 'git checkout -b docs/reference-cleanup', status: 'complete' } ] }, { id: 'output', phase: 'output', output: [ @@ -66,15 +65,14 @@ const scenarios: CommandScenario[] = [ }, { id: 'commit', - label: '/commit', - command: '/commit tighten command docs', + label: '/commit/inline', + command: '/commit/inline tighten command docs', agentName: 'Worker', task: 'Create a commit from uncommitted work', group: 'workflow', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Load uncommitted changes, stop if there is nothing to commit, then stage the work and write a conventional message.' }, + { id: 'thinking', phase: 'thinking', content: 'Reuse the current session change context, stop if there is nothing to commit, then stage the work and write a conventional message.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ - { tool: 'changes_load', args: 'uncommitted: true', status: 'complete' }, { tool: 'bash', args: 'git add -A', status: 'complete' }, { tool: 'bash', args: 'git commit', status: 'complete' } ] }, @@ -86,15 +84,14 @@ const scenarios: CommandScenario[] = [ }, { id: 'commit-and-push', - label: '/commit-and-push', - command: '/commit-and-push', + label: '/commit-and-push/inline', + command: '/commit-and-push/inline', agentName: 'Worker', task: 'Create a commit and push it', group: 'workflow', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Create the commit from current uncommitted work, then push and fall back to upstream setup if needed.' }, + { id: 'thinking', phase: 'thinking', content: 'Reuse current-session changes for the commit, then push and fall back to upstream setup if needed.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ - { tool: 'changes_load', args: 'uncommitted: true', status: 'complete' }, { tool: 'bash', args: 'git commit', status: 'complete' }, { tool: 'bash', args: 'git push', status: 'complete' } ] }, @@ -249,17 +246,16 @@ const scenarios: CommandScenario[] = [ id: 'ticket-dev', label: '/ticket/dev', command: '/ticket/dev #42', - agentName: 'Navigator', + agentName: 'Worker', task: 'Implement a ticket through PR creation', group: 'ticket', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Load the ticket, then orchestrate implementation, branch creation, commit-and-push, and PR creation in order.' }, + { id: 'thinking', phase: 'thinking', content: 'Load the ticket, implement it, then reuse change context through branch, commit, push, and PR creation.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ { tool: 'ticket_load', args: '#42', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · dev', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · branch', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · commit-and-push', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · pr/create', status: 'complete' } + { tool: 'changes_load', args: 'uncommitted', status: 'complete' }, + { tool: 'changes_load', args: 'branch comparison', status: 'complete' }, + { tool: 'pr_sync', args: 'create PR', status: 'complete' } ] }, { id: 'output', phase: 'output', output: [ 'Implemented ticket: refresh command docs', @@ -309,8 +305,8 @@ const scenarios: CommandScenario[] = [ }, { id: 'pr-create', - label: '/pr/create', - command: '/pr/create', + label: '/pr/create/inline', + command: '/pr/create/inline', agentName: 'Worker', task: 'Create a structured PR from current branch work', group: 'pr', @@ -338,9 +334,10 @@ const scenarios: CommandScenario[] = [ task: 'Fix review feedback, then push and reply', group: 'pr', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Address the feedback, validate the fixes, then in default mode wait for approval before committing, pushing, or replying on the PR.' }, + { id: 'thinking', phase: 'thinking', content: 'Update the PR branch from its base when needed, address the feedback, validate the fixes, then wait for approval before pushing or replying.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ { tool: 'pr_load', args: 'current PR', status: 'complete' }, + { tool: 'bash', args: 'fetch and merge PR base when behind', status: 'complete' }, { tool: 'apply_patch', args: 'implement requested fixes', status: 'complete' }, { tool: 'question', args: 'Review Fixes', status: 'complete' }, { tool: 'bash', args: 'git push', status: 'complete' }, @@ -417,17 +414,16 @@ const scenarios: CommandScenario[] = [ }, { id: 'ship', - label: '/ship', - command: '/ship', - agentName: 'Navigator', - task: 'Ship current work through delegated steps', + label: '/ship/inline', + command: '/ship/inline', + agentName: 'Worker', + task: 'Ship current work in one stateful workflow', group: 'orchestration', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Ensure a work branch, delegate commit creation, then delegate PR creation and stop on blockers.' }, + { id: 'thinking', phase: 'thinking', content: 'Reuse current-session work for branch and commit phases, then load the committed branch comparison for PR creation.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ - { tool: 'command_expansion', args: 'worker · branch', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · commit', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · pr/create', status: 'complete' } + { tool: 'changes_load', args: 'branch comparison', status: 'complete' }, + { tool: 'pr_sync', args: 'create PR', status: 'complete' } ] }, { id: 'output', phase: 'output', output: [ 'Ship flow complete', @@ -438,18 +434,18 @@ const scenarios: CommandScenario[] = [ }, { id: 'loop-pr-fix', - label: '/loop/pr/fix', - command: '/loop/pr/fix 51', - agentName: 'Navigator', + label: '/pr/fix/loop', + command: '/pr/fix/loop 51', + agentName: 'Worker', task: 'Watch PR CI and comments, then fix both hands-off', group: 'orchestration', steps: [ - { id: 'thinking', phase: 'thinking', content: 'Load the PR, wait for checks to finish, reload comments, delegate a non-interactive fix pass for CI and feedback, then repeat until clean.' }, + { id: 'thinking', phase: 'thinking', content: 'Load the PR once, wait for checks, incrementally load review activity, apply fixes inline, then repeat until clean.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ { tool: 'pr_load', args: 'PR #51', status: 'complete' }, { tool: 'bash', args: 'gh pr checks 51 --watch', status: 'complete' }, - { tool: 'pr_load', args: 'refresh PR feedback', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · pr/fix auto', status: 'complete' } + { tool: 'pr_load_review', args: 'since last checkpoint', status: 'complete' }, + { tool: 'pr_sync', args: 'reply to addressed feedback', status: 'complete' } ] }, { id: 'output', phase: 'output', output: [ 'PR loop complete for #51', @@ -463,17 +459,16 @@ const scenarios: CommandScenario[] = [ id: 'todo', label: '/todo', command: '/todo @TODO.md', - agentName: 'Navigator', + agentName: 'Worker', task: 'Work through a todo file one item at a time', group: 'orchestration', steps: [ { id: 'thinking', phase: 'thinking', content: 'Take the first unchecked item only, plan it, get approval, implement it, commit it, mark it complete, and loop.' }, { id: 'tools', phase: 'tool_calls', toolCalls: [ { tool: 'read', args: '@TODO.md', status: 'complete' }, - { tool: 'command_expansion', args: 'planner · ticket/plan', status: 'complete' }, { tool: 'question', args: 'Plan Review', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · dev', status: 'complete' }, - { tool: 'command_expansion', args: 'worker · commit', status: 'complete' } + { tool: 'changes_load', args: 'uncommitted', status: 'complete' }, + { tool: 'bash', args: 'git commit', status: 'complete' } ] }, { id: 'output', phase: 'output', output: [ 'Todo complete: @TODO.md', @@ -662,27 +657,18 @@ const orchestrationScenarios = scenarios.filter(s => s.group === 'orchestration'
- {step.toolCalls.some(t => t.tool === 'command_expansion') ? 'Delegated' : 'Explored'} + Tools - {step.toolCalls.length} {step.toolCalls.some(t => t.tool === 'command_expansion') ? 'delegations' : 'reads, 1 search'} + {step.toolCalls.length} calls
{step.toolCalls.map((tool) => ( -
- {tool.tool === 'command_expansion' ? ( - <> - - {tool.args} - - ) : ( - <> - - {tool.tool} - {tool.args} - - )} +
+ + {tool.tool} + {tool.args}
))}
diff --git a/packages/web/src/content/docs/docs/adapters/opencode.mdx b/packages/web/src/content/docs/docs/adapters/opencode.mdx index d894b5b..0e333d5 100644 --- a/packages/web/src/content/docs/docs/adapters/opencode.mdx +++ b/packages/web/src/content/docs/docs/adapters/opencode.mdx @@ -27,15 +27,15 @@ You can use overrides to: - enable or disable agents - remap tool names - change defaults such as the base branch -- adjust adapter behavior such as `agentMode` and `subtaskCommandMode` +- adjust adapter behavior such as `agentMode` ## Agent model Most command execution runs on the bundled `worker` agent. -Kompass also provides the `worker`, `navigator`, `planner`, and `reviewer` agent roles for structured workflow execution and review-specific execution. +Kompass also provides the `worker`, `planner`, and `reviewer` agent roles for workflow execution, planning, and review-specific execution. -OpenCode also exposes the `command_expansion` tool, which resolves explicit command-plus-body inputs into the rendered prompt that a navigator can delegate immediately through `task`. +Commands run as subtasks outside CI unless their definition opts out. The `/inline` variants of `/branch`, `/commit`, `/commit-and-push`, `/pr/create`, and `/ship`, plus `/learn`, opt out so they can use the invoking session directly. ## Useful OpenCode notes diff --git a/packages/web/src/content/docs/docs/concepts/modes.mdx b/packages/web/src/content/docs/docs/concepts/modes.mdx index 1e00a16..2749225 100644 --- a/packages/web/src/content/docs/docs/concepts/modes.mdx +++ b/packages/web/src/content/docs/docs/concepts/modes.mdx @@ -11,6 +11,8 @@ Kompass is built around three working styles: The same command and agent structure can support each mode without forcing one interaction pattern. +OpenCode normally runs commands as subtasks outside CI. Use the `/inline` variants of `/branch`, `/commit`, `/commit-and-push`, `/pr/create`, and `/ship` when the invoking session should retain execution; these variants force `subtask: false`. Change-producing variants skip redundant initial uncommitted loads, while `/pr/create/inline` still loads the authoritative committed branch comparison. + ## Manual steering Use this when you want the tightest control. @@ -31,6 +33,6 @@ Use this when you want shared planning and execution. Use this when you want the agent to run further on its own. -- let navigator-style workflows orchestrate multiple phases +- let stateful commands orchestrate multiple phases inline - rely on structured tools instead of ad-hoc context guessing - review artifacts such as plans, tickets, and PRs at checkpoints diff --git a/packages/web/src/content/docs/docs/config/overview.mdx b/packages/web/src/content/docs/docs/config/overview.mdx index 29295da..352f2e9 100644 --- a/packages/web/src/content/docs/docs/config/overview.mdx +++ b/packages/web/src/content/docs/docs/config/overview.mdx @@ -64,7 +64,6 @@ Shared defaults such as `baseBranch`. Adapter-specific configuration. Today this includes: - `adapters.opencode.agentMode` -- `adapters.opencode.subtaskCommandMode` ## Tool alias example diff --git a/packages/web/src/content/docs/docs/config/schema.mdx b/packages/web/src/content/docs/docs/config/schema.mdx index ab3766e..38b1333 100644 --- a/packages/web/src/content/docs/docs/config/schema.mdx +++ b/packages/web/src/content/docs/docs/config/schema.mdx @@ -49,9 +49,3 @@ Deprecated array fields still exist in the schema for compatibility, but the new - `subagent` - `primary` - `all` - -`adapters.opencode.subtaskCommandMode` supports: - -- `kompass` -- `all` -- `off` diff --git a/packages/web/src/content/docs/docs/reference/agents/index.mdx b/packages/web/src/content/docs/docs/reference/agents/index.mdx index dd1cd73..b2d0ac8 100644 --- a/packages/web/src/content/docs/docs/reference/agents/index.mdx +++ b/packages/web/src/content/docs/docs/reference/agents/index.mdx @@ -5,17 +5,13 @@ description: Overview of the bundled Kompass agent roles. ## Bundled agents -Kompass currently defines four bundled agent roles: `worker`, `navigator`, `planner`, and `reviewer`. +Kompass currently defines three bundled agent roles: `worker`, `planner`, and `reviewer`. These are resolved from merged config and exposed through the active adapter. ### `worker` -Generic worker role with minimal built-in behavior. It is the default execution agent when a command just needs focused work. - -### `navigator` - -Owns structured multi-step workflows locally, preserves state and stop conditions, and forwards literal `` blocks through the `command_expansion` tool when commands such as `/ship`, `/todo`, `/ticket/dev`, and `/loop/pr/fix` require delegated step execution. +Generic worker role with minimal built-in behavior. It is the default execution agent for focused work and stateful multi-step command workflows. ### `planner` diff --git a/packages/web/src/content/docs/docs/reference/agents/navigator.mdx b/packages/web/src/content/docs/docs/reference/agents/navigator.mdx deleted file mode 100644 index c011ced..0000000 --- a/packages/web/src/content/docs/docs/reference/agents/navigator.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: navigator -description: Orchestrator agent for structured multi-step workflows. ---- - -## Role - -`navigator` owns multi-step command workflows locally. It keeps state, ordering, approval gates, and stop conditions in one place instead of handing orchestration off elsewhere. - -## Best for - -- pause-and-resume workflows -- stepwise orchestration such as `/ship`, `/todo`, `/ticket/dev`, and `/loop/pr/fix` -- commands that mix local state handling with delegated leaf steps - -## Key behavior - -- forwards literal `...` bodies exactly after variable substitution -- calls `command_expansion` with explicit `command` and `body` -- immediately delegates the returned prompt through `task` and uses that task result as the step result -- stops and reports blockers when the workflow itself cannot continue safely diff --git a/packages/web/src/content/docs/docs/reference/agents/worker.mdx b/packages/web/src/content/docs/docs/reference/agents/worker.mdx index 6a7649d..5d757c3 100644 --- a/packages/web/src/content/docs/docs/reference/agents/worker.mdx +++ b/packages/web/src/content/docs/docs/reference/agents/worker.mdx @@ -10,7 +10,7 @@ description: Generic worker role used for focused execution. ## Best for - focused implementation or follow-up work -- direct command execution that does not need planner, navigator, or reviewer specialization +- direct command execution that does not need planner or reviewer specialization - asking a targeted question when a command allows it and execution is blocked ## Notes diff --git a/packages/web/src/content/docs/docs/reference/commands/branch.mdx b/packages/web/src/content/docs/docs/reference/commands/branch.mdx index 2dd868f..1634fb4 100644 --- a/packages/web/src/content/docs/docs/reference/commands/branch.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/branch.mdx @@ -11,8 +11,11 @@ Use `/branch` to create a short categorized branch name from current uncommitted ```text /branch [context] +/branch/inline [context] ``` +Use `/branch/inline` to retain the invoking session and reuse its known uncommitted-change context. It still checks the active branch and current worktree before creating a branch. + ## Typical flow - load uncommitted changes with `changes_load` diff --git a/packages/web/src/content/docs/docs/reference/commands/commit-and-push.mdx b/packages/web/src/content/docs/docs/reference/commands/commit-and-push.mdx index 9f963c6..97ca700 100644 --- a/packages/web/src/content/docs/docs/reference/commands/commit-and-push.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/commit-and-push.mdx @@ -11,8 +11,11 @@ Use `/commit-and-push` when current uncommitted work should become a commit and ```text /commit-and-push [message-guidance] +/commit-and-push/inline [message-guidance] ``` +Use `/commit-and-push/inline` to retain the invoking session, reuse its known uncommitted-change context, and keep push and upstream checks live. + ## Typical flow - load uncommitted changes with `changes_load` diff --git a/packages/web/src/content/docs/docs/reference/commands/commit.mdx b/packages/web/src/content/docs/docs/reference/commands/commit.mdx index 62a0895..d4c30c4 100644 --- a/packages/web/src/content/docs/docs/reference/commands/commit.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/commit.mdx @@ -11,8 +11,11 @@ Use `/commit` to stage current work, generate a commit message, and create a com ```text /commit [message-guidance] +/commit/inline [message-guidance] ``` +Use `/commit/inline` to run in the invoking session with `subtask: false`. It reuses the session's known uncommitted-change context and only inspects the worktree when that context is insufficient. + ## Typical flow - load uncommitted changes with `changes_load` diff --git a/packages/web/src/content/docs/docs/reference/commands/index.mdx b/packages/web/src/content/docs/docs/reference/commands/index.mdx index f52e1e8..d8bde3b 100644 --- a/packages/web/src/content/docs/docs/reference/commands/index.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/index.mdx @@ -7,17 +7,17 @@ Kompass ships workflow-oriented commands authored as explicit templates in `pack ## Groups -- Workflow: `/ask`, `/branch`, `/commit`, `/commit-and-push`, `/merge`, `/rmslop` +- Workflow: `/ask`, `/branch`, `/branch/inline`, `/commit`, `/commit/inline`, `/commit-and-push`, `/commit-and-push/inline`, `/merge`, `/rmslop` - Guidelines: `/learn`, `/skill/create`, `/skill/optimize` - Ticket: `/ticket/ask`, `/ticket/create`, `/ticket/dev`, `/ticket/plan`, `/ticket/plan-and-sync` -- PR: `/pr/create`, `/pr/fix`, `/pr/review`, `/review` -- Orchestration: `/dev`, `/ship`, `/todo`, `/loop/pr/fix` +- PR: `/pr/create`, `/pr/create/inline`, `/pr/fix`, `/pr/review`, `/review` +- Orchestration: `/dev`, `/ship`, `/ship/inline`, `/todo`, `/pr/fix/loop` ## What makes them different - each command is a documented workflow, not an opaque prompt - placeholders like ``, ``, and `` are normalized before execution -- navigator workflows orchestrate locally and delegate focused leaf work with literal `` blocks +- multi-step commands preserve state and reuse shared component phases in one workflow - outputs are deterministic, reviewable, and usually terminal ## Workflow Commands @@ -38,6 +38,14 @@ Creates and switches to a categorized work branch from current uncommitted chang - arguments: optional naming guidance that can steer the category and slug - expected tools: `changes_load(uncommitted)`, `git checkout -b` +### `/branch/inline` + +Creates a work branch in the invoking session from its known uncommitted work. + +- usage: `/branch/inline [context]` +- arguments: optional naming guidance +- expected tools: live branch/worktree inspection and `git checkout -b`; no initial `changes_load` + ### `/commit` Creates a commit with an appropriate message summarizing uncommitted changes. @@ -46,6 +54,14 @@ Creates a commit with an appropriate message summarizing uncommitted changes. - arguments: optional commit message guidance - expected tools: `changes_load(uncommitted)`, staging/commit git commands +### `/commit/inline` + +Creates a commit in the invoking session, reusing its known uncommitted-change context instead of loading changes again. + +- usage: `/commit/inline [message-guidance]` +- arguments: optional commit message guidance +- expected tools: staging/commit git commands; worktree inspection only when session context is insufficient + ### `/commit-and-push` Creates a commit and immediately pushes it to the remote repository. @@ -54,6 +70,14 @@ Creates a commit and immediately pushes it to the remote repository. - arguments: optional commit message guidance - expected tools: `changes_load(uncommitted)`, git commit, `git push` with upstream fallback when needed +### `/commit-and-push/inline` + +Commits and pushes in the invoking session, reusing its known uncommitted-change context. + +- usage: `/commit-and-push/inline [message-guidance]` +- arguments: optional commit message guidance +- expected tools: staging/commit commands and live `git push`; worktree inspection only when session context is insufficient + ### `/merge` Merges a provided branch into the current branch, defaulting to the repo base branch, and resolves conflicts with a best-effort preference for the incoming branch. @@ -116,11 +140,11 @@ Creates a ticket summarizing the current change comparison. ### `/ticket/dev` -Implements a ticket through a navigator-led orchestration of `/dev`, `/branch`, `/commit-and-push`, and `/pr/create`. +Implements and ships a ticket in one stateful workflow. - usage: `/ticket/dev ` - arguments: ticket reference, URL, file path, or raw request -- expected tools: `ticket_load`, `command_expansion(dev)`, `command_expansion(branch)`, `command_expansion(commit-and-push)`, `command_expansion(pr/create)` +- expected tools: `ticket_load`, `changes_load`, validation commands, `ticket_sync`, `pr_sync` ### `/ticket/plan` @@ -148,6 +172,14 @@ Creates a pull request for the current branch, including mandatory ticket resolu - arguments: optional base branch, ticket directive, ticket reference, skip directive, or additional context - expected tools: `changes_load`, `question` when ticket handling is unresolved, `ticket_sync` when auto-creating a ticket, `git push`, `pr_sync` +### `/pr/create/inline` + +Creates the PR in the invoking session while retaining an authoritative committed branch comparison. + +- usage: `/pr/create/inline [base-or-ticket-context]` +- arguments: optional base branch, ticket directive, ticket reference, skip directive, or additional context +- expected tools: the same as `/pr/create`; inline execution does not skip mutable repository or GitHub state + ### `/pr/fix` Addresses PR feedback or CI failures by making fixes and responding to review threads. @@ -156,13 +188,13 @@ Addresses PR feedback or CI failures by making fixes and responding to review th - arguments: optional PR ref, `auto`, or additional fix guidance - expected tools: `pr_load`, file-edit tools, validation commands, `question` unless `auto`, `git push`, `pr_sync` -### `/loop/pr/fix` +### `/pr/fix/loop` -Watches PR CI and comments, then repeatedly delegates non-interactive CI and feedback fixes through `/pr/fix auto` until no actionable work remains. +Watches PR CI and incrementally loads review activity, then repeatedly applies the shared non-interactive fix phase until no actionable work remains. -- usage: `/loop/pr/fix [pr-or-context]` +- usage: `/pr/fix/loop [pr-or-context]` - arguments: optional PR ref, CI guidance, or fix scope constraints -- expected tools: `pr_load`, `gh pr checks --watch`, `command_expansion(pr/fix)` +- expected tools: `pr_load`, `pr_load_review`, `gh pr checks --watch`, validation commands, `pr_sync` ### `/pr/review` @@ -192,11 +224,19 @@ Implements a feature or fix, validates the result, and prepares a PR handoff. ### `/ship` -Ships current work by delegating branch creation, commit creation, and PR creation. +Ships current work through inline branch, commit, and PR phases. - usage: `/ship [context]` - arguments: optional base branch, branch naming guidance, or additional shipping context -- expected tools: `command_expansion(branch)`, `command_expansion(commit)`, `command_expansion(pr/create)` +- expected tools: `changes_load`, `ticket_sync`, `pr_sync` + +### `/ship/inline` + +Ships current work in the invoking session, reusing known uncommitted-change context for branch naming and commit creation before loading the post-commit PR comparison. + +- usage: `/ship/inline [context]` +- arguments: optional base branch, branch naming guidance, or additional shipping context +- expected tools: `changes_load` for the post-commit comparison, `ticket_sync`, `pr_sync` ### `/todo` @@ -204,4 +244,4 @@ Works through a todo file one pending item at a time with planning, approval, im - usage: `/todo [@todo-file]` - arguments: optional `@file` reference and execution guidance; defaults to `@TODO.md` -- expected tools: `read`, `question`, `command_expansion(ticket/plan)`, `command_expansion(dev)`, `command_expansion(commit)` +- expected tools: `read`, `question`, `changes_load`, validation and git commands diff --git a/packages/web/src/content/docs/docs/reference/commands/pr-create.mdx b/packages/web/src/content/docs/docs/reference/commands/pr-create.mdx index 6a5a597..2face61 100644 --- a/packages/web/src/content/docs/docs/reference/commands/pr-create.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/pr-create.mdx @@ -11,8 +11,11 @@ Use `/pr/create` to move current branch work into a reviewable pull request. ```text /pr/create [base-or-ticket-context] +/pr/create/inline [base-or-ticket-context] ``` +Use `/pr/create/inline` to retain the invoking session for PR intent and wording. It still calls `changes_load` because the final base, commit graph, and diff must come from authoritative repository state. + ## Typical flow - load branch changes against the base branch diff --git a/packages/web/src/content/docs/docs/reference/commands/loop-pr-fix.mdx b/packages/web/src/content/docs/docs/reference/commands/pr-fix-loop.mdx similarity index 62% rename from packages/web/src/content/docs/docs/reference/commands/loop-pr-fix.mdx rename to packages/web/src/content/docs/docs/reference/commands/pr-fix-loop.mdx index a92a51c..b1312cb 100644 --- a/packages/web/src/content/docs/docs/reference/commands/loop-pr-fix.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/pr-fix-loop.mdx @@ -1,20 +1,21 @@ --- -title: /loop/pr/fix +title: /pr/fix/loop description: Watch PR CI and comments, repeatedly fixing both without approval prompts. --- -Use `/loop/pr/fix` when a PR should be advanced hands-off until both CI and review feedback are clean. +Use `/pr/fix/loop` when a PR should be advanced hands-off until both CI and review feedback are clean. ```text -/loop/pr/fix [pr-or-context] +/pr/fix/loop [pr-or-context] ``` ## Behavior - loads the PR and stores the PR URL and number - watches `gh pr checks --watch` until the latest checks finish -- reloads the PR after checks finish -- delegates actionable CI failures and PR feedback to `/pr/fix auto` +- loads review activity after the previous `loadedAt` checkpoint +- applies the shared non-interactive PR-fix phase inline +- updates the PR branch from its base when it is behind - repeats after each push until no actionable CI failures or PR feedback remain - stops on failing validation, failed push, failed PR replies, or no-change feedback loops diff --git a/packages/web/src/content/docs/docs/reference/commands/pr-fix.mdx b/packages/web/src/content/docs/docs/reference/commands/pr-fix.mdx index d9dcca0..9f5e0b8 100644 --- a/packages/web/src/content/docs/docs/reference/commands/pr-fix.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/pr-fix.mdx @@ -16,9 +16,10 @@ Use `/pr/fix` when a PR already exists and review feedback or CI failures need a ## Typical flow - load the PR and existing review state +- check out the PR branch, fetch its base, and merge and push the base when the branch is behind - implement the requested review or CI fixes on the current branch - run relevant validation -- in default mode, show the fix summary and wait for user approval before commit, push, or replies +- in default mode, show the fix summary and wait for user approval before committing or pushing fix changes or replying; required base alignment is applied first - skip that approval loop only with `/pr/fix auto` - push the updated branch and reply in the relevant review threads after commit succeeds diff --git a/packages/web/src/content/docs/docs/reference/commands/ship.mdx b/packages/web/src/content/docs/docs/reference/commands/ship.mdx index d16a483..6927e87 100644 --- a/packages/web/src/content/docs/docs/reference/commands/ship.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/ship.mdx @@ -5,22 +5,26 @@ description: Move current work through branch, commit, and PR creation as a fast ## Purpose -Use `/ship` when you want a fast path from current work to a PR through local orchestration and delegated command steps. +Use `/ship` when you want a fast path from current work to a PR in one stateful workflow. ## Usage ```text /ship [base-or-context] +/ship/inline [base-or-context] ``` +Use `/ship/inline` to run in the invoking session with `subtask: false`. It reuses known uncommitted-change context for branch and commit phases, while still loading the post-commit branch comparison required to create the PR. + ## Typical flow - ensure there is a suitable work branch -- expand and delegate `branch`, `commit`, and `pr/create` +- load uncommitted changes once for branch naming and commit creation +- reload the committed branch comparison only when preparing the PR - stop on blockers and report `Nothing to ship` when PR creation finds no shippable work ## Common tools -- `command_expansion(worker, branch)` -- `command_expansion(worker, commit)` -- `command_expansion(worker, pr/create)` +- `changes_load` +- `ticket_sync` +- `pr_sync` diff --git a/packages/web/src/content/docs/docs/reference/commands/ticket-dev.mdx b/packages/web/src/content/docs/docs/reference/commands/ticket-dev.mdx index 07fe3f4..6510df6 100644 --- a/packages/web/src/content/docs/docs/reference/commands/ticket-dev.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/ticket-dev.mdx @@ -5,7 +5,7 @@ description: Implement a ticket by orchestrating development, branching, commit- ## Purpose -Use `/ticket/dev` when implementation starts from a tracked ticket and should run through a navigator-led shipping flow with delegated command steps. +Use `/ticket/dev` when implementation starts from a tracked ticket and should run through one stateful shipping flow. ## Usage @@ -16,15 +16,13 @@ Use `/ticket/dev` when implementation starts from a tracked ticket and should ru ## Typical flow - load the ticket and its surrounding context -- expand and delegate `dev` for implementation and validation -- expand and delegate `branch` for branch naming from the ticket summary -- expand and delegate `commit-and-push` -- expand and delegate `pr/create` as the next shipping step +- implement and validate the ticket +- load uncommitted changes once for branch naming and commit creation +- push and create the PR from the committed branch comparison ## Common tools - `ticket_load` -- `command_expansion(worker, dev)` -- `command_expansion(worker, branch)` -- `command_expansion(worker, commit-and-push)` -- `command_expansion(worker, pr/create)` +- `ticket_load` +- `changes_load` +- `pr_sync` diff --git a/packages/web/src/content/docs/docs/reference/commands/todo.mdx b/packages/web/src/content/docs/docs/reference/commands/todo.mdx index 7b59520..b271019 100644 --- a/packages/web/src/content/docs/docs/reference/commands/todo.mdx +++ b/packages/web/src/content/docs/docs/reference/commands/todo.mdx @@ -5,7 +5,7 @@ description: Work through a todo file one item at a time with planning, approval ## Purpose -Use `/todo` for structured pause-and-resume work from a checklist file with explicit planning, approval, and delegated implementation steps. +Use `/todo` for structured pause-and-resume work from a checklist file with explicit planning, approval, and implementation steps. ## Usage @@ -17,14 +17,13 @@ Use `/todo` for structured pause-and-resume work from a checklist file with expl - load `@TODO.md` by default or a provided `@file` - take the first unchecked item only -- expand and delegate `ticket/plan`, show the plan, and require explicit approval before implementation -- expand and delegate `dev`, then `commit`, then mark the checklist item complete +- plan the current task, show the plan, and require explicit approval before implementation +- implement, validate, commit, then mark the checklist item complete - repeat until there are no pending tasks left ## Common tools - `read` - `question` -- `command_expansion(planner, ticket/plan)` -- `command_expansion(worker, dev)` -- `command_expansion(worker, commit)` +- `question` +- `changes_load` diff --git a/packages/web/src/content/docs/docs/reference/components/change-summary.mdx b/packages/web/src/content/docs/docs/reference/components/change-summary.mdx index a3a9499..4d054ed 100644 --- a/packages/web/src/content/docs/docs/reference/components/change-summary.mdx +++ b/packages/web/src/content/docs/docs/reference/components/change-summary.mdx @@ -5,8 +5,9 @@ description: Shared partial for loading changes and summarizing them into themes ## Behavior -- calls `changes_load` +- calls `changes_load` unless `it.load` is `false` - accepts optional extra rules through `it.rules` - stores the result as `` -- analyzes paths, statuses, and diffs +- analyzes comparison metadata, commits, paths, statuses, and diffs +- can analyze a comparison loaded by an earlier workflow phase - groups related work into concise what/why themes diff --git a/packages/web/src/content/docs/docs/reference/components/index.mdx b/packages/web/src/content/docs/docs/reference/components/index.mdx index b756ad4..f3064c1 100644 --- a/packages/web/src/content/docs/docs/reference/components/index.mdx +++ b/packages/web/src/content/docs/docs/reference/components/index.mdx @@ -8,19 +8,28 @@ Kompass command templates can include reusable Eta partials from `packages/core/ Bundled components: - `change-summary` +- `branch` - `changes-summary` - `commit` - `dev-flow` - `load-pr` - `load-ticket` +- `pr-create` +- `pr-branch-update` +- `pr-fix` +- `push` - `skill-authoring` -- `summarize-changes` +- `ticket-planning` ## Bundled components ### `change-summary` -Loads changes with `changes_load`, analyzes file-level diffs, and groups the work into concise what/why themes. +Loads changes with `changes_load` when needed, analyzes comparison metadata, commits, and file-level diffs, and groups the work into concise what/why themes. + +### `branch` + +Checks whether the active branch is suitable and creates a categorized work branch from already loaded change context when needed. ### `changes-summary` @@ -42,10 +51,26 @@ Loads PR context through `pr_load` and treats returned discussion, review histor Loads ticket context through `ticket_load`, with optional comments, and treats returned discussion and relevant attachments as source context. +### `pr-create` + +Checks PR blockers, resolves ticket handling, pushes the branch, and creates or finds the pull request from already loaded branch changes. + +### `pr-branch-update` + +Checks out the PR branch, fetches its base, confirms base ancestry, and merges and pushes the base without rebasing or force-pushing when the PR branch is behind. + +### `pr-fix` + +Analyzes feedback, applies and validates fixes, commits, pushes, and responds after the caller aligns the PR branch. Callers select interactive or automatic review behavior. + +### `push` + +Pushes the current branch and sets its upstream when necessary. + ### `skill-authoring` Provides the shared authoring rules for skill-focused commands, including scope, trigger-description quality, progressive disclosure, and validation expectations. -### `summarize-changes` +### `ticket-planning` -Guides commands to inspect comparison metadata, commit history, and changed files before grouping the work into themes. +Interprets ticket-planning arguments, loads request context, inspects the repository, and shapes a grounded implementation and validation plan. diff --git a/packages/web/src/content/docs/docs/reference/components/summarize-changes.mdx b/packages/web/src/content/docs/docs/reference/components/summarize-changes.mdx deleted file mode 100644 index a3b9df1..0000000 --- a/packages/web/src/content/docs/docs/reference/components/summarize-changes.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: summarize-changes -description: Shared guidance block for reading change context before final summaries. ---- - -## Behavior - -- notes comparison mode, base branch, and current branch -- reviews commit messages when they are available -- reads the most relevant changed files for real context -- groups related work into themes for the final summary diff --git a/packages/web/src/content/docs/docs/reference/components/ticket-planning.mdx b/packages/web/src/content/docs/docs/reference/components/ticket-planning.mdx new file mode 100644 index 0000000..4c5a7fc --- /dev/null +++ b/packages/web/src/content/docs/docs/reference/components/ticket-planning.mdx @@ -0,0 +1,12 @@ +--- +title: ticket-planning +description: Shared partial for grounding ticket plans in request and repository context. +--- + +## Behavior + +- interprets ticket references, requests, and additional planning context +- loads ticket context, including comments, when a ticket is provided +- inspects relevant repository code, config, schema, and tests +- preserves operative constraints and valid technical direction +- produces implementation and validation checklist items diff --git a/packages/web/src/content/docs/docs/reference/tools/command-expansion.mdx b/packages/web/src/content/docs/docs/reference/tools/command-expansion.mdx deleted file mode 100644 index 7b3e73c..0000000 --- a/packages/web/src/content/docs/docs/reference/tools/command-expansion.mdx +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: command_expansion -description: Resolve an explicit command plus body into a runnable delegated prompt. ---- - -## Purpose - -Use `command_expansion` when a workflow should expand another Kompass command into a concrete prompt before delegating it through `task`. - -## Inputs - -- `command`: command name without the leading slash -- `body`: literal body content from the `` block - -## Behavior - -- resolves the command template from the bundled command set -- substitutes `$ARGUMENTS` and positional placeholders from `body` -- prefixes Kompass tool references for the active adapter when needed -- returns the fully expanded prompt text for the delegated command - -## Typical use - -```xml - -auth bug - -``` - -This expands the equivalent of the `/review` command with `auth bug` as the body content so a navigator can pass the returned prompt into `task`. The `` tag's `agent` value remains the routing source of truth. diff --git a/packages/web/src/content/docs/docs/reference/tools/index.mdx b/packages/web/src/content/docs/docs/reference/tools/index.mdx index 99fde34..e0d0b36 100644 --- a/packages/web/src/content/docs/docs/reference/tools/index.mdx +++ b/packages/web/src/content/docs/docs/reference/tools/index.mdx @@ -8,8 +8,8 @@ Kompass uses structured tools to keep workflows grounded in repository and GitHu Current built-in tools: - `changes_load` -- `command_expansion` - `pr_load` +- `pr_load_review` - `pr_sync` - `ticket_load` - `ticket_sync` @@ -20,14 +20,14 @@ Current built-in tools: Loads either uncommitted worktree changes or a base/head git comparison, returning structured file diffs and optional commit metadata. -### `command_expansion` - -Resolves an explicit command plus body into a rendered prompt so a navigator can delegate it immediately through `task`. - ### `pr_load` Loads normalized PR metadata, review history, issue comments, review threads, repo identity, and viewer identity from GitHub. +### `pr_load_review` + +Loads reviews, issue comments, and complete review threads changed after an exclusive ISO-8601 checkpoint. It returns a new `loadedAt` checkpoint for polling loops. + ### `pr_sync` Creates PRs, updates PR metadata, posts comments and replies, and submits formal reviews against an existing PR. diff --git a/packages/web/src/content/docs/docs/reference/tools/pr-load-review.mdx b/packages/web/src/content/docs/docs/reference/tools/pr-load-review.mdx new file mode 100644 index 0000000..a1983a0 --- /dev/null +++ b/packages/web/src/content/docs/docs/reference/tools/pr-load-review.mdx @@ -0,0 +1,20 @@ +--- +title: pr_load_review +description: Incrementally load PR review activity after a checkpoint. +--- + +Use `pr_load_review` after an initial `pr_load` when a long-running workflow only needs new or updated review activity. + +## Inputs + +- `pr`: optional PR number or URL +- `since`: required exclusive ISO-8601 timestamp, usually the previous result's `loadedAt` + +## Behavior + +- filters formal reviews by submission time +- asks GitHub for issue comments updated since the checkpoint +- returns a whole review thread when any comment in it changed after the checkpoint +- returns `loadedAt` for the next call + +GitHub does not expose a timestamp filter for review-thread resolution changes, so resolution-only changes without comment activity are not detectable incrementally. diff --git a/packages/web/src/content/docs/docs/reference/tools/pr-load.mdx b/packages/web/src/content/docs/docs/reference/tools/pr-load.mdx index c3c6649..5ade503 100644 --- a/packages/web/src/content/docs/docs/reference/tools/pr-load.mdx +++ b/packages/web/src/content/docs/docs/reference/tools/pr-load.mdx @@ -24,4 +24,4 @@ Use `pr_load` when a workflow needs one grounded PR context payload instead of s - `/pr/review` - `/pr/fix` -- `/loop/pr/fix` +- `/pr/fix/loop`