jorgex-stack 1.0.27 → 1.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +28 -3
- package/package.json +1 -1
- package/stack/agents/orchestrator.md +29 -11
- package/stack/commands/claude-code/xreview.md +5 -0
- package/stack/commands/opencode/xreview.md +5 -0
- package/stack/hooks/hooks.json +1 -1
- package/stack/scripts/post-pr-review.cjs +103 -120
- package/stack/skills/work-lifecycle/SKILL.md +12 -0
- package/stack/skills/work-lifecycle/references/plan-template.md +2 -0
- package/stack/{commands/xreview.md → skills/xreview/SKILL.md} +9 -8
- package/stack/system-prompt/AGENTS.md +6 -1
package/dist/cli.js
CHANGED
|
@@ -591,9 +591,34 @@ ${agent.body}`,
|
|
|
591
591
|
}
|
|
592
592
|
const hooksFile = path7.join(ctx.configDir, "hooks.json");
|
|
593
593
|
const content = upsertJson(readTextIfExists(hooksFile), (root) => {
|
|
594
|
-
const
|
|
595
|
-
|
|
594
|
+
const afterValue = root["tool.execute.after"] ??= {};
|
|
595
|
+
if (afterValue === null || typeof afterValue !== "object" || Array.isArray(afterValue)) {
|
|
596
|
+
ctx.warnings.push("opencode: tool.execute.after no es un objeto; hooks gestionados omitidos.");
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const after = afterValue;
|
|
600
|
+
const bashValue = after["bash"];
|
|
601
|
+
if (bashValue !== void 0 && !Array.isArray(bashValue) && (bashValue === null || typeof bashValue !== "object")) {
|
|
602
|
+
ctx.warnings.push("opencode: tool.execute.after.bash no es un array ni un mapa; hooks gestionados omitidos.");
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const bash = Array.isArray(bashValue) ? { "*": bashValue } : bashValue ?? {};
|
|
606
|
+
after["bash"] = bash;
|
|
607
|
+
const managedScripts = new Set(Object.values(bashEntries).flat());
|
|
608
|
+
for (const [includes, scripts] of Object.entries(bash)) {
|
|
609
|
+
if (!Array.isArray(scripts)) continue;
|
|
610
|
+
const preserved = scripts.filter(
|
|
611
|
+
(script) => typeof script !== "string" || !managedScripts.has(script)
|
|
612
|
+
);
|
|
613
|
+
if (preserved.length > 0) bash[includes] = preserved;
|
|
614
|
+
else delete bash[includes];
|
|
615
|
+
}
|
|
596
616
|
for (const [includes, scripts] of Object.entries(bashEntries)) {
|
|
617
|
+
const current = bash[includes];
|
|
618
|
+
if (current !== void 0 && !Array.isArray(current)) {
|
|
619
|
+
ctx.warnings.push(`opencode: trigger bash '${includes}' no es un array; hook gestionado omitido.`);
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
597
622
|
const list = bash[includes] ??= [];
|
|
598
623
|
for (const s of scripts) if (!list.includes(s)) list.push(s);
|
|
599
624
|
}
|
|
@@ -2084,7 +2109,7 @@ async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
|
|
|
2084
2109
|
import fs18 from "fs";
|
|
2085
2110
|
import path23 from "path";
|
|
2086
2111
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
2087
|
-
var PROTECTED_SKILLS = /* @__PURE__ */ new Set(["agent-delegation", "work-lifecycle"]);
|
|
2112
|
+
var PROTECTED_SKILLS = /* @__PURE__ */ new Set(["agent-delegation", "work-lifecycle", "xreview"]);
|
|
2088
2113
|
function sameTextContentNormalized(a, b) {
|
|
2089
2114
|
const ba = fs18.readFileSync(a);
|
|
2090
2115
|
const bb = fs18.readFileSync(b);
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@ INIT → EXPLORE → SPEC → PLAN → EXECUTE → VERIFY → SHIP → CLOSE
|
|
|
19
19
|
|
|
20
20
|
### Autonomy
|
|
21
21
|
|
|
22
|
-
The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no confirmation pauses: plan approval authorizes commits, pushes to the work branch and the
|
|
22
|
+
The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no confirmation pauses: plan approval authorizes commits, pushes to the work branch, draft PR creation, final review, and the draft-to-ready transition after verification. Task-critical uncertainty from a subagent is an operational blocker, not a pause in autonomy: answer from existing context first; only if the decision genuinely cannot be made from available context may you ask the user, then relaunch with explicit guidance. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order. For multi-PR work, each merge is a checkpoint; keep `work/{name}/PRD.md` and `plan.md` alive until the roadmap is finished. Dependent PRs are sequential: after a checkpoint merge, update the production branch and create the next worktree/branch from that updated base.
|
|
23
23
|
|
|
24
24
|
## 1. INIT
|
|
25
25
|
|
|
@@ -48,12 +48,10 @@ Once a task crosses any of these thresholds, delegating stops being optional:
|
|
|
48
48
|
| Trigger | Expected behavior |
|
|
49
49
|
| --- | --- |
|
|
50
50
|
| Reading 4+ files just to understand a flow | Delegate exploration to the matching analyst. |
|
|
51
|
-
| Touching 2+ non-trivial files | One writer (`implementer`) per scope; fresh `code-reviewer` pass before closing. |
|
|
52
|
-
| Commit, push or PR after code changes | Run `code-reviewer` on the diff unless it is trivial docs/text. |
|
|
53
51
|
| Wrong cwd, git/worktree accident, confusing test or env failure | Stop; re-explore with fresh context before continuing. |
|
|
54
52
|
| Long session with accumulating complexity | Pause and re-plan or delegate — or state explicitly why not. |
|
|
55
53
|
|
|
56
|
-
The goal is not ceremony: it is one responsible coordinator, one writer per scope, and fresh eyes
|
|
54
|
+
The goal is not ceremony: it is one responsible coordinator, one writer per scope, deterministic feedback while the diff is evolving, and fresh eyes at the PR boundary.
|
|
57
55
|
|
|
58
56
|
## 3. SPEC
|
|
59
57
|
|
|
@@ -109,6 +107,7 @@ Load the `agent-delegation` skill: it defines the available subagents, the scope
|
|
|
109
107
|
Every subagent ends with a **Result contract** (Status / Delegations / Risks). Process it:
|
|
110
108
|
|
|
111
109
|
- For each `→ [agent]: ...` line, launch the corresponding specialist.
|
|
110
|
+
- A delegation is unfinished work in another scope, not a request to append a generic quality pipeline. Normal handoffs between `implementer` and `tester` do not by themselves justify reviewers or analyzers.
|
|
112
111
|
- If a subagent reports `partial`, keep the safe work and relaunch only what still needs guidance.
|
|
113
112
|
- If a subagent reports `blocked` with one concrete uncertainty question, answer it from existing context when possible; if it still cannot be resolved, ask the user only if genuinely necessary, then relaunch the original or a suitable specialist with explicit guidance.
|
|
114
113
|
- Don't declare a phase done while a delegation line remains unprocessed.
|
|
@@ -128,6 +127,12 @@ Every delegation prompt must state the worktree path as the ONLY allowed write r
|
|
|
128
127
|
|
|
129
128
|
Commit after each task or bounded group of tasks, with a message that reflects that task — the branch history must map to the plan. Never accumulate the whole work into one giant commit at the end.
|
|
130
129
|
|
|
130
|
+
### Draft PR cadence
|
|
131
|
+
|
|
132
|
+
- After the first coherent commit, push the branch and create the PR against its real base with `gh pr create --draft`. Do not wait until SHIP to open it.
|
|
133
|
+
- Keep every code change, commit and push inside the draft phase. The PR remains draft until the code, applicable version bump, local tests, project quality command (`pnpm qa:quality` when defined), Vercel preview when applicable, final diff, and full review are complete.
|
|
134
|
+
- Never push to a ready PR. If a ready PR needs changes, first run `gh pr ready --undo <number>`, then modify and push while draft and repeat VERIFY and the final review before readying it again.
|
|
135
|
+
|
|
131
136
|
### Handoff rule
|
|
132
137
|
|
|
133
138
|
The analyst's **Recommendation** is the implementer's input. Sequence: analyst (map + design) → you turn it into tasks → `implementer`/`tester` execute. Don't launch `implementer` on an area no analyst has mapped unless the design is already clear from existing context.
|
|
@@ -152,15 +157,26 @@ implementer (direct change)
|
|
|
152
157
|
|
|
153
158
|
### Verification cadence
|
|
154
159
|
|
|
155
|
-
Verify by bounded, coherent sections (e.g. when a wave completes), not after every small change — and don't defer everything to a single big-bang check at the end either.
|
|
160
|
+
Deterministic checks are the routine feedback loop while implementation is in progress: run the relevant tests, lint and typecheck/build checks at the cheapest seam that can catch the section's regressions. Verify by bounded, coherent sections (e.g. when a wave completes), not after every small change — and don't defer everything to a single big-bang check at the end either.
|
|
161
|
+
|
|
162
|
+
Each writer verifies its own bounded area (e.g. its test file). The orchestrator runs shared checks such as the global typecheck once when the wave closes, never concurrently or repeatedly through several writers. Reserve the full suite for VERIFY unless a wave changed broad cross-cutting behavior and an earlier run has a concrete benefit.
|
|
163
|
+
|
|
164
|
+
### Early-review budget
|
|
165
|
+
|
|
166
|
+
An early review during EXECUTE is an **exception**, not a default phase. Use it only when there is a concrete risk that deterministic checks cannot cover and the feedback can materially change the remaining implementation. Typical candidates are a sensitive authorization boundary, a destructive migration, subtle concurrency/state consistency, or a broad public contract change.
|
|
156
167
|
|
|
157
|
-
|
|
168
|
+
- State the exact risk and the bounded diff section to inspect before launching anyone.
|
|
169
|
+
- Use the single most relevant specialist. Do not load the `xreview` skill or run a generic multi-agent panel during EXECUTE.
|
|
170
|
+
- Run at most one early review per bounded critical section, after that section is coherent rather than after each task inside it.
|
|
171
|
+
- Do not launch `code-reviewer`, `code-simplifier`, `test-analyzer` or `silent-failure-hunter` merely because a writer finished, a test task completed, several files changed or a commit is due.
|
|
172
|
+
- File count, writer completion, commit, push, or draft PR creation are not early-review triggers. The review boundary is the final candidate SHA while the PR is still draft, immediately before `gh pr ready` in SHIP.
|
|
158
173
|
|
|
159
174
|
## 6. VERIFY
|
|
160
175
|
|
|
161
176
|
- Validate against the plan's **Success criteria** in plan.md and tick the ones that pass. Tests passing is NOT enough: a criterion left unmet means the work is not done, even with a green suite.
|
|
162
177
|
- Run the minimum verification that is sufficient.
|
|
163
178
|
- Reserve heavy suites for cases where they provide real value or the project requires them.
|
|
179
|
+
- Before SHIP, ensure all applicable preflight work is complete: code, version bump, local tests, the project's quality command (`pnpm qa:quality` when defined), and Vercel preview review when the project uses Vercel. React Doctor is manual/local, never assumed to be a GitHub Actions gate.
|
|
164
180
|
- If something fails, go back to EXECUTE with fix tasks.
|
|
165
181
|
- **Anti-thrashing**: max 3 attempts per failing task or criterion. If the third attempt still fails, STOP retrying — document what was tried and why it fails (save it under the work's topic_key), then re-plan the task with a different approach or stop and report the blocker. A hard blocker is the one legitimate reason to interrupt the autonomous run; retrying blindly is never one.
|
|
166
182
|
|
|
@@ -168,18 +184,20 @@ In parallel waves, each writer's minimum verification is its own bounded area (e
|
|
|
168
184
|
|
|
169
185
|
When the plan is fully applied and VERIFY passes:
|
|
170
186
|
|
|
171
|
-
1.
|
|
172
|
-
2. Process the report by its three levels:
|
|
187
|
+
1. Confirm the draft PR exists, the worktree is clean, and the draft head matches the local HEAD. Inspect the final diff against the PR's real base.
|
|
188
|
+
2. Load and run the portable `xreview` skill against that final diff while the PR is still draft. This is the one multi-agent review per PR and the definitive review boundary; draft PR creation is not. Process the report by its three levels:
|
|
173
189
|
- **Critical Issues (must fix)**: apply ALL of them — the PR must not reach merge with these open.
|
|
174
190
|
- **Important Improvements (should fix)**: apply the ones worth doing now, at your judgment.
|
|
175
191
|
- **Suggestions (nice to have)**: apply only if trivial and safe.
|
|
176
192
|
3. Every finding you decide NOT to apply now goes to the project's `work/backlog` single topic_key — one line each: what + why deferred. Apply the safe serialized backlog protocol above; subagents only return candidate lines.
|
|
177
|
-
4. For what you DO apply: add the new tasks to plan.md and one `mem_save` per task spec, execute them as in EXECUTE, re-verify, and push the fixes
|
|
178
|
-
5.
|
|
193
|
+
4. For what you DO apply: add the new tasks to plan.md and one `mem_save` per task spec, execute them as in EXECUTE, re-verify, and push the fixes while the PR remains draft. Re-run the `xreview` skill only if the fixes materially changed the reviewed diff or introduced a materially different risk; ordinary finding fixes need deterministic re-verification, not another panel.
|
|
194
|
+
5. Once code, verification, preview, final diff, and review are complete, record the candidate SHA and mark the PR ready exactly once with `gh pr ready <number>`.
|
|
195
|
+
6. Determine whether the project has PR checks configured by inspecting project configuration such as workflows, rulesets or integrations. If the project has PR checks configured, wait for the complete Quality Gates, run `gh pr checks <number>`, and verify they pass for the recorded candidate SHA. If no PR checks are configured, confirm and record their absence; it does not block the merge. An empty `gh pr checks` result immediately after ready is not evidence that no checks are configured. In either case, do not push while the PR is ready. Immediately before reporting or merging, compare `gh pr view --json headRefOid` with the recorded candidate SHA.
|
|
196
|
+
7. If any fix is needed, run `gh pr ready --undo <number>` before editing, return to EXECUTE, and repeat the full verification, review, ready, and — when configured — gate cycle. Never treat checks from an older SHA as merge evidence.
|
|
179
197
|
|
|
180
198
|
## 8. CLOSE
|
|
181
199
|
|
|
182
|
-
- STOP here and hand control back to the user: report
|
|
200
|
+
- STOP here and hand control back to the user only after configured Quality Gates pass for the latest commit, or after confirming that the project has no PR checks configured: report the candidate SHA, check result or confirmed absence, review findings applied vs deferred to `work/backlog`, and whether manual testing is advisable (recommend it for big or user-facing changes; small well-tested changes may not need it).
|
|
183
201
|
- NEVER merge the PR yourself — merge only on an explicit user order. After each intermediate merge: persist the checkpoint to `work/{name}/pr/{NN}`, update `plan.md`, and keep `work/{name}/` alive. After the final merge: persist the final outcome to memory, clean up `work/{name}/` and remove the worktree (see Work state).
|
|
184
202
|
- If the repo has its own skill for the closing steps (release, deploy, git, cleanup), that skill takes precedence over the default behavior.
|
|
185
203
|
|
package/stack/hooks/hooks.json
CHANGED
|
@@ -1,158 +1,141 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Global PostToolUse
|
|
3
|
+
* Global PostToolUse guardrail for the PR draft → ready lifecycle.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* The historical filename is intentionally preserved so sync can migrate the
|
|
6
|
+
* existing hook entry instead of leaving an orphan in user configuration.
|
|
7
|
+
* The hook never infers success or PR state from command text: PostToolUse
|
|
8
|
+
* payloads are not consistent enough across runtimes to prove either.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
* Mirrors the `/xreview` command logic so both stay aligned: comment-fixer first
|
|
10
|
-
* (committed before the analysts), then the read-only analysts in parallel. 4R
|
|
11
|
-
* stays internal (Reliability / Resilience / Readability / Risk), not a separate
|
|
12
|
-
* report section, taxonomy, or extra agents.
|
|
13
|
-
*
|
|
14
|
-
* Payload compatibility (stdin JSON), so the same script works on every runtime:
|
|
10
|
+
* Payload compatibility (stdin JSON):
|
|
15
11
|
* - Claude Code hooks: { tool_name: "Bash", tool_input: { command: "..." }, cwd }
|
|
16
12
|
* - Codex hooks: { tool_name: "shell", tool_input: { command: [...] }, cwd }
|
|
17
13
|
* - OpenCode bridge: { tool: "bash", args: { command: "..." }, directory }
|
|
18
14
|
*
|
|
19
|
-
* Output
|
|
20
|
-
* - OpenCode bridge payload → plain message on stderr.
|
|
21
|
-
* - Claude Code / Codex payload → JSON additionalContext on stdout.
|
|
22
|
-
* Exit 0 always.
|
|
15
|
+
* Output uses one channel per runtime and the script always exits 0.
|
|
23
16
|
*/
|
|
24
17
|
|
|
25
|
-
const { execSync } = require('child_process');
|
|
26
|
-
const path = require('path');
|
|
27
|
-
|
|
28
|
-
const DEFAULT_BASE_BRANCH = 'main';
|
|
29
|
-
const BASE_BRANCH_SOURCE = Object.freeze({
|
|
30
|
-
GH: 'gh',
|
|
31
|
-
ORIGIN_HEAD: 'origin-head',
|
|
32
|
-
DEFAULT: 'default',
|
|
33
|
-
});
|
|
34
|
-
|
|
35
18
|
function writeWarning(message) {
|
|
36
19
|
process.stderr.write(`post-pr-review: warning: ${message}\n`);
|
|
37
20
|
}
|
|
38
21
|
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
22
|
+
function shellCommandSegments(command) {
|
|
23
|
+
const segments = [];
|
|
24
|
+
let tokens = [];
|
|
25
|
+
let token = "";
|
|
26
|
+
let quote = null;
|
|
27
|
+
let started = false;
|
|
28
|
+
|
|
29
|
+
const pushToken = () => {
|
|
30
|
+
if (!started) return;
|
|
31
|
+
tokens.push(token);
|
|
32
|
+
token = "";
|
|
33
|
+
started = false;
|
|
34
|
+
};
|
|
35
|
+
const pushSegment = () => {
|
|
36
|
+
pushToken();
|
|
37
|
+
if (tokens.length > 0) segments.push(tokens);
|
|
38
|
+
tokens = [];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
for (const character of command) {
|
|
42
|
+
if (quote !== null) {
|
|
43
|
+
if (character === quote) quote = null;
|
|
44
|
+
else token += character;
|
|
45
|
+
started = true;
|
|
46
|
+
} else if (character === '"' || character === "'") {
|
|
47
|
+
quote = character;
|
|
48
|
+
started = true;
|
|
49
|
+
} else if (character === "\r" || character === "\n") {
|
|
50
|
+
pushSegment();
|
|
51
|
+
} else if (/\s/.test(character)) {
|
|
52
|
+
pushToken();
|
|
53
|
+
} else if (character === ";" || character === "&" || character === "|") {
|
|
54
|
+
pushSegment();
|
|
55
|
+
} else {
|
|
56
|
+
token += character;
|
|
57
|
+
started = true;
|
|
58
|
+
}
|
|
55
59
|
}
|
|
60
|
+
pushSegment();
|
|
61
|
+
return segments;
|
|
62
|
+
}
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
};
|
|
64
|
+
function skipRepoOptions(tokens, start) {
|
|
65
|
+
let index = start;
|
|
66
|
+
while (index < tokens.length) {
|
|
67
|
+
const option = tokens[index];
|
|
68
|
+
if (option === "-R" || option === "--repo") {
|
|
69
|
+
if (tokens[index + 1] === undefined) return false;
|
|
70
|
+
index += 2;
|
|
71
|
+
} else if (/^(?:-R|--repo=).+/i.test(option)) {
|
|
72
|
+
index += 1;
|
|
73
|
+
} else {
|
|
74
|
+
break;
|
|
69
75
|
}
|
|
70
|
-
} catch {
|
|
71
|
-
// ignore
|
|
72
76
|
}
|
|
77
|
+
return index;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isLifecycleSegment(tokens) {
|
|
81
|
+
if (!/(?:^|[\\/])gh(?:\.exe)?$/i.test(tokens[0] ?? "")) return false;
|
|
82
|
+
|
|
83
|
+
let index = skipRepoOptions(tokens, 1);
|
|
84
|
+
if (tokens[index]?.toLowerCase() !== "pr") return false;
|
|
85
|
+
index = skipRepoOptions(tokens, index + 1);
|
|
73
86
|
|
|
74
|
-
|
|
87
|
+
const action = tokens[index]?.toLowerCase();
|
|
88
|
+
return action === "create" || action === "ready";
|
|
75
89
|
}
|
|
76
90
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
91
|
+
function isPrLifecycleCommand(command) {
|
|
92
|
+
const segments = Array.isArray(command)
|
|
93
|
+
? [command.map(String)]
|
|
94
|
+
: shellCommandSegments(String(command));
|
|
95
|
+
return segments.some(isLifecycleSegment);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const message = `<pr-lifecycle-state-required>
|
|
99
|
+
A \`gh pr create\` or \`gh pr ready\` command was attempted. Do not infer success or PR state from the command text. Resolve the current PR and run \`gh pr view --json number,isDraft,headRefOid\` before the next action.
|
|
100
|
+
|
|
101
|
+
- If the PR should still be under development, it must be draft. If it is ready, run \`gh pr ready --undo <number>\` before any change or push.
|
|
102
|
+
- While draft, finish code, the applicable version bump, local tests, \`pnpm qa:quality\` when defined, Vercel preview review when applicable, final diff inspection, and the full review on the candidate SHA.
|
|
103
|
+
- If the PR is actually ready, do not push. If the project has PR checks configured, wait for the complete Quality Gates, run \`gh pr checks <number>\`, and verify the checked headRefOid is the candidate SHA.
|
|
104
|
+
- If no PR checks are configured, confirm that from project configuration such as workflows, rulesets or integrations, and record it; their absence does not block the merge. An empty \`gh pr checks\` result immediately after ready is not evidence that no checks are configured.
|
|
105
|
+
- Immediately before reporting or merging, compare \`gh pr view --json headRefOid\` with the recorded candidate SHA. Merge still requires explicit user approval.
|
|
106
|
+
</pr-lifecycle-state-required>`;
|
|
107
|
+
|
|
108
|
+
let raw = "";
|
|
109
|
+
process.stdin.setEncoding("utf8");
|
|
110
|
+
process.stdin.on("data", (chunk) => (raw += chunk));
|
|
111
|
+
process.stdin.on("end", () => {
|
|
81
112
|
let data = {};
|
|
82
113
|
try {
|
|
83
|
-
data = JSON.parse(raw ||
|
|
114
|
+
data = JSON.parse(raw || "{}");
|
|
84
115
|
} catch {
|
|
85
|
-
writeWarning(
|
|
116
|
+
writeWarning("invalid JSON payload; skipping PR lifecycle hook.");
|
|
86
117
|
process.exit(0);
|
|
87
118
|
}
|
|
88
119
|
|
|
89
|
-
const toolName = String(data.tool_name || data.tool ||
|
|
90
|
-
const
|
|
91
|
-
const commandValue = data?.tool_input?.command ?? data?.args?.command ??
|
|
92
|
-
|
|
93
|
-
const rawToolCommand = Array.isArray(commandValue) ? commandValue.join(' ') : String(commandValue);
|
|
94
|
-
const toolCommand = rawToolCommand.toLowerCase();
|
|
95
|
-
|
|
96
|
-
if (!SHELL_TOOLS.includes(toolName) || !toolCommand.includes('gh pr create')) {
|
|
120
|
+
const toolName = String(data.tool_name || data.tool || "").toLowerCase();
|
|
121
|
+
const shellTools = ["bash", "shell", "local_shell", "powershell"];
|
|
122
|
+
const commandValue = data?.tool_input?.command ?? data?.args?.command ?? "";
|
|
123
|
+
if (!shellTools.includes(toolName) || !isPrLifecycleCommand(commandValue)) {
|
|
97
124
|
process.exit(0);
|
|
98
125
|
}
|
|
99
126
|
|
|
100
|
-
const scriptDir = __dirname;
|
|
101
|
-
const projectDir = data.cwd || data.directory || path.resolve(scriptDir, '..');
|
|
102
|
-
const resolution = resolveBaseBranch(projectDir);
|
|
103
|
-
const baseBranch = resolution.branch;
|
|
104
|
-
const baseRef = formatGitRef(baseBranch);
|
|
105
|
-
const diffScope = `git diff ${baseRef}...HEAD`;
|
|
106
|
-
const isConfirmed = resolution.source === BASE_BRANCH_SOURCE.GH;
|
|
107
|
-
const baseSummary = isConfirmed
|
|
108
|
-
? `BASE (PR target, confirmed via gh pr view): ${baseBranch}`
|
|
109
|
-
: `BASE (PR target, NOT confirmed — fallback guess): ${baseBranch}. Before anything else, re-resolve it yourself: run \`gh pr view --json baseRefName --jq .baseRefName\` (the PR exists now; this hook may have raced its creation) and use THAT as BASE. Keep ${baseBranch} only if it still fails. Work is often done in sub-branches whose PR does NOT target the default branch — reviewing against the wrong BASE produces a huge, useless diff.`;
|
|
110
|
-
|
|
111
|
-
const message = `<post-pr-review-required>
|
|
112
|
-
A PR was just created. Run a conditional multi-agent review BEFORE reporting back to the user.
|
|
113
|
-
|
|
114
|
-
${baseSummary}
|
|
115
|
-
HEAD: the current branch / worktree (resolve with \`git rev-parse --abbrev-ref HEAD\`).
|
|
116
|
-
|
|
117
|
-
1. Routing only (lightweight): list changed file NAMES with \`${diffScope} --name-only\` to decide which subagents apply. Do NOT load the full diff into your own context.
|
|
118
|
-
|
|
119
|
-
Sanity check: if that list is far larger than the work just done (hundreds of files, unrelated areas), BASE is almost certainly wrong — STOP, re-resolve the PR base with \`gh pr view\`, and only continue when the diff matches the actual work.
|
|
120
|
-
|
|
121
|
-
2. Comment pass FIRST (conditional): if the diff adds or changes comments/docstrings, run comment-fixer ALONE before the analysts — it edits comments in place (comments only, never code). If it changed anything, comment-fixer itself never commits — YOU commit its fixes to the PR branch BEFORE launching the analysts, staging ONLY the files it touched (never -a/-A: don't sweep unrelated working-tree changes), so the diff they fetch is already clean of comment noise; push them together with whatever the review produces, or on their own if nothing else needs fixing. If the commit can't be made, leave the edits uncommitted and say so in the report. If the diff touches no comments, skip it.
|
|
122
|
-
|
|
123
|
-
3. The remaining subagents are CONDITIONAL, read-only, and each fetches its OWN diff. Launch in PARALLEL (with your runtime's delegation mechanism) ONLY the relevant ones, passing each EXACTLY the BASE and HEAD branches and the instruction: review only \`${diffScope}\` — never assume \`main\`, use the BASE/HEAD given.
|
|
124
|
-
- test-analyzer — only if the diff touches tests or code that should be tested
|
|
125
|
-
- silent-failure-hunter — only if the diff includes error handling, try/catch, fallbacks, or async flows
|
|
126
|
-
- type-design-analyzer — only if the diff changes types, interfaces, schemas, or public contracts
|
|
127
|
-
- code-reviewer — for general code quality whenever non-trivial source code changed
|
|
128
|
-
- code-simplifier — only if the diff introduces complexity worth simplifying; this is the lean/anti-bloat pass for diffs and PRs
|
|
129
|
-
- security-auditor — only if the diff touches auth, authorization, permissions, secrets/credentials, sensitive data, input validation, webhooks, or other security-critical flows
|
|
130
|
-
|
|
131
|
-
If none of a subagent's triggers are present, skip it. Always state which subagents ran and which were skipped and why.
|
|
132
|
-
|
|
133
|
-
4. After the relevant subagents complete, synthesize a unified report:
|
|
134
|
-
Use 4R internally (Reliability / Resilience / Readability / Risk) as a checklist while synthesizing; do not add a separate 4R section or taxonomy to the final report.
|
|
135
|
-
- BASE and HEAD used
|
|
136
|
-
- Subagents run vs skipped (with reason)
|
|
137
|
-
- Critical Issues (must fix)
|
|
138
|
-
- Important Improvements (should fix)
|
|
139
|
-
- Suggestions (nice to have)
|
|
140
|
-
- Changes already applied (comment fixes: committed to the PR branch, or left uncommitted for working-tree reviews)
|
|
141
|
-
- Positive Findings
|
|
142
|
-
</post-pr-review-required>`;
|
|
143
|
-
|
|
144
|
-
// Un solo canal por runtime: el bridge de OpenCode recoge stdout Y stderr,
|
|
145
|
-
// así que emitir por ambos duplicaría el mensaje.
|
|
146
127
|
const isOpenCodeBridge = data.tool !== undefined && data.tool_name === undefined;
|
|
147
128
|
if (isOpenCodeBridge) {
|
|
148
|
-
process.stderr.write(message
|
|
129
|
+
process.stderr.write(`${message}\n`);
|
|
149
130
|
} else {
|
|
150
|
-
// Claude Code / Codex PostToolUse leen additionalContext del stdout JSON.
|
|
151
131
|
process.stdout.write(
|
|
152
|
-
JSON.stringify({
|
|
132
|
+
`${JSON.stringify({
|
|
153
133
|
additionalContext: message,
|
|
154
|
-
hookSpecificOutput: {
|
|
155
|
-
|
|
134
|
+
hookSpecificOutput: {
|
|
135
|
+
hookEventName: "PostToolUse",
|
|
136
|
+
additionalContext: message,
|
|
137
|
+
},
|
|
138
|
+
})}\n`,
|
|
156
139
|
);
|
|
157
140
|
}
|
|
158
141
|
process.exit(0);
|
|
@@ -41,6 +41,18 @@ Every piece of work gets a **canonical kebab-case name** when it starts (e.g. `c
|
|
|
41
41
|
- Task status lives ONLY in the task table: flip it (⬜ → ✅) with a surgical edit when the task closes. PR status/evidence lives ONLY in the PR roadmap table. Do not mirror task progress into memory, and do not re-read the whole plan after every task — it is already in context; re-read it on resume.
|
|
42
42
|
- For multi-PR work, resume from the first PR/task not done in the roadmap/table. For single-PR work, the canonical name worktree/branch is enough and the roadmap collapses to one checkpoint.
|
|
43
43
|
|
|
44
|
+
## Pull request lifecycle
|
|
45
|
+
|
|
46
|
+
1. Start from the updated production branch in the canonical worktree/branch. Keep one concrete objective per PR.
|
|
47
|
+
2. Implement one coherent first slice, commit it, push the work branch, and open the PR immediately as draft with `gh pr create --draft`.
|
|
48
|
+
3. Continue implementation, commits and pushes only while the PR is draft. Draft means the code can still change; ready means the current SHA is the candidate to merge.
|
|
49
|
+
4. Before ready, complete every applicable preflight item: code, version bump, local tests, project quality command (`pnpm qa:quality` when defined), Vercel preview review when the project uses Vercel, final diff inspection, and full PR review.
|
|
50
|
+
5. Mark ready once with `gh pr ready <number>`. If the project has PR checks configured, wait for Quality Gates, run `gh pr checks <number>`, and verify the checks belong to the latest commit. If no PR checks are configured, confirm that from project configuration such as workflows, rulesets or integrations, and record it; their absence does not block the merge. An empty `gh pr checks` result immediately after ready is not evidence that no checks are configured. Immediately before reporting or merging, compare `gh pr view --json headRefOid` with the recorded candidate SHA.
|
|
51
|
+
6. Never push to a ready PR. If it needs changes, first run `gh pr ready --undo <number>`, then modify and push while draft, repeat preflight and review, mark ready again, and wait for a fresh complete gate when checks are configured.
|
|
52
|
+
7. Merge only after explicit user approval. When PR checks are configured, their passing result must match the current candidate SHA.
|
|
53
|
+
|
|
54
|
+
Dependent PRs are sequential: merge one checkpoint, update the production branch, then create the next worktree/branch from that updated base. Do not stack a dependent PR from an unmerged work branch unless the human explicitly chooses a stacked-PR strategy.
|
|
55
|
+
|
|
44
56
|
## HTML review view (on demand)
|
|
45
57
|
|
|
46
58
|
When presenting the PRD or the plan for human review on non-trivial work, OFFER a disposable HTML view (e.g. side-by-side approach comparison for the PRD, task table + dependency graph for the plan). Rules:
|
|
@@ -41,6 +41,8 @@ The full spec of each task is NOT a file: it lives in Engram, one observation pe
|
|
|
41
41
|
> This is the live PR-level board: scope, PR status, and merge evidence live here.
|
|
42
42
|
> Task-level status stays in the task table below.
|
|
43
43
|
> Full checkpoint history lives in Engram under `work/[name]/pr/[NN]`.
|
|
44
|
+
> PR status advances: ⬜ Pending → 📝 Draft → 🔍 Reviewed → ⏳ Ready / gates when configured → ✅ Merged.
|
|
45
|
+
> If a ready PR changes, return it to Draft with `gh pr ready --undo`, clear stale gate evidence, and repeat review plus configured gates for the new SHA. If no PR checks are configured, confirm that from project configuration and record their absence instead of blocking the merge. An empty `gh pr checks` result immediately after ready is not evidence that no checks are configured. Immediately before reporting or merging, compare `gh pr view --json headRefOid` with the recorded candidate SHA.
|
|
44
46
|
|
|
45
47
|
| PR | Scope | Branch | Worktree | Base | Status | Merge evidence |
|
|
46
48
|
|----|-------|--------|----------|------|--------|----------------|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
name: xreview
|
|
2
3
|
description: Conditional multi-agent code review — determines what to review (asking if unclear), resolves the exact diff, and launches only the relevant subagents in parallel
|
|
3
4
|
---
|
|
4
5
|
|
|
@@ -6,7 +7,7 @@ Run a comprehensive multi-agent review. Your job as the main agent: determine WH
|
|
|
6
7
|
|
|
7
8
|
## 0. Determine the review target
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Review target (may be empty): use the invocation context or the explicit target supplied by the caller.
|
|
10
11
|
|
|
11
12
|
- If the input names a branch → review `git diff <that-branch>...HEAD`.
|
|
12
13
|
- If the input references a PR (number or URL) → use that PR's base branch as BASE.
|
|
@@ -51,19 +52,19 @@ If the diff adds or changes comments/docstrings, run `comment-fixer` ALONE befor
|
|
|
51
52
|
|
|
52
53
|
## 4. Launch the remaining subagents in PARALLEL
|
|
53
54
|
|
|
54
|
-
All subagents are CONDITIONAL: launch one only when the changed files indicate it applies. Run them in PARALLEL via the
|
|
55
|
+
All subagents are CONDITIONAL: launch one only when the changed files indicate it applies. Run them in PARALLEL via the delegation mechanism available in the current runtime. Each subagent fetches its OWN diff; all are read-only. Pass every one EXACTLY:
|
|
55
56
|
|
|
56
57
|
- the review scope: BASE and HEAD branches (verbatim), or "working diff" for uncommitted work
|
|
57
58
|
- the instruction: review only that scope — never assume `main`, use the scope given
|
|
58
59
|
|
|
59
60
|
Subagents and their triggers:
|
|
60
61
|
|
|
61
|
-
1.
|
|
62
|
-
2.
|
|
63
|
-
3.
|
|
64
|
-
4.
|
|
65
|
-
5.
|
|
66
|
-
6.
|
|
62
|
+
1. `test-analyzer` — only if the diff touches tests or code that should be tested
|
|
63
|
+
2. `silent-failure-hunter` — only if the diff includes error handling, try/catch, fallbacks, or async flows
|
|
64
|
+
3. `type-design-analyzer` — only if the diff changes types, interfaces, schemas, or public contracts
|
|
65
|
+
4. `code-reviewer` — for general code quality whenever non-trivial source code changed
|
|
66
|
+
5. `code-simplifier` — only if the diff introduces complexity worth simplifying; this is the lean/anti-bloat pass for diffs and PRs
|
|
67
|
+
6. `security-auditor` — only if the diff touches auth, authorization, permissions, secrets/credentials, sensitive data, input validation, webhooks, or other security-critical flows
|
|
67
68
|
|
|
68
69
|
If none of a subagent's triggers are present, skip it and note that it was skipped. Always state which subagents ran and which were skipped and why.
|
|
69
70
|
|
|
@@ -125,7 +125,12 @@ Every piece of information about a piece of work has exactly ONE home — never
|
|
|
125
125
|
- Commit per task or per bounded group of tasks — small, separate commits whose history maps to the work; never everything in one giant commit.
|
|
126
126
|
- Never push code or behavior changes directly to production branches (main/master or the repo's protected/release branches): those always go through a work branch + PR. Pushing a work branch or a worktree branch is fine without asking.
|
|
127
127
|
- Exception: TRIVIAL changes — docs, typos, content removal, config text with no behavior or code-logic impact — may be committed and pushed directly to the production branch. When in doubt about whether a change is trivial, it is not: use a PR.
|
|
128
|
-
-
|
|
128
|
+
- Start each non-trivial PR from an updated production branch in its canonical worktree/branch, and keep one concrete objective per PR. Dependent PRs are sequential: merge the first, update the production branch, then create the next branch from it.
|
|
129
|
+
- After the first coherent commit, push the work branch and always open the PR as draft with `gh pr create --draft`. Creating and pushing the work branch and draft PR is fine without asking.
|
|
130
|
+
- Keep the PR in draft while its code can still change. All subsequent commits and pushes happen while draft; never push to a ready PR.
|
|
131
|
+
- Before ready, complete all applicable preflight work: code, version bump, local tests, the project's quality command (`pnpm qa:quality` when defined), Vercel preview review when the project uses Vercel, final diff inspection, and the full PR review. React Doctor is manual/local, not a GitHub Actions gate.
|
|
132
|
+
- Mark the PR ready only once the current SHA is the candidate to merge: `gh pr ready <number>`. If the project has PR checks configured, wait for Quality Gates, run `gh pr checks <number>`, and verify the checks belong to the latest commit before reporting it mergeable. If no PR checks are configured, confirm that from project configuration such as workflows, rulesets or integrations, and record it; their absence does not block the merge. An empty `gh pr checks` result immediately after ready is not evidence that no checks are configured. Immediately before reporting or merging, compare `gh pr view --json headRefOid` with the recorded candidate SHA.
|
|
133
|
+
- If a ready PR needs any code or behavior change, first run `gh pr ready --undo <number>`, then modify and push while draft, repeat the full local verification and review, mark ready again, and wait for a fresh complete gate when PR checks are configured. Never push to a ready PR and merge without repeating the applicable cycle.
|
|
129
134
|
- Merging a PR ALWAYS requires an explicit user request — no exceptions, in any flow.
|
|
130
135
|
- Before commit or push, review `git status`, `git diff`, and `git log --oneline -10`.
|
|
131
136
|
- Never add AI signatures, `Co-Authored-By`, or agent mentions.
|