@mestreyoda/fabrica 0.2.35 → 0.2.37

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.
Files changed (2) hide show
  1. package/dist/index.js +145 -4
  2. 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.35") {
113909
- return "0.2.35";
113908
+ if ("0.2.37") {
113909
+ return "0.2.37";
113910
113910
  }
113911
113911
  try {
113912
113912
  const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
@@ -131742,9 +131742,18 @@ async function defaultValidateDeveloperDone(opts) {
131742
131742
  );
131743
131743
  return { ok: true, prStatus };
131744
131744
  } catch (error48) {
131745
+ let prStatus;
131746
+ try {
131747
+ const fallbackPr = await opts.provider.getPrStatus(opts.issueId);
131748
+ if (fallbackPr.url && fallbackPr.state !== "merged" && fallbackPr.state !== "closed") {
131749
+ prStatus = fallbackPr;
131750
+ }
131751
+ } catch {
131752
+ }
131745
131753
  return {
131746
131754
  ok: false,
131747
- reason: error48 instanceof Error ? error48.message : "developer_validation_failed"
131755
+ reason: error48 instanceof Error ? error48.message : "developer_validation_failed",
131756
+ prStatus
131748
131757
  };
131749
131758
  }
131750
131759
  }
@@ -131836,9 +131845,24 @@ async function applyWorkerResult(opts) {
131836
131845
  if (!validation.ok) {
131837
131846
  const validationReason = validation.reason ?? "developer_validation_failed";
131838
131847
  const feedbackQueueLabel = getQueueLabels(workflow, "developer").find((label) => isFeedbackState(workflow, label)) ?? "To Improve";
131848
+ const convergenceIssueRuntime = validation.prStatus ? {
131849
+ ...context2.issueRuntime,
131850
+ currentPrNumber: validation.prStatus.number ?? context2.issueRuntime?.currentPrNumber ?? null,
131851
+ currentPrUrl: validation.prStatus.url ?? context2.issueRuntime?.currentPrUrl ?? null,
131852
+ currentPrState: validation.prStatus.state ?? context2.issueRuntime?.currentPrState ?? null
131853
+ } : context2.issueRuntime;
131854
+ if (validation.prStatus) {
131855
+ await persistDeveloperPrBinding({
131856
+ workspaceDir: opts.workspaceDir,
131857
+ projectSlug: context2.projectSlug,
131858
+ issueId: context2.issueId,
131859
+ prStatus: validation.prStatus
131860
+ }).catch(() => {
131861
+ });
131862
+ }
131839
131863
  const convergence = decidePostPrConvergence({
131840
131864
  workflow,
131841
- issueRuntime: context2.issueRuntime,
131865
+ issueRuntime: convergenceIssueRuntime,
131842
131866
  reason: validationReason,
131843
131867
  feedbackQueueLabel
131844
131868
  });
@@ -148927,6 +148951,103 @@ async function checkProjects(dataDir) {
148927
148951
  return results;
148928
148952
  }
148929
148953
 
148954
+ // lib/setup/doctor-run.ts
148955
+ async function runIssueDoctor(opts) {
148956
+ const data = await readProjects(opts.workspacePath);
148957
+ const project = data.projects[opts.projectSlug];
148958
+ if (!project) throw new Error(`Project not found: ${opts.projectSlug}`);
148959
+ const issueRuntime = getIssueRuntime(project, opts.issueId) ?? null;
148960
+ const hasArtifact = Boolean(
148961
+ issueRuntime?.currentPrUrl || issueRuntime?.currentPrNumber || issueRuntime?.artifactOfRecord
148962
+ );
148963
+ const { provider } = await createProvider({
148964
+ repo: project.repo,
148965
+ provider: project.provider,
148966
+ providerProfile: project.providerProfile,
148967
+ runCommand: opts.runCommand,
148968
+ pluginConfig: opts.pluginConfig
148969
+ });
148970
+ let prStatus = null;
148971
+ try {
148972
+ const pr = await provider.getPrStatus(opts.issueId);
148973
+ if (pr.url || pr.number) prStatus = pr;
148974
+ } catch {
148975
+ prStatus = null;
148976
+ }
148977
+ let issue2 = null;
148978
+ try {
148979
+ issue2 = await provider.getIssue(opts.issueId);
148980
+ } catch {
148981
+ issue2 = null;
148982
+ }
148983
+ const convergenceCause = issueRuntime?.lastConvergenceCause ?? null;
148984
+ const convergenceAction = issueRuntime?.lastConvergenceAction ?? null;
148985
+ const retryCount = issueRuntime?.lastConvergenceRetryCount ?? 0;
148986
+ const convergenceReason = issueRuntime?.lastConvergenceReason ?? issueRuntime?.inconclusiveCompletionReason ?? null;
148987
+ const summaryParts = [
148988
+ hasArtifact ? "artifact_present" : "artifact_missing",
148989
+ convergenceCause ? `cause=${convergenceCause}` : "cause=none",
148990
+ convergenceAction ? `action=${convergenceAction}` : "action=none",
148991
+ retryCount ? `retries=${retryCount}` : "retries=0",
148992
+ prStatus?.state ? `pr=${prStatus.state}` : "pr=unknown"
148993
+ ];
148994
+ const likelyNextAction = (() => {
148995
+ if (convergenceAction === "escalate_human") return "human_intervention";
148996
+ if (convergenceCause === "invalid_qa_evidence") return "repair_qa_evidence";
148997
+ if (convergenceCause === "merge_conflict") return "repair_merge_conflict";
148998
+ if (convergenceCause === "stalled_with_artifact") return "force_convergence_review";
148999
+ if (hasArtifact) return "post_pr_convergence";
149000
+ return "redispatch_or_investigate";
149001
+ })();
149002
+ return {
149003
+ projectSlug: project.slug,
149004
+ projectName: project.name,
149005
+ issueId: opts.issueId,
149006
+ issueRuntime,
149007
+ hasArtifact,
149008
+ convergence: {
149009
+ cause: convergenceCause,
149010
+ action: convergenceAction,
149011
+ retryCount,
149012
+ reason: convergenceReason,
149013
+ at: issueRuntime?.lastConvergenceAt ?? null
149014
+ },
149015
+ pr: prStatus ? {
149016
+ url: prStatus.url ?? null,
149017
+ state: prStatus.state ?? null,
149018
+ number: prStatus.number ?? null,
149019
+ mergeable: prStatus.mergeable ?? null,
149020
+ currentIssueMatch: prStatus.currentIssueMatch ?? null,
149021
+ sourceBranch: prStatus.sourceBranch ?? null
149022
+ } : null,
149023
+ issue: issue2 ? {
149024
+ url: issue2.web_url ?? null,
149025
+ state: issue2.state ?? null,
149026
+ labels: issue2.labels ?? [],
149027
+ title: issue2.title ?? null
149028
+ } : null,
149029
+ recommendation: {
149030
+ summary: summaryParts.join(" | "),
149031
+ likelyNextAction
149032
+ }
149033
+ };
149034
+ }
149035
+ function formatIssueDoctor(result) {
149036
+ const lines = [
149037
+ `Issue run doctor \u2014 ${result.projectSlug}#${result.issueId}`,
149038
+ ` Artifact: ${result.hasArtifact ? "yes" : "no"}`,
149039
+ ` PR: ${result.pr?.url ?? "n/a"} (${result.pr?.state ?? "unknown"})`,
149040
+ ` Issue: ${result.issue?.url ?? "n/a"} (${result.issue?.state ?? "unknown"})`,
149041
+ ` Labels: ${result.issue?.labels?.join(", ") ?? "n/a"}`,
149042
+ ` Convergence cause: ${result.convergence.cause ?? "none"}`,
149043
+ ` Convergence action: ${result.convergence.action ?? "none"}`,
149044
+ ` Retry count: ${result.convergence.retryCount}`,
149045
+ ` Last reason: ${result.convergence.reason ?? "n/a"}`,
149046
+ ` Suggested next action: ${result.recommendation.likelyNextAction}`
149047
+ ];
149048
+ return lines.join("\n");
149049
+ }
149050
+
148930
149051
  // lib/observability/metrics.ts
148931
149052
  init_constants();
148932
149053
  import { readFile as readFile3 } from "node:fs/promises";
@@ -149509,6 +149630,26 @@ function registerCli(program, ctx) {
149509
149630
  ${result.checks.length} checks: ${result.errors} errors, ${result.warnings} warnings`);
149510
149631
  process.exit(result.errors > 0 ? 1 : 0);
149511
149632
  });
149633
+ 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) => {
149634
+ const workspaceDir = requireWorkspaceDir2(ctx.runtime, opts.workspace);
149635
+ const issueId = Number.parseInt(String(opts.issue), 10);
149636
+ if (!Number.isFinite(issueId)) {
149637
+ console.error(`Invalid issue id: ${opts.issue}`);
149638
+ process.exit(1);
149639
+ }
149640
+ const result = await runIssueDoctor({
149641
+ workspacePath: workspaceDir,
149642
+ projectSlug: String(opts.project),
149643
+ issueId,
149644
+ runCommand: ctx.runCommand,
149645
+ pluginConfig: ctx.pluginConfig
149646
+ });
149647
+ if (opts.json) {
149648
+ console.log(JSON.stringify(result, null, 2));
149649
+ return;
149650
+ }
149651
+ console.log(formatIssueDoctor(result));
149652
+ });
149512
149653
  doctor.option("-w, --workspace <path>", "Workspace directory").option("--fix", "Apply fixes for detected issues").action(async (opts) => {
149513
149654
  const workspaceDir = requireWorkspaceDir2(ctx.runtime, opts.workspace);
149514
149655
  const result = await runDoctor({ workspacePath: workspaceDir, fix: opts.fix ?? false, pluginConfig: ctx.pluginConfig });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mestreyoda/fabrica",
3
- "version": "0.2.35",
3
+ "version": "0.2.37",
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",