@pushpalsdev/cli 1.0.29 → 1.0.30
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/pushpals-cli.js
CHANGED
|
@@ -3953,8 +3953,45 @@ function formatSessionEventLine(event) {
|
|
|
3953
3953
|
}
|
|
3954
3954
|
return null;
|
|
3955
3955
|
}
|
|
3956
|
+
function buildSessionEventReplayFingerprint(event) {
|
|
3957
|
+
const type = String(event.type ?? "").trim().toLowerCase();
|
|
3958
|
+
if (type !== "status")
|
|
3959
|
+
return null;
|
|
3960
|
+
const payload = event.payload ?? {};
|
|
3961
|
+
const source = String(event.from ?? payload.agentId ?? "status").trim().toLowerCase();
|
|
3962
|
+
const state = String(payload.state ?? "").trim().toLowerCase();
|
|
3963
|
+
const detail = String(payload.detail ?? "").trim().toLowerCase();
|
|
3964
|
+
const message = String(payload.message ?? "").trim().toLowerCase();
|
|
3965
|
+
return {
|
|
3966
|
+
source,
|
|
3967
|
+
fingerprint: `${type}:${source}:${state}:${detail}:${message}`
|
|
3968
|
+
};
|
|
3969
|
+
}
|
|
3970
|
+
function createSessionEventReplayFilter() {
|
|
3971
|
+
const seenEventIds = new Set;
|
|
3972
|
+
const lastStatusFingerprintBySource = new Map;
|
|
3973
|
+
return {
|
|
3974
|
+
shouldRender(event) {
|
|
3975
|
+
const eventId = String(event.id ?? "").trim();
|
|
3976
|
+
if (eventId) {
|
|
3977
|
+
if (seenEventIds.has(eventId))
|
|
3978
|
+
return false;
|
|
3979
|
+
seenEventIds.add(eventId);
|
|
3980
|
+
}
|
|
3981
|
+
const replayStatus = buildSessionEventReplayFingerprint(event);
|
|
3982
|
+
if (!replayStatus)
|
|
3983
|
+
return true;
|
|
3984
|
+
const previous = lastStatusFingerprintBySource.get(replayStatus.source);
|
|
3985
|
+
if (previous === replayStatus.fingerprint)
|
|
3986
|
+
return false;
|
|
3987
|
+
lastStatusFingerprintBySource.set(replayStatus.source, replayStatus.fingerprint);
|
|
3988
|
+
return true;
|
|
3989
|
+
}
|
|
3990
|
+
};
|
|
3991
|
+
}
|
|
3956
3992
|
async function runSessionStream(serverUrl, sessionId, client, print, signal) {
|
|
3957
3993
|
let cursor = 0;
|
|
3994
|
+
const replayFilter = createSessionEventReplayFilter();
|
|
3958
3995
|
while (!signal.aborted) {
|
|
3959
3996
|
try {
|
|
3960
3997
|
const response = await fetchWithTimeout(`${serverUrl}/sessions/${encodeURIComponent(sessionId)}/events${buildClientTransportQuery(cursor, client)}`, {}, 15000);
|
|
@@ -4004,6 +4041,8 @@ async function runSessionStream(serverUrl, sessionId, client, print, signal) {
|
|
|
4004
4041
|
cursor = Math.max(cursor, blockCursor, serverCursor);
|
|
4005
4042
|
if (!parsed.envelope)
|
|
4006
4043
|
continue;
|
|
4044
|
+
if (!replayFilter.shouldRender(parsed.envelope))
|
|
4045
|
+
continue;
|
|
4007
4046
|
const line = formatSessionEventLine(parsed.envelope);
|
|
4008
4047
|
if (line)
|
|
4009
4048
|
print(line);
|
|
@@ -4506,6 +4545,7 @@ export {
|
|
|
4506
4545
|
ensureWorkerpalDockerImageReady,
|
|
4507
4546
|
ensureRuntimeBinaries,
|
|
4508
4547
|
downloadRuntimeAssetsFromSourceTag,
|
|
4548
|
+
createSessionEventReplayFilter,
|
|
4509
4549
|
copyTrackedRepoPath,
|
|
4510
4550
|
cleanupLingeringWorkerpalWarmContainers,
|
|
4511
4551
|
cleanupLingeringPushPalsGitWorktrees,
|
package/package.json
CHANGED
|
@@ -130,14 +130,51 @@ export function redactSensitiveText(value: string): string {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
export function buildCriticRevisionIssues(
|
|
133
|
-
critic:
|
|
133
|
+
critic:
|
|
134
|
+
| {
|
|
135
|
+
score: number;
|
|
136
|
+
findings?: string[];
|
|
137
|
+
mustFix?: string[];
|
|
138
|
+
revisionGuidance?: string;
|
|
139
|
+
}
|
|
140
|
+
| null
|
|
141
|
+
| undefined,
|
|
134
142
|
qualityCriticMinScore: number,
|
|
135
143
|
): string[] {
|
|
136
144
|
if (!critic) return [];
|
|
137
145
|
if (critic.score >= qualityCriticMinScore) return [];
|
|
138
|
-
|
|
146
|
+
const issues = [
|
|
139
147
|
`Critic score ${critic.score.toFixed(1)} is below required threshold ${qualityCriticMinScore}.`,
|
|
140
148
|
];
|
|
149
|
+
const mustFix = Array.isArray(critic.mustFix) ? critic.mustFix : [];
|
|
150
|
+
const findings = Array.isArray(critic.findings) ? critic.findings : [];
|
|
151
|
+
const revisionGuidance = String(critic.revisionGuidance ?? "").trim();
|
|
152
|
+
const actionableItems = (mustFix.length > 0 ? mustFix : findings)
|
|
153
|
+
.map((entry) => toSingleLine(entry, 180))
|
|
154
|
+
.filter(Boolean)
|
|
155
|
+
.slice(0, 3);
|
|
156
|
+
for (const item of actionableItems) {
|
|
157
|
+
issues.push(mustFix.length > 0 ? `Critic must-fix: ${item}` : `Critic finding: ${item}`);
|
|
158
|
+
}
|
|
159
|
+
if (revisionGuidance) {
|
|
160
|
+
issues.push(`Critic revision guidance: ${toSingleLine(revisionGuidance, 220)}`);
|
|
161
|
+
}
|
|
162
|
+
return issues;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function buildQualityGateRevisionIssues(
|
|
166
|
+
qualityIssues: string[],
|
|
167
|
+
critic: CriticReview | null,
|
|
168
|
+
qualityCriticMinScore: number,
|
|
169
|
+
): string[] {
|
|
170
|
+
const normalizedQualityIssues = qualityIssues
|
|
171
|
+
.map((entry) => String(entry ?? "").trim())
|
|
172
|
+
.filter(Boolean);
|
|
173
|
+
if (!critic || critic.score >= qualityCriticMinScore) {
|
|
174
|
+
return [...normalizedQualityIssues];
|
|
175
|
+
}
|
|
176
|
+
const merged = [...normalizedQualityIssues, ...buildCriticRevisionIssues(critic, qualityCriticMinScore)];
|
|
177
|
+
return [...new Set(merged)];
|
|
141
178
|
}
|
|
142
179
|
|
|
143
180
|
export function resolveReviewFixCompletionBranch(
|
|
@@ -3006,9 +3043,10 @@ export async function executeJob(
|
|
|
3006
3043
|
: executor === "openai_codex"
|
|
3007
3044
|
? await runCodexCriticReview(repo, attemptParams, quality, runtimeConfig, onLog)
|
|
3008
3045
|
: await runTaskCriticReview(repo, attemptParams, quality, runtimeConfig, onLog);
|
|
3046
|
+
const deterministicRequiresRevision = !quality.ok;
|
|
3009
3047
|
const criticRequiresRevision = Boolean(critic && critic.score < qualityCriticMinScore);
|
|
3010
3048
|
|
|
3011
|
-
if (!criticRequiresRevision) {
|
|
3049
|
+
if (!deterministicRequiresRevision && !criticRequiresRevision) {
|
|
3012
3050
|
if (critic) {
|
|
3013
3051
|
onLog?.(
|
|
3014
3052
|
"stdout",
|
|
@@ -3018,10 +3056,11 @@ export async function executeJob(
|
|
|
3018
3056
|
return result;
|
|
3019
3057
|
}
|
|
3020
3058
|
|
|
3021
|
-
const issues
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3059
|
+
const issues = buildQualityGateRevisionIssues(
|
|
3060
|
+
quality.issues,
|
|
3061
|
+
critic,
|
|
3062
|
+
qualityCriticMinScore,
|
|
3063
|
+
);
|
|
3025
3064
|
const issueSummary = issues.map((entry) => toSingleLine(entry, 180)).join(" | ");
|
|
3026
3065
|
if (revisionAttempt >= qualityMaxAutoRevisions) {
|
|
3027
3066
|
if (qualitySoftPassOnExhausted) {
|