@mestreyoda/fabrica 0.2.31 → 0.2.34

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 +142 -47
  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.31") {
113909
- return "0.2.31";
113908
+ if ("0.2.34") {
113909
+ return "0.2.34";
113910
113910
  }
113911
113911
  try {
113912
113912
  const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
@@ -131466,6 +131466,13 @@ function detectExecutionContractViolation(messages) {
131466
131466
  evidence: nestedCommand
131467
131467
  };
131468
131468
  }
131469
+ const worktreeDrift = evidenceEntries.map((entry) => matchWorktreeDriftEvidence(entry.text)).find((match) => Boolean(match));
131470
+ if (worktreeDrift) {
131471
+ return {
131472
+ reason: "worktree_drift",
131473
+ evidence: worktreeDrift
131474
+ };
131475
+ }
131469
131476
  for (const entry of assistantEntries) {
131470
131477
  const metaSkillUsage = matchStrongMetaSkillUsage(entry.text);
131471
131478
  if (metaSkillUsage) {
@@ -131491,6 +131498,19 @@ function detectExecutionContractViolation(messages) {
131491
131498
  }
131492
131499
  return null;
131493
131500
  }
131501
+ function matchWorktreeDriftEvidence(text) {
131502
+ if (!text) return null;
131503
+ const patterns = [
131504
+ /ENOENT: .*\/home\/ubuntu\/\.openclaw\/workspace(?:\/[^\s'"`]+)?/,
131505
+ /^\/home\/ubuntu\/\.openclaw\/workspace$/m,
131506
+ /\/home\/ubuntu\/\.openclaw\/workspace(?:\/[^\s'"`]+)?/
131507
+ ];
131508
+ for (const pattern of patterns) {
131509
+ const match = text.match(pattern);
131510
+ if (match?.[0]) return match[0];
131511
+ }
131512
+ return null;
131513
+ }
131494
131514
  function collectWorkerTranscriptEvidence(messages) {
131495
131515
  const evidence = [];
131496
131516
  for (const message of messages) {
@@ -131914,48 +131934,49 @@ async function handleWorkerAgentEnd(opts) {
131914
131934
  }).catch(() => {
131915
131935
  });
131916
131936
  }
131917
- if (!observation.result) {
131918
- if (observation.executionContractViolation) {
131919
- if (context2) {
131920
- const violationPayload = {
131921
- sessionKey: opts.sessionKey,
131922
- projectSlug: context2.projectSlug,
131923
- issueId: context2.issueId,
131924
- role,
131925
- reason: "invalid_execution_path",
131926
- violationReason: observation.executionContractViolation.reason,
131927
- evidence: observation.executionContractViolation.evidence
131928
- };
131929
- await updateIssueRuntime(opts.workspaceDir, context2.projectSlug, context2.issueId, {
131930
- inconclusiveCompletionAt: (/* @__PURE__ */ new Date()).toISOString(),
131931
- inconclusiveCompletionReason: "invalid_execution_path"
131932
- }).catch(() => {
131933
- });
131934
- await log(opts.workspaceDir, "worker_execution_contract_violation", violationPayload).catch(() => {
131935
- });
131936
- await log(opts.workspaceDir, "worker_execution_recovery_started", violationPayload).catch(() => {
131937
- });
131938
- await log(opts.workspaceDir, "worker_completion_inconclusive", {
131939
- ...violationPayload
131940
- }).catch(() => {
131941
- });
131942
- } else {
131943
- const violationPayload = {
131944
- sessionKey: opts.sessionKey,
131945
- role,
131946
- reason: "invalid_execution_path",
131947
- violationReason: observation.executionContractViolation.reason,
131948
- evidence: observation.executionContractViolation.evidence
131949
- };
131950
- await log(opts.workspaceDir, "worker_execution_contract_violation", violationPayload).catch(() => {
131951
- });
131952
- await log(opts.workspaceDir, "worker_result_skipped", {
131953
- ...violationPayload
131954
- }).catch(() => {
131955
- });
131956
- }
131957
- return { applied: false, reason: "invalid_execution_path" };
131937
+ if (observation.executionContractViolation && (!observation.result || observation.executionContractViolation.reason === "worktree_drift")) {
131938
+ if (context2) {
131939
+ const violationPayload = {
131940
+ sessionKey: opts.sessionKey,
131941
+ projectSlug: context2.projectSlug,
131942
+ issueId: context2.issueId,
131943
+ role,
131944
+ reason: "invalid_execution_path",
131945
+ violationReason: observation.executionContractViolation.reason,
131946
+ evidence: observation.executionContractViolation.evidence
131947
+ };
131948
+ await updateIssueRuntime(opts.workspaceDir, context2.projectSlug, context2.issueId, {
131949
+ inconclusiveCompletionAt: (/* @__PURE__ */ new Date()).toISOString(),
131950
+ inconclusiveCompletionReason: "invalid_execution_path"
131951
+ }).catch(() => {
131952
+ });
131953
+ await log(opts.workspaceDir, "worker_execution_contract_violation", violationPayload).catch(() => {
131954
+ });
131955
+ await log(opts.workspaceDir, "worker_execution_recovery_started", violationPayload).catch(() => {
131956
+ });
131957
+ await log(opts.workspaceDir, "worker_completion_inconclusive", {
131958
+ ...violationPayload,
131959
+ hadResultLine: Boolean(observation.result)
131960
+ }).catch(() => {
131961
+ });
131962
+ } else {
131963
+ const violationPayload = {
131964
+ sessionKey: opts.sessionKey,
131965
+ role,
131966
+ reason: "invalid_execution_path",
131967
+ violationReason: observation.executionContractViolation.reason,
131968
+ evidence: observation.executionContractViolation.evidence
131969
+ };
131970
+ await log(opts.workspaceDir, "worker_execution_contract_violation", violationPayload).catch(() => {
131971
+ });
131972
+ await log(opts.workspaceDir, "worker_result_skipped", {
131973
+ ...violationPayload
131974
+ }).catch(() => {
131975
+ });
131958
131976
  }
131977
+ return { applied: false, reason: "invalid_execution_path" };
131978
+ }
131979
+ if (!observation.result) {
131959
131980
  if (context2 && observation.activityObserved) {
131960
131981
  await updateIssueRuntime(opts.workspaceDir, context2.projectSlug, context2.issueId, {
131961
131982
  inconclusiveCompletionAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -132597,15 +132618,17 @@ async function checkWorkerHealth(opts) {
132597
132618
  const startedAtMs = new Date(slot.startTime).getTime();
132598
132619
  const minutesActive = (Date.now() - startedAtMs) / 6e4;
132599
132620
  const hours = minutesActive / 60;
132621
+ let reviewablePrStatus = null;
132600
132622
  let hasReviewableArtifact = Boolean(
132601
132623
  issueRuntime?.currentPrNumber || issueRuntime?.currentPrUrl || issueRuntime?.artifactOfRecord?.prNumber
132602
132624
  );
132603
- if (!hasReviewableArtifact && issueIdNum) {
132625
+ if (issueIdNum) {
132604
132626
  try {
132605
132627
  const prStatus = await provider.getPrStatus(issueIdNum);
132606
- hasReviewableArtifact = Boolean(
132607
- prStatus.url && prStatus.state !== PrState.MERGED && prStatus.state !== PrState.CLOSED && prStatus.currentIssueMatch !== false
132608
- );
132628
+ if (prStatus.url && prStatus.state !== PrState.MERGED && prStatus.state !== PrState.CLOSED && prStatus.currentIssueMatch !== false) {
132629
+ reviewablePrStatus = prStatus;
132630
+ hasReviewableArtifact = true;
132631
+ }
132609
132632
  } catch {
132610
132633
  }
132611
132634
  }
@@ -132708,6 +132731,78 @@ async function checkWorkerHealth(opts) {
132708
132731
  fixes.push(fix);
132709
132732
  continue;
132710
132733
  }
132734
+ const quietMinutes = (() => {
132735
+ const lastObservableAt = sessionKey ? getLastObservableSessionActivityAt(sessionKey, sessions) : null;
132736
+ const referenceAt = lastObservableAt ?? agentAcceptedAt ?? dispatchRequestedAt ?? startedAtMs;
132737
+ if (!referenceAt || Number.isNaN(referenceAt)) return minutesActive;
132738
+ return (Date.now() - referenceAt) / 6e4;
132739
+ })();
132740
+ if (role === "developer" && issue2 && issueIdNum && hasReviewableArtifact && reviewablePrStatus?.url && minutesActive >= stallTimeoutMinutes && quietMinutes >= Math.max(8, Math.floor(stallTimeoutMinutes / 2))) {
132741
+ const fix = {
132742
+ issue: {
132743
+ type: "stalled_with_artifact",
132744
+ severity: "critical",
132745
+ project: project.name,
132746
+ projectSlug,
132747
+ role,
132748
+ level,
132749
+ sessionKey,
132750
+ issueId: slot.issueId,
132751
+ slotIndex,
132752
+ message: `${role.toUpperCase()} ${level}[${slotIndex}] has an open PR but stayed idle for ${Math.round(quietMinutes)}m without converging`
132753
+ },
132754
+ fixed: false
132755
+ };
132756
+ if (autoFix) {
132757
+ const channel = project.channels?.[0];
132758
+ await notify(
132759
+ {
132760
+ type: "workerRecoveryExhausted",
132761
+ project: project.name,
132762
+ issueId: issueIdNum,
132763
+ issueUrl: issue2.web_url,
132764
+ issueTitle: issue2.title,
132765
+ role,
132766
+ detail: `Open PR ${reviewablePrStatus.url} has stalled for ${Math.round(quietMinutes)} minutes without a trustworthy completion. Re-queueing to ${slotQueueLabel}.`,
132767
+ nextState: slotQueueLabel,
132768
+ dispatchCycleId: slot.dispatchCycleId ?? issueRuntime?.lastDispatchCycleId ?? null,
132769
+ dispatchRunId: slot.dispatchRunId ?? issueRuntime?.dispatchRunId ?? null
132770
+ },
132771
+ {
132772
+ workspaceDir,
132773
+ config: notificationConfig,
132774
+ target: channel ? {
132775
+ channelId: channel.channelId,
132776
+ channel: channel.channel,
132777
+ accountId: channel.accountId,
132778
+ messageThreadId: channel.messageThreadId
132779
+ } : void 0,
132780
+ runCommand
132781
+ }
132782
+ ).catch(() => {
132783
+ });
132784
+ await revertLabel(fix, expectedLabel, slotQueueLabel);
132785
+ if (!fix.labelRevertFailed) {
132786
+ await deactivateSlot();
132787
+ await updateIssueRuntime(workspaceDir, projectSlug, issueIdNum, {
132788
+ inconclusiveCompletionAt: (/* @__PURE__ */ new Date()).toISOString(),
132789
+ inconclusiveCompletionReason: "stalled_with_artifact",
132790
+ progressNotifiedAt: null
132791
+ }).catch(() => {
132792
+ });
132793
+ fix.fixed = true;
132794
+ await auditHealthFixApplied(workspaceDir, fix, {
132795
+ action: "requeue_issue",
132796
+ fromLabel: expectedLabel,
132797
+ toLabel: slotQueueLabel,
132798
+ idleMinutes: Math.round(quietMinutes),
132799
+ deliveryState
132800
+ });
132801
+ }
132802
+ }
132803
+ fixes.push(fix);
132804
+ continue;
132805
+ }
132711
132806
  if (hours > staleWorkerHours) {
132712
132807
  const fix = {
132713
132808
  issue: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mestreyoda/fabrica",
3
- "version": "0.2.31",
3
+ "version": "0.2.34",
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",