@mestreyoda/fabrica 0.1.12 → 0.1.13
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 +133 -20
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -110768,7 +110768,7 @@ var init_registry = __esm({
|
|
|
110768
110768
|
senior: "\u{1F9E0}"
|
|
110769
110769
|
},
|
|
110770
110770
|
fallbackEmoji: "\u{1F50D}",
|
|
110771
|
-
completionResults: ["pass", "fail", "refine", "blocked"],
|
|
110771
|
+
completionResults: ["pass", "fail", "fail_infra", "refine", "blocked"],
|
|
110772
110772
|
sessionKeyPattern: "tester",
|
|
110773
110773
|
notifications: { onStart: true, onComplete: true }
|
|
110774
110774
|
},
|
|
@@ -111329,8 +111329,8 @@ import fsSync from "node:fs";
|
|
|
111329
111329
|
import path5 from "node:path";
|
|
111330
111330
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
111331
111331
|
function getCurrentVersion() {
|
|
111332
|
-
if ("0.1.
|
|
111333
|
-
return "0.1.
|
|
111332
|
+
if ("0.1.13") {
|
|
111333
|
+
return "0.1.13";
|
|
111334
111334
|
}
|
|
111335
111335
|
try {
|
|
111336
111336
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -119852,6 +119852,22 @@ PR merged \u2014 issue closed automatically (was stuck in ${event.fromState})`;
|
|
|
119852
119852
|
\u{1F3C1} Done \u2014 no human action needed.`;
|
|
119853
119853
|
return msg;
|
|
119854
119854
|
}
|
|
119855
|
+
case "infraFailure": {
|
|
119856
|
+
const icon = event.infraFailCount >= 2 ? "\u{1F6A8}" : "\u26A0\uFE0F";
|
|
119857
|
+
let msg = `${icon} Infrastructure failure on #${event.issueId} (attempt ${event.infraFailCount})`;
|
|
119858
|
+
msg += `
|
|
119859
|
+
${event.summary}`;
|
|
119860
|
+
msg += `
|
|
119861
|
+
\u{1F4CB} [Issue #${event.issueId}](${event.issueUrl})`;
|
|
119862
|
+
if (event.infraFailCount >= 2) {
|
|
119863
|
+
msg += `
|
|
119864
|
+
\u2192 Circuit breaker tripped \u2014 moved to Refining (operator intervention required)`;
|
|
119865
|
+
} else {
|
|
119866
|
+
msg += `
|
|
119867
|
+
\u2192 Returned to To Test queue \u2014 will retry after toolchain is fixed`;
|
|
119868
|
+
}
|
|
119869
|
+
return msg;
|
|
119870
|
+
}
|
|
119855
119871
|
}
|
|
119856
119872
|
}
|
|
119857
119873
|
async function sendMessage(target, message, channel, workspaceDir, runtime, accountId, runCommand, messageThreadId, auditMeta) {
|
|
@@ -120589,10 +120605,10 @@ init_audit();
|
|
|
120589
120605
|
init_migrate_layout();
|
|
120590
120606
|
init_roles();
|
|
120591
120607
|
init_workflow();
|
|
120608
|
+
init_labels();
|
|
120592
120609
|
|
|
120593
120610
|
// lib/tools/tasks/public-output-sanitizer.ts
|
|
120594
120611
|
var SECRET_PATTERNS = [
|
|
120595
|
-
/\b[A-Za-z_][A-Za-z0-9_]*=([^\s]+)/g,
|
|
120596
120612
|
/\b(?:ghp_|gho_|github_pat_|sk-|xoxb-|xoxp-|AIza|AKIA|glpat-)[A-Za-z0-9._-]*/g,
|
|
120597
120613
|
/\b(?:token|secret|api[_-]?key|password|passwd|authorization|bearer)\b\s*[:=]\s*[^\s]+/gi
|
|
120598
120614
|
];
|
|
@@ -120917,6 +120933,7 @@ function matchesReviewArtifact(comment, artifactId, artifactType) {
|
|
|
120917
120933
|
}
|
|
120918
120934
|
return comment.state === "COMMENTED" && !comment.path;
|
|
120919
120935
|
}
|
|
120936
|
+
var INFRA_FAIL_CIRCUIT_BREAKER_THRESHOLD = 2;
|
|
120920
120937
|
function createWorkFinishTool(ctx) {
|
|
120921
120938
|
return (toolCtx) => ({
|
|
120922
120939
|
name: "work_finish",
|
|
@@ -120928,7 +120945,7 @@ function createWorkFinishTool(ctx) {
|
|
|
120928
120945
|
properties: {
|
|
120929
120946
|
channelId: { type: "string", description: "YOUR chat/group ID \u2014 the numeric ID of the chat you are in right now (e.g. '-1003844794417'). Do NOT guess; use the ID of the conversation this message came from." },
|
|
120930
120947
|
role: { type: "string", enum: getAllRoleIds(), description: "Worker role" },
|
|
120931
|
-
result: { type: "string", enum: ["done", "pass", "fail", "refine", "blocked", "approve", "reject"], description: "Completion result" },
|
|
120948
|
+
result: { type: "string", enum: ["done", "pass", "fail", "fail_infra", "refine", "blocked", "approve", "reject"], description: "Completion result. Use fail_infra (tester only) when the test toolchain is missing or broken \u2014 this keeps the issue in the test queue instead of routing it to the developer." },
|
|
120932
120949
|
summary: { type: "string", description: "Brief summary" },
|
|
120933
120950
|
prUrl: { type: "string", description: "PR/MR URL (auto-detected if omitted)" },
|
|
120934
120951
|
createdTasks: {
|
|
@@ -121010,6 +121027,79 @@ function createWorkFinishTool(ctx) {
|
|
|
121010
121027
|
})),
|
|
121011
121028
|
keyTransitions: resolvedConfig.workflowMeta.keyTransitions
|
|
121012
121029
|
});
|
|
121030
|
+
if (role === "tester" && result === "fail_infra") {
|
|
121031
|
+
const currentInfraFails = (issueRuntime?.infraFailCount ?? 0) + 1;
|
|
121032
|
+
await updateIssueRuntime(workspaceDir, project.slug, issueId, {
|
|
121033
|
+
infraFailCount: currentInfraFails
|
|
121034
|
+
});
|
|
121035
|
+
await log(workspaceDir, "infra_failure", {
|
|
121036
|
+
project: project.name,
|
|
121037
|
+
issue: issueId,
|
|
121038
|
+
role,
|
|
121039
|
+
result,
|
|
121040
|
+
summary: summary ?? null,
|
|
121041
|
+
infraFailCount: currentInfraFails
|
|
121042
|
+
});
|
|
121043
|
+
const notifyConfig = getNotificationConfig(ctx.pluginConfig);
|
|
121044
|
+
const target = resolveNotifyChannel([], project.channels);
|
|
121045
|
+
const issueUrl = `https://github.com/${project.repo}/issues/${issueId}`;
|
|
121046
|
+
await notify(
|
|
121047
|
+
{
|
|
121048
|
+
type: "infraFailure",
|
|
121049
|
+
project: project.name,
|
|
121050
|
+
issueId,
|
|
121051
|
+
issueUrl,
|
|
121052
|
+
summary: summary ?? "Infrastructure failure during testing",
|
|
121053
|
+
infraFailCount: currentInfraFails
|
|
121054
|
+
},
|
|
121055
|
+
{
|
|
121056
|
+
workspaceDir,
|
|
121057
|
+
config: notifyConfig,
|
|
121058
|
+
channelId: target?.channelId,
|
|
121059
|
+
channel: target?.channel ?? "telegram",
|
|
121060
|
+
runtime: ctx.runtime,
|
|
121061
|
+
accountId: target?.accountId,
|
|
121062
|
+
messageThreadId: target?.messageThreadId,
|
|
121063
|
+
runCommand: ctx.runCommand
|
|
121064
|
+
}
|
|
121065
|
+
).catch((err) => {
|
|
121066
|
+
getRootLogger().warn(`infra_failure notification failed: ${err}`);
|
|
121067
|
+
});
|
|
121068
|
+
if (currentInfraFails >= INFRA_FAIL_CIRCUIT_BREAKER_THRESHOLD) {
|
|
121069
|
+
await log(workspaceDir, "infra_failure_circuit_breaker", {
|
|
121070
|
+
project: project.name,
|
|
121071
|
+
issue: issueId,
|
|
121072
|
+
infraFailCount: currentInfraFails
|
|
121073
|
+
});
|
|
121074
|
+
await resilientLabelTransition(provider, issueId, "Testing", "Refining");
|
|
121075
|
+
} else {
|
|
121076
|
+
await resilientLabelTransition(provider, issueId, "Testing", "To Test");
|
|
121077
|
+
}
|
|
121078
|
+
await deactivateWorker(workspaceDir, project.slug, "tester", {
|
|
121079
|
+
level: slotLevel,
|
|
121080
|
+
slotIndex,
|
|
121081
|
+
issueId: String(issueId)
|
|
121082
|
+
});
|
|
121083
|
+
await recordIssueLifecycle({
|
|
121084
|
+
workspaceDir,
|
|
121085
|
+
slug: project.slug,
|
|
121086
|
+
issueId,
|
|
121087
|
+
stage: "session_completed",
|
|
121088
|
+
sessionKey: toolCtx.sessionKey ?? null,
|
|
121089
|
+
details: { role, result, infraFailCount: currentInfraFails }
|
|
121090
|
+
}).catch(() => {
|
|
121091
|
+
});
|
|
121092
|
+
return jsonResult2({
|
|
121093
|
+
success: true,
|
|
121094
|
+
project: project.name,
|
|
121095
|
+
projectSlug: project.slug,
|
|
121096
|
+
issueId,
|
|
121097
|
+
role,
|
|
121098
|
+
result,
|
|
121099
|
+
infraFailCount: currentInfraFails,
|
|
121100
|
+
circuitBroken: currentInfraFails >= INFRA_FAIL_CIRCUIT_BREAKER_THRESHOLD
|
|
121101
|
+
});
|
|
121102
|
+
}
|
|
121013
121103
|
if (!getRule(role, result, workflow))
|
|
121014
121104
|
throw new Error(`Invalid completion: ${role}:${result}`);
|
|
121015
121105
|
const repoPath = resolveRepoPath(project.repo);
|
|
@@ -121128,6 +121218,9 @@ function createWorkFinishTool(ctx) {
|
|
|
121128
121218
|
details: { role, result }
|
|
121129
121219
|
}).catch(() => {
|
|
121130
121220
|
});
|
|
121221
|
+
if (role === "tester" && issueRuntime?.infraFailCount) {
|
|
121222
|
+
await updateIssueRuntime(workspaceDir, project.slug, issueId, { infraFailCount: 0 });
|
|
121223
|
+
}
|
|
121131
121224
|
return jsonResult2({
|
|
121132
121225
|
success: true,
|
|
121133
121226
|
project: project.name,
|
|
@@ -136063,25 +136156,39 @@ async function runHeartbeatTick(ctx, logger6, mode) {
|
|
|
136063
136156
|
})
|
|
136064
136157
|
);
|
|
136065
136158
|
const tickFn = lifecycle ? () => lifecycle.track(mode === "repair" ? "recovery" : "heartbeat", {}, run) : run;
|
|
136066
|
-
let
|
|
136067
|
-
|
|
136068
|
-
|
|
136069
|
-
|
|
136159
|
+
let resolveTick;
|
|
136160
|
+
let rejectTick;
|
|
136161
|
+
const tickPromise = new Promise((res, rej) => {
|
|
136162
|
+
resolveTick = res;
|
|
136163
|
+
rejectTick = rej;
|
|
136164
|
+
});
|
|
136165
|
+
tickPromise.catch(() => {
|
|
136166
|
+
});
|
|
136167
|
+
const wrappedTickFn = async () => {
|
|
136168
|
+
try {
|
|
136169
|
+
const result = await tickFn();
|
|
136170
|
+
resolveTick(result);
|
|
136171
|
+
return result;
|
|
136172
|
+
} catch (err) {
|
|
136173
|
+
rejectTick(err);
|
|
136174
|
+
throw err;
|
|
136175
|
+
}
|
|
136070
136176
|
};
|
|
136177
|
+
const HARD_TICK_TIMEOUT_MS = 5 * 6e4;
|
|
136071
136178
|
const raceResult = await raceWithTimeout(wrappedTickFn, DEFAULT_TICK_TIMEOUT_MS, () => {
|
|
136072
136179
|
_ticksTimedOut++;
|
|
136073
136180
|
timedOut = true;
|
|
136074
136181
|
logger6.warn(`work_heartbeat ${mode} tick timed out after ${DEFAULT_TICK_TIMEOUT_MS}ms (total timeouts: ${_ticksTimedOut})`);
|
|
136075
|
-
|
|
136076
|
-
|
|
136077
|
-
_tickRunning[mode] = false;
|
|
136078
|
-
_anyTickRunning = false;
|
|
136079
|
-
});
|
|
136080
|
-
} else {
|
|
136081
|
-
logger6.error("tick_mutex: tickPromise undefined in timeout handler \u2014 forcing mutex release");
|
|
136182
|
+
const hardTimeout = setTimeout(() => {
|
|
136183
|
+
logger6.error("tick_mutex: hard timeout \u2014 forcing mutex release");
|
|
136082
136184
|
_tickRunning[mode] = false;
|
|
136083
136185
|
_anyTickRunning = false;
|
|
136084
|
-
}
|
|
136186
|
+
}, HARD_TICK_TIMEOUT_MS);
|
|
136187
|
+
tickPromise.finally(() => {
|
|
136188
|
+
clearTimeout(hardTimeout);
|
|
136189
|
+
_tickRunning[mode] = false;
|
|
136190
|
+
_anyTickRunning = false;
|
|
136191
|
+
});
|
|
136085
136192
|
});
|
|
136086
136193
|
void raceResult;
|
|
136087
136194
|
} catch (err) {
|
|
@@ -138569,15 +138676,21 @@ Install manually: curl -LsSf ${UV_INSTALL_URL} | sh`
|
|
|
138569
138676
|
var PYTHON_TOOLCHAIN_PACKAGES = ["ruff", "mypy", "pip-audit"];
|
|
138570
138677
|
var TOOLCHAIN_DIR = ".openclaw/toolchains/python";
|
|
138571
138678
|
var TOOLCHAIN_FINGERPRINT_FILE = "toolchain.sha256";
|
|
138572
|
-
function toolchainFingerprint() {
|
|
138573
|
-
|
|
138679
|
+
async function toolchainFingerprint(runCommand) {
|
|
138680
|
+
let pythonVersion = "unknown";
|
|
138681
|
+
try {
|
|
138682
|
+
const result = await runCommand("python3", ["--version"], { timeout: 5e3 });
|
|
138683
|
+
if (result.exitCode === 0) pythonVersion = result.stdout.trim();
|
|
138684
|
+
} catch {
|
|
138685
|
+
}
|
|
138686
|
+
return createHash4("sha256").update(PYTHON_TOOLCHAIN_PACKAGES.join(",") + ":" + pythonVersion).digest("hex");
|
|
138574
138687
|
}
|
|
138575
138688
|
async function ensurePythonToolchain(runCommand, homeDir) {
|
|
138576
138689
|
const home = homeDir ?? process.env.HOME ?? "/tmp";
|
|
138577
138690
|
const toolchainPath = path34.join(home, TOOLCHAIN_DIR);
|
|
138578
138691
|
const ruffPath = path34.join(toolchainPath, "bin", "ruff");
|
|
138579
138692
|
const fingerprintPath = path34.join(toolchainPath, TOOLCHAIN_FINGERPRINT_FILE);
|
|
138580
|
-
const expectedFp = toolchainFingerprint();
|
|
138693
|
+
const expectedFp = await toolchainFingerprint(runCommand);
|
|
138581
138694
|
if (await isValidBinary(ruffPath)) {
|
|
138582
138695
|
try {
|
|
138583
138696
|
const currentFp = (await fs34.readFile(fingerprintPath, "utf-8")).trim();
|