@mestreyoda/fabrica 0.2.7 → 0.2.9
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/defaults/fabrica/prompts/reviewer.md +21 -39
- package/dist/index.js +68 -3
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
|
@@ -91,49 +91,31 @@ If you discover unrelated bugs or needed improvements, call `task_create`:
|
|
|
91
91
|
|
|
92
92
|
## Completing Your Task
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
### Method A — Fabrica tools (preferred)
|
|
97
|
-
|
|
98
|
-
1. Call `review_submit` to write the review artifact to the PR:
|
|
99
|
-
- **Approve:** `review_submit({ channelId: "<project slug>", issueId: <issue number>, result: "approve", body: "<what you checked>" })`
|
|
100
|
-
- **Reject:** `review_submit({ channelId: "<project slug>", issueId: <issue number>, result: "reject", body: "<specific issues>" })`
|
|
101
|
-
- Capture the returned `artifactId` and `artifactType`.
|
|
102
|
-
2. Then call `work_finish`:
|
|
103
|
-
- **Approve:** `work_finish({ role: "reviewer", result: "approve", channelId: "<project slug>", summary: "<what you checked>", reviewArtifactId: <artifactId>, reviewArtifactType: "<artifactType>" })`
|
|
104
|
-
- **Reject:** `work_finish({ role: "reviewer", result: "reject", channelId: "<project slug>", summary: "<specific issues>", reviewArtifactId: <artifactId>, reviewArtifactType: "<artifactType>" })`
|
|
105
|
-
- **Blocked:** `work_finish({ role: "reviewer", result: "blocked", channelId: "<project slug>", summary: "<what you need>" })`
|
|
106
|
-
|
|
107
|
-
> **IMPORTANT:** The `channelId` parameter accepts the project slug (e.g., "gestao-notas").
|
|
108
|
-
> Extract it from the "Project: <name>" line in your task message. Do NOT use the numeric
|
|
109
|
-
> channel ID — use the project slug to avoid resolution errors when channels are shared.
|
|
110
|
-
|
|
111
|
-
### Method B — GitHub CLI fallback (use only if `review_submit` / `work_finish` are unavailable)
|
|
112
|
-
|
|
113
|
-
Extract from your task message:
|
|
114
|
-
- `OWNER/REPO` from the `Repo:` line
|
|
115
|
-
- `PR_NUMBER` from the PR URL in the diff header or the `Branch:` line
|
|
116
|
-
- `ISSUE_NUMBER` from the `Issue:` field
|
|
117
|
-
|
|
118
|
-
**Approve:**
|
|
119
|
-
```bash
|
|
120
|
-
gh pr review PR_NUMBER --repo OWNER/REPO --approve -b "$(cat <<'EOF'
|
|
121
|
-
<your full review body here>
|
|
122
|
-
EOF
|
|
123
|
-
)"
|
|
124
|
-
```
|
|
94
|
+
After writing your review, you **MUST** output your final decision on a dedicated line in **exactly** one of these two formats:
|
|
125
95
|
|
|
126
|
-
**Reject (request changes):**
|
|
127
|
-
```bash
|
|
128
|
-
gh pr review PR_NUMBER --repo OWNER/REPO --request-changes -b "$(cat <<'EOF'
|
|
129
|
-
<specific issues and how to fix them>
|
|
130
|
-
EOF
|
|
131
|
-
)"
|
|
132
96
|
```
|
|
97
|
+
Review result: APPROVE
|
|
98
|
+
```
|
|
99
|
+
```
|
|
100
|
+
Review result: REJECT
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The Fabrica orchestrator reads your session output and advances the pipeline automatically based on this line. **You do not need to call any tool or run any CLI command.** Just output the line above and your work is done.
|
|
104
|
+
|
|
105
|
+
- Output `Review result: APPROVE` if all quality gates pass and the code is ready to proceed.
|
|
106
|
+
- Output `Review result: REJECT` if any blocking issue was found that the developer must fix.
|
|
133
107
|
|
|
134
|
-
|
|
108
|
+
> **IMPORTANT:** The decision line must appear in your response text, not inside a code block. It is case-insensitive but must follow the `Review result: APPROVE/REJECT` format exactly.
|
|
109
|
+
|
|
110
|
+
### Optional: submit PR comment (best-effort)
|
|
111
|
+
|
|
112
|
+
If `gh` is available and the PR author is not the same GitHub account you are logged in as, you may optionally leave a PR comment for visibility:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
gh pr comment <PR_NUMBER> --repo <OWNER/REPO> --body "<summary of your findings>"
|
|
116
|
+
```
|
|
135
117
|
|
|
136
|
-
|
|
118
|
+
This is informational only — the orchestrator does not require it to advance the pipeline.
|
|
137
119
|
|
|
138
120
|
## Tools You Should NOT Use
|
|
139
121
|
|
package/dist/index.js
CHANGED
|
@@ -111330,8 +111330,8 @@ import fsSync from "node:fs";
|
|
|
111330
111330
|
import path5 from "node:path";
|
|
111331
111331
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
111332
111332
|
function getCurrentVersion() {
|
|
111333
|
-
if ("0.2.
|
|
111334
|
-
return "0.2.
|
|
111333
|
+
if ("0.2.9") {
|
|
111334
|
+
return "0.2.9";
|
|
111335
111335
|
}
|
|
111336
111336
|
try {
|
|
111337
111337
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -139562,6 +139562,36 @@ function registerReactiveDispatchHooks(api, ctx) {
|
|
|
139562
139562
|
|
|
139563
139563
|
// lib/dispatch/subagent-lifecycle-hook.ts
|
|
139564
139564
|
init_workflow();
|
|
139565
|
+
init_labels();
|
|
139566
|
+
async function parseReviewerSessionResult(ctx, sessionKey) {
|
|
139567
|
+
try {
|
|
139568
|
+
const messagesResult = await ctx.runtime.subagent?.getSessionMessages?.({ sessionKey });
|
|
139569
|
+
if (!messagesResult) return null;
|
|
139570
|
+
const messages = Array.isArray(messagesResult) ? messagesResult : Array.isArray(messagesResult?.messages) ? messagesResult.messages : [];
|
|
139571
|
+
const assistantTexts = messages.filter((m2) => m2.role === "assistant").map((m2) => {
|
|
139572
|
+
const raw = m2.content;
|
|
139573
|
+
if (typeof raw === "string") return raw;
|
|
139574
|
+
if (Array.isArray(raw)) {
|
|
139575
|
+
return raw.find((b) => b.type === "text")?.text ?? "";
|
|
139576
|
+
}
|
|
139577
|
+
return "";
|
|
139578
|
+
}).filter(Boolean).reverse();
|
|
139579
|
+
for (const text of assistantTexts) {
|
|
139580
|
+
const lower2 = text.toLowerCase();
|
|
139581
|
+
if (/review\s+result\s*:\s*approve/i.test(text)) return "approve";
|
|
139582
|
+
if (/review\s+result\s*:\s*reject/i.test(text)) return "reject";
|
|
139583
|
+
if (/\*\*approved\*\*/i.test(text)) return "approve";
|
|
139584
|
+
if (/\*\*rejected\*\*/i.test(text)) return "reject";
|
|
139585
|
+
const approveMatch = lower2.match(/\b(approve|approved|lgtm|looks good)\b/);
|
|
139586
|
+
const rejectMatch = lower2.match(/\b(reject|rejected|request[s]?\s+changes?|changes\s+requested)\b/);
|
|
139587
|
+
if (approveMatch && !rejectMatch) return "approve";
|
|
139588
|
+
if (rejectMatch && !approveMatch) return "reject";
|
|
139589
|
+
}
|
|
139590
|
+
return null;
|
|
139591
|
+
} catch {
|
|
139592
|
+
return null;
|
|
139593
|
+
}
|
|
139594
|
+
}
|
|
139565
139595
|
function registerSubagentLifecycleHook(api, ctx) {
|
|
139566
139596
|
const workspaceDir = resolveWorkspaceDir(ctx.config);
|
|
139567
139597
|
if (!workspaceDir) return;
|
|
@@ -139625,7 +139655,42 @@ function registerSubagentLifecycleHook(api, ctx) {
|
|
|
139625
139655
|
runCommand: ctx.runCommand
|
|
139626
139656
|
});
|
|
139627
139657
|
const issue2 = await provider.getIssue(Number(issueId));
|
|
139628
|
-
if (issue2.labels.includes(activeLabel)) {
|
|
139658
|
+
if (!issue2.labels.includes(activeLabel)) {
|
|
139659
|
+
} else if (role === "reviewer") {
|
|
139660
|
+
const reviewResult = await parseReviewerSessionResult(ctx, sessionKey);
|
|
139661
|
+
if (reviewResult === "approve" || reviewResult === "reject") {
|
|
139662
|
+
const reviewingState = findStateByLabel(config2.workflow, activeLabel);
|
|
139663
|
+
const eventKey = reviewResult === "approve" ? WorkflowEvent.APPROVED : WorkflowEvent.CHANGES_REQUESTED;
|
|
139664
|
+
const transition2 = reviewingState?.on?.[eventKey];
|
|
139665
|
+
const targetKey = typeof transition2 === "string" ? transition2 : transition2?.target;
|
|
139666
|
+
const targetState = targetKey ? config2.workflow.states[targetKey] : void 0;
|
|
139667
|
+
if (targetState) {
|
|
139668
|
+
await resilientLabelTransition(provider, Number(issueId), activeLabel, targetState.label);
|
|
139669
|
+
await log(workspaceDir, "reviewer_session_transition", {
|
|
139670
|
+
sessionKey,
|
|
139671
|
+
project: projectName,
|
|
139672
|
+
issueId,
|
|
139673
|
+
result: reviewResult,
|
|
139674
|
+
from: activeLabel,
|
|
139675
|
+
to: targetState.label
|
|
139676
|
+
}).catch(() => {
|
|
139677
|
+
});
|
|
139678
|
+
ctx.logger.info(
|
|
139679
|
+
`reviewer_session_transition: issue #${issueId} \u2192 ${targetState.label} (result=${reviewResult})`
|
|
139680
|
+
);
|
|
139681
|
+
} else {
|
|
139682
|
+
await provider.transitionLabel(Number(issueId), activeLabel, revertLabel);
|
|
139683
|
+
}
|
|
139684
|
+
} else {
|
|
139685
|
+
await provider.transitionLabel(Number(issueId), activeLabel, revertLabel);
|
|
139686
|
+
await log(workspaceDir, "reviewer_session_no_result", {
|
|
139687
|
+
sessionKey,
|
|
139688
|
+
project: projectName,
|
|
139689
|
+
issueId
|
|
139690
|
+
}).catch(() => {
|
|
139691
|
+
});
|
|
139692
|
+
}
|
|
139693
|
+
} else {
|
|
139629
139694
|
await provider.transitionLabel(Number(issueId), activeLabel, revertLabel);
|
|
139630
139695
|
}
|
|
139631
139696
|
} catch {
|