@mestreyoda/fabrica 0.2.36 → 0.2.38
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/index.js +168 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -113905,8 +113905,8 @@ import fsSync from "node:fs";
|
|
|
113905
113905
|
import path5 from "node:path";
|
|
113906
113906
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
113907
113907
|
function getCurrentVersion() {
|
|
113908
|
-
if ("0.2.
|
|
113909
|
-
return "0.2.
|
|
113908
|
+
if ("0.2.38") {
|
|
113909
|
+
return "0.2.38";
|
|
113910
113910
|
}
|
|
113911
113911
|
try {
|
|
113912
113912
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -130477,6 +130477,135 @@ function createProjectStatusTool(ctx) {
|
|
|
130477
130477
|
});
|
|
130478
130478
|
}
|
|
130479
130479
|
|
|
130480
|
+
// lib/setup/doctor-run.ts
|
|
130481
|
+
async function runIssueDoctor(opts) {
|
|
130482
|
+
const data = await readProjects(opts.workspacePath);
|
|
130483
|
+
const project = data.projects[opts.projectSlug];
|
|
130484
|
+
if (!project) throw new Error(`Project not found: ${opts.projectSlug}`);
|
|
130485
|
+
const issueRuntime = getIssueRuntime(project, opts.issueId) ?? null;
|
|
130486
|
+
const hasArtifact = Boolean(
|
|
130487
|
+
issueRuntime?.currentPrUrl || issueRuntime?.currentPrNumber || issueRuntime?.artifactOfRecord
|
|
130488
|
+
);
|
|
130489
|
+
const { provider } = await createProvider({
|
|
130490
|
+
repo: project.repo,
|
|
130491
|
+
provider: project.provider,
|
|
130492
|
+
providerProfile: project.providerProfile,
|
|
130493
|
+
runCommand: opts.runCommand,
|
|
130494
|
+
pluginConfig: opts.pluginConfig
|
|
130495
|
+
});
|
|
130496
|
+
let prStatus = null;
|
|
130497
|
+
try {
|
|
130498
|
+
const pr = await provider.getPrStatus(opts.issueId);
|
|
130499
|
+
if (pr.url || pr.number) prStatus = pr;
|
|
130500
|
+
} catch {
|
|
130501
|
+
prStatus = null;
|
|
130502
|
+
}
|
|
130503
|
+
let issue2 = null;
|
|
130504
|
+
try {
|
|
130505
|
+
issue2 = await provider.getIssue(opts.issueId);
|
|
130506
|
+
} catch {
|
|
130507
|
+
issue2 = null;
|
|
130508
|
+
}
|
|
130509
|
+
const convergenceCause = issueRuntime?.lastConvergenceCause ?? null;
|
|
130510
|
+
const convergenceAction = issueRuntime?.lastConvergenceAction ?? null;
|
|
130511
|
+
const retryCount = issueRuntime?.lastConvergenceRetryCount ?? 0;
|
|
130512
|
+
const convergenceReason = issueRuntime?.lastConvergenceReason ?? issueRuntime?.inconclusiveCompletionReason ?? null;
|
|
130513
|
+
const summaryParts = [
|
|
130514
|
+
hasArtifact ? "artifact_present" : "artifact_missing",
|
|
130515
|
+
convergenceCause ? `cause=${convergenceCause}` : "cause=none",
|
|
130516
|
+
convergenceAction ? `action=${convergenceAction}` : "action=none",
|
|
130517
|
+
retryCount ? `retries=${retryCount}` : "retries=0",
|
|
130518
|
+
prStatus?.state ? `pr=${prStatus.state}` : "pr=unknown"
|
|
130519
|
+
];
|
|
130520
|
+
const likelyNextAction = (() => {
|
|
130521
|
+
if (convergenceAction === "escalate_human") return "human_intervention";
|
|
130522
|
+
if (convergenceCause === "invalid_qa_evidence") return "repair_qa_evidence";
|
|
130523
|
+
if (convergenceCause === "merge_conflict") return "repair_merge_conflict";
|
|
130524
|
+
if (convergenceCause === "stalled_with_artifact") return "force_convergence_review";
|
|
130525
|
+
if (hasArtifact) return "post_pr_convergence";
|
|
130526
|
+
return "redispatch_or_investigate";
|
|
130527
|
+
})();
|
|
130528
|
+
return {
|
|
130529
|
+
projectSlug: project.slug,
|
|
130530
|
+
projectName: project.name,
|
|
130531
|
+
issueId: opts.issueId,
|
|
130532
|
+
issueRuntime,
|
|
130533
|
+
hasArtifact,
|
|
130534
|
+
convergence: {
|
|
130535
|
+
cause: convergenceCause,
|
|
130536
|
+
action: convergenceAction,
|
|
130537
|
+
retryCount,
|
|
130538
|
+
reason: convergenceReason,
|
|
130539
|
+
at: issueRuntime?.lastConvergenceAt ?? null
|
|
130540
|
+
},
|
|
130541
|
+
pr: prStatus ? {
|
|
130542
|
+
url: prStatus.url ?? null,
|
|
130543
|
+
state: prStatus.state ?? null,
|
|
130544
|
+
number: prStatus.number ?? null,
|
|
130545
|
+
mergeable: prStatus.mergeable ?? null,
|
|
130546
|
+
currentIssueMatch: prStatus.currentIssueMatch ?? null,
|
|
130547
|
+
sourceBranch: prStatus.sourceBranch ?? null
|
|
130548
|
+
} : null,
|
|
130549
|
+
issue: issue2 ? {
|
|
130550
|
+
url: issue2.web_url ?? null,
|
|
130551
|
+
state: issue2.state ?? null,
|
|
130552
|
+
labels: issue2.labels ?? [],
|
|
130553
|
+
title: issue2.title ?? null
|
|
130554
|
+
} : null,
|
|
130555
|
+
recommendation: {
|
|
130556
|
+
summary: summaryParts.join(" | "),
|
|
130557
|
+
likelyNextAction
|
|
130558
|
+
}
|
|
130559
|
+
};
|
|
130560
|
+
}
|
|
130561
|
+
function formatIssueDoctor(result) {
|
|
130562
|
+
const lines = [
|
|
130563
|
+
`Issue run doctor \u2014 ${result.projectSlug}#${result.issueId}`,
|
|
130564
|
+
` Artifact: ${result.hasArtifact ? "yes" : "no"}`,
|
|
130565
|
+
` PR: ${result.pr?.url ?? "n/a"} (${result.pr?.state ?? "unknown"})`,
|
|
130566
|
+
` Issue: ${result.issue?.url ?? "n/a"} (${result.issue?.state ?? "unknown"})`,
|
|
130567
|
+
` Labels: ${result.issue?.labels?.join(", ") ?? "n/a"}`,
|
|
130568
|
+
` Convergence cause: ${result.convergence.cause ?? "none"}`,
|
|
130569
|
+
` Convergence action: ${result.convergence.action ?? "none"}`,
|
|
130570
|
+
` Retry count: ${result.convergence.retryCount}`,
|
|
130571
|
+
` Last reason: ${result.convergence.reason ?? "n/a"}`,
|
|
130572
|
+
` Suggested next action: ${result.recommendation.likelyNextAction}`
|
|
130573
|
+
];
|
|
130574
|
+
return lines.join("\n");
|
|
130575
|
+
}
|
|
130576
|
+
|
|
130577
|
+
// lib/tools/admin/doctor-issue.ts
|
|
130578
|
+
function createDoctorIssueTool(ctx) {
|
|
130579
|
+
return (toolCtx) => ({
|
|
130580
|
+
name: "doctor_issue",
|
|
130581
|
+
label: "Doctor Issue",
|
|
130582
|
+
description: "Inspect one Fabrica issue/run with convergence metadata, PR context, issue labels, and a recommended next action.",
|
|
130583
|
+
parameters: {
|
|
130584
|
+
type: "object",
|
|
130585
|
+
required: ["projectSlug", "issueId"],
|
|
130586
|
+
properties: {
|
|
130587
|
+
projectSlug: { type: "string", description: "Project slug (for example: fabrica or my-project)." },
|
|
130588
|
+
issueId: { type: "number", description: "Issue number to inspect." }
|
|
130589
|
+
}
|
|
130590
|
+
},
|
|
130591
|
+
async execute(_id, params) {
|
|
130592
|
+
const workspaceDir = requireWorkspaceDir(toolCtx);
|
|
130593
|
+
const projectSlug = String(params.projectSlug ?? "").trim();
|
|
130594
|
+
const issueId = Number(params.issueId);
|
|
130595
|
+
if (!projectSlug) throw new Error("projectSlug is required");
|
|
130596
|
+
if (!Number.isFinite(issueId)) throw new Error("issueId must be a number");
|
|
130597
|
+
const result = await runIssueDoctor({
|
|
130598
|
+
workspacePath: workspaceDir,
|
|
130599
|
+
projectSlug,
|
|
130600
|
+
issueId,
|
|
130601
|
+
runCommand: ctx.runCommand,
|
|
130602
|
+
pluginConfig: ctx.pluginConfig
|
|
130603
|
+
});
|
|
130604
|
+
return jsonResult(result);
|
|
130605
|
+
}
|
|
130606
|
+
});
|
|
130607
|
+
}
|
|
130608
|
+
|
|
130480
130609
|
// lib/tools/admin/project-register.ts
|
|
130481
130610
|
import fs24 from "node:fs/promises";
|
|
130482
130611
|
import path24 from "node:path";
|
|
@@ -131291,9 +131420,12 @@ function decidePostPrConvergence(params) {
|
|
|
131291
131420
|
const { workflow, issueRuntime, reason, feedbackQueueLabel } = params;
|
|
131292
131421
|
const cause = classifyConvergenceCause(reason);
|
|
131293
131422
|
const hasArtifact = hasReviewableArtifact(issueRuntime);
|
|
131423
|
+
const progressHeadSha = issueRuntime?.currentPrHeadSha ?? issueRuntime?.lastHeadSha ?? issueRuntime?.artifactOfRecord?.headSha ?? null;
|
|
131294
131424
|
const previousCause = issueRuntime?.lastConvergenceCause ?? null;
|
|
131295
131425
|
const previousCount = issueRuntime?.lastConvergenceRetryCount ?? 0;
|
|
131296
|
-
const
|
|
131426
|
+
const previousHeadSha = issueRuntime?.lastConvergenceHeadSha ?? null;
|
|
131427
|
+
const sameHeadSha = !progressHeadSha || !previousHeadSha ? true : progressHeadSha === previousHeadSha;
|
|
131428
|
+
const retryCount = previousCause === cause && sameHeadSha ? previousCount + 1 : 1;
|
|
131297
131429
|
const maxRetries = getConvergenceRetryBudget(cause);
|
|
131298
131430
|
const holdLabel = getPreferredHoldLabel(workflow);
|
|
131299
131431
|
const shouldEscalate = hasArtifact && retryCount > maxRetries && Boolean(holdLabel);
|
|
@@ -131303,7 +131435,8 @@ function decidePostPrConvergence(params) {
|
|
|
131303
131435
|
targetLabel: shouldEscalate ? holdLabel ?? feedbackQueueLabel : feedbackQueueLabel,
|
|
131304
131436
|
retryCount,
|
|
131305
131437
|
maxRetries,
|
|
131306
|
-
hasArtifact
|
|
131438
|
+
hasArtifact,
|
|
131439
|
+
progressHeadSha
|
|
131307
131440
|
};
|
|
131308
131441
|
}
|
|
131309
131442
|
|
|
@@ -131895,7 +132028,8 @@ ${validationReason}`;
|
|
|
131895
132028
|
lastConvergenceAction: convergence.action,
|
|
131896
132029
|
lastConvergenceRetryCount: convergence.retryCount,
|
|
131897
132030
|
lastConvergenceReason: validationReason,
|
|
131898
|
-
lastConvergenceAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
132031
|
+
lastConvergenceAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
132032
|
+
lastConvergenceHeadSha: convergence.progressHeadSha
|
|
131899
132033
|
}).catch(() => {
|
|
131900
132034
|
});
|
|
131901
132035
|
await executeCompletion({
|
|
@@ -132021,7 +132155,8 @@ ${validationReason}`;
|
|
|
132021
132155
|
lastConvergenceAction: null,
|
|
132022
132156
|
lastConvergenceRetryCount: 0,
|
|
132023
132157
|
lastConvergenceReason: null,
|
|
132024
|
-
lastConvergenceAt: null
|
|
132158
|
+
lastConvergenceAt: null,
|
|
132159
|
+
lastConvergenceHeadSha: null
|
|
132025
132160
|
}).catch(() => {
|
|
132026
132161
|
});
|
|
132027
132162
|
} else {
|
|
@@ -132032,7 +132167,8 @@ ${validationReason}`;
|
|
|
132032
132167
|
lastConvergenceAction: null,
|
|
132033
132168
|
lastConvergenceRetryCount: 0,
|
|
132034
132169
|
lastConvergenceReason: null,
|
|
132035
|
-
lastConvergenceAt: null
|
|
132170
|
+
lastConvergenceAt: null,
|
|
132171
|
+
lastConvergenceHeadSha: null
|
|
132036
132172
|
}).catch(() => {
|
|
132037
132173
|
});
|
|
132038
132174
|
}
|
|
@@ -132555,7 +132691,8 @@ async function checkWorkerHealth(opts) {
|
|
|
132555
132691
|
lastConvergenceAction: convergence.action,
|
|
132556
132692
|
lastConvergenceRetryCount: convergence.retryCount,
|
|
132557
132693
|
lastConvergenceReason: inconclusiveReason,
|
|
132558
|
-
lastConvergenceAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
132694
|
+
lastConvergenceAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
132695
|
+
lastConvergenceHeadSha: convergence.progressHeadSha
|
|
132559
132696
|
}).catch(() => {
|
|
132560
132697
|
});
|
|
132561
132698
|
fix.fixed = true;
|
|
@@ -132938,7 +133075,8 @@ async function checkWorkerHealth(opts) {
|
|
|
132938
133075
|
lastConvergenceAction: convergence.action,
|
|
132939
133076
|
lastConvergenceRetryCount: convergence.retryCount,
|
|
132940
133077
|
lastConvergenceReason: "stalled_with_artifact",
|
|
132941
|
-
lastConvergenceAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
133078
|
+
lastConvergenceAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
133079
|
+
lastConvergenceHeadSha: convergence.progressHeadSha
|
|
132942
133080
|
}).catch(() => {
|
|
132943
133081
|
});
|
|
132944
133082
|
fix.fixed = true;
|
|
@@ -149533,6 +149671,26 @@ function registerCli(program, ctx) {
|
|
|
149533
149671
|
${result.checks.length} checks: ${result.errors} errors, ${result.warnings} warnings`);
|
|
149534
149672
|
process.exit(result.errors > 0 ? 1 : 0);
|
|
149535
149673
|
});
|
|
149674
|
+
doctor.command("issue").description("Inspect one Fabrica issue/run with convergence and PR context").requiredOption("-p, --project <slug>", "Project slug").requiredOption("-i, --issue <id>", "Issue number").option("-w, --workspace <path>", "Workspace directory").option("--json", "Emit machine-readable JSON").action(async (opts) => {
|
|
149675
|
+
const workspaceDir = requireWorkspaceDir2(ctx.runtime, opts.workspace);
|
|
149676
|
+
const issueId = Number.parseInt(String(opts.issue), 10);
|
|
149677
|
+
if (!Number.isFinite(issueId)) {
|
|
149678
|
+
console.error(`Invalid issue id: ${opts.issue}`);
|
|
149679
|
+
process.exit(1);
|
|
149680
|
+
}
|
|
149681
|
+
const result = await runIssueDoctor({
|
|
149682
|
+
workspacePath: workspaceDir,
|
|
149683
|
+
projectSlug: String(opts.project),
|
|
149684
|
+
issueId,
|
|
149685
|
+
runCommand: ctx.runCommand,
|
|
149686
|
+
pluginConfig: ctx.pluginConfig
|
|
149687
|
+
});
|
|
149688
|
+
if (opts.json) {
|
|
149689
|
+
console.log(JSON.stringify(result, null, 2));
|
|
149690
|
+
return;
|
|
149691
|
+
}
|
|
149692
|
+
console.log(formatIssueDoctor(result));
|
|
149693
|
+
});
|
|
149536
149694
|
doctor.option("-w, --workspace <path>", "Workspace directory").option("--fix", "Apply fixes for detected issues").action(async (opts) => {
|
|
149537
149695
|
const workspaceDir = requireWorkspaceDir2(ctx.runtime, opts.workspace);
|
|
149538
149696
|
const result = await runDoctor({ workspacePath: workspaceDir, fix: opts.fix ?? false, pluginConfig: ctx.pluginConfig });
|
|
@@ -150903,6 +151061,7 @@ var plugin = {
|
|
|
150903
151061
|
api.registerTool(createTaskListTool(ctx), { names: ["task_list"] });
|
|
150904
151062
|
api.registerTool(createTasksStatusTool(ctx), { names: ["tasks_status"] });
|
|
150905
151063
|
api.registerTool(createProjectStatusTool(ctx), { names: ["project_status"] });
|
|
151064
|
+
api.registerTool(createDoctorIssueTool(ctx), { names: ["doctor_issue"] });
|
|
150906
151065
|
api.registerTool(createProjectRegisterTool(ctx), { names: ["project_register"] });
|
|
150907
151066
|
api.registerTool(createHealthTool(ctx), { names: ["health"] });
|
|
150908
151067
|
api.registerTool(createSyncLabelsTool(ctx), { names: ["sync_labels"] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mestreyoda/fabrica",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.38",
|
|
4
4
|
"description": "Autonomous software engineering pipeline for OpenClaw. Turns ideas into deployed code via intake, dispatch, review, test, and merge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|