@hamp10/agentforge 0.2.32 → 0.2.33
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/package.json +1 -1
- package/src/worker.js +84 -7
package/package.json
CHANGED
package/src/worker.js
CHANGED
|
@@ -854,11 +854,8 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
854
854
|
addLines(this._gitOutput(baseline.root, ['diff', '--name-only'], 10000));
|
|
855
855
|
addLines(this._gitOutput(baseline.root, ['diff', '--name-only', '--cached'], 10000));
|
|
856
856
|
addLines(this._gitOutput(baseline.root, ['ls-files', '--others', '--exclude-standard'], 10000));
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
const rel = rawLine.length >= 3 && rawLine[2] === ' ' ? rawLine.slice(3) : rawLine.trim().replace(/^..\s+/, '');
|
|
860
|
-
const pathName = rel.includes(' -> ') ? rel.split(' -> ').pop() : rel;
|
|
861
|
-
if (pathName) names.add(pathName);
|
|
857
|
+
for (const pathName of this._parseGitStatusPaths(this._gitStatusPorcelain(baseline.root, 10000))) {
|
|
858
|
+
names.add(pathName);
|
|
862
859
|
}
|
|
863
860
|
|
|
864
861
|
const initialDirty = new Set(baseline.initialDirtyPaths || []);
|
|
@@ -890,6 +887,45 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
890
887
|
return restored;
|
|
891
888
|
}
|
|
892
889
|
|
|
890
|
+
_restoreGeneratedScopedUiTargets(repoBaselines, userMessage) {
|
|
891
|
+
if (!this._isBroadUiQualityTask(userMessage)) return [];
|
|
892
|
+
if (!Array.isArray(repoBaselines) || repoBaselines.length === 0) return [];
|
|
893
|
+
const { slugs: allowedSlugs, pageOnly } = this._extractExplicitScope(userMessage);
|
|
894
|
+
if (allowedSlugs.length === 0 || !pageOnly) return [];
|
|
895
|
+
|
|
896
|
+
const restored = [];
|
|
897
|
+
for (const baseline of repoBaselines) {
|
|
898
|
+
const names = new Set();
|
|
899
|
+
const addLines = (output) => {
|
|
900
|
+
for (const rel of String(output || '').split('\n').map(line => line.trim()).filter(Boolean)) {
|
|
901
|
+
names.add(rel);
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
addLines(this._gitOutput(baseline.root, ['diff', '--name-only'], 10000));
|
|
905
|
+
addLines(this._gitOutput(baseline.root, ['diff', '--name-only', '--cached'], 10000));
|
|
906
|
+
addLines(this._gitOutput(baseline.root, ['ls-files', '--others', '--exclude-standard'], 10000));
|
|
907
|
+
for (const pathName of this._parseGitStatusPaths(this._gitStatusPorcelain(baseline.root, 10000))) {
|
|
908
|
+
names.add(pathName);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const initialDirty = new Set(baseline.initialDirtyPaths || []);
|
|
912
|
+
const files = [...names]
|
|
913
|
+
.filter(rel => !initialDirty.has(rel))
|
|
914
|
+
.filter(rel => this._scopeAllowsChangedPath(baseline, rel, allowedSlugs, pageOnly, userMessage))
|
|
915
|
+
.filter(rel => !this._gitPathExistsAtRef(baseline.root, baseline.head || 'HEAD', rel))
|
|
916
|
+
.sort();
|
|
917
|
+
if (files.length === 0) continue;
|
|
918
|
+
|
|
919
|
+
this._gitRun(baseline.root, ['restore', '--staged', '--', ...files], 10000);
|
|
920
|
+
const untracked = files.filter(file => this._gitOutput(baseline.root, ['ls-files', '--others', '--exclude-standard', '--', file], 5000));
|
|
921
|
+
if (untracked.length > 0) {
|
|
922
|
+
this._gitRun(baseline.root, ['clean', '-fd', '--', ...untracked], 10000);
|
|
923
|
+
}
|
|
924
|
+
restored.push({ repo: baseline.root, files: files.slice(0, 12), restoredCount: files.length });
|
|
925
|
+
}
|
|
926
|
+
return restored;
|
|
927
|
+
}
|
|
928
|
+
|
|
893
929
|
_formatScopeDriftRestoreNudge(restored) {
|
|
894
930
|
const lines = restored.slice(0, 5).flatMap(w => [
|
|
895
931
|
`- ${w.repo}: restored ${w.restoredCount} out-of-scope file(s); allowed scope tokens: ${w.allowedSlugs.join(', ')}${w.pageOnly ? ' (page/source files only)' : ''}`,
|
|
@@ -1294,6 +1330,19 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
1294
1330
|
].join('\n');
|
|
1295
1331
|
}
|
|
1296
1332
|
|
|
1333
|
+
_formatGeneratedScopedUiResetNudge(restored) {
|
|
1334
|
+
if (!Array.isArray(restored) || restored.length === 0) return '';
|
|
1335
|
+
const lines = restored.slice(0, 5).flatMap(item => [
|
|
1336
|
+
`- ${item.repo}: removed ${item.restoredCount} rejected generated scoped file(s) before retrying`,
|
|
1337
|
+
...item.files.map(file => ` ${file}`),
|
|
1338
|
+
]);
|
|
1339
|
+
return [
|
|
1340
|
+
'AgentForge removed the rejected generated target file(s) before this retry.',
|
|
1341
|
+
...lines,
|
|
1342
|
+
'Treat those removed files as failed output, not source material. Rebuild the requested target page-owned file(s) from inspected project context and comparable existing pages, then verify the rebuilt pages visually.',
|
|
1343
|
+
].join('\n');
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1297
1346
|
_findUiImplementationArtifactChanges(repoBaselines, userMessage) {
|
|
1298
1347
|
if (!this._isBroadUiQualityTask(userMessage)) return [];
|
|
1299
1348
|
if (!Array.isArray(repoBaselines) || repoBaselines.length === 0) return [];
|
|
@@ -3469,6 +3518,20 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
3469
3518
|
// generic discovery loop after the user has steered the active task.
|
|
3470
3519
|
const withTaskContext = (message) => activeGuidePrefix() + retryContextPrefix + taskContextPrefix + message;
|
|
3471
3520
|
finalMessage = withTaskContext(finalMessage);
|
|
3521
|
+
const applyGuideToSemanticScope = (guideText) => {
|
|
3522
|
+
const text = String(guideText || '').trim();
|
|
3523
|
+
if (!text) return;
|
|
3524
|
+
const before = this._extractExplicitScope(scopeAwareUserMessage);
|
|
3525
|
+
const merged = `${scopeAwareUserMessage}\n\n[Active user guide]\n${text}`;
|
|
3526
|
+
const after = this._extractExplicitScope(merged);
|
|
3527
|
+
if (after.slugs.length === 0) return;
|
|
3528
|
+
scopeAwareUserMessage = merged;
|
|
3529
|
+
const beforeKey = `${before.slugs.join(',')}|${before.pageOnly}`;
|
|
3530
|
+
const afterKey = `${after.slugs.join(',')}|${after.pageOnly}`;
|
|
3531
|
+
if (beforeKey !== afterKey) {
|
|
3532
|
+
agentLog(`[${taskId}] 🎯 Updated active scope from guide: ${after.slugs.join(', ')}${after.pageOnly ? ' (page/source files only)' : ''}`);
|
|
3533
|
+
}
|
|
3534
|
+
};
|
|
3472
3535
|
|
|
3473
3536
|
// If conversation history was loaded from DB (e.g. session expired, worker restarted,
|
|
3474
3537
|
// or user returning hours later), prepend it so the agent has full context.
|
|
@@ -3794,6 +3857,7 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
3794
3857
|
nudgeCount = 0;
|
|
3795
3858
|
uiRepairNudgeCount = 0;
|
|
3796
3859
|
uiVerificationRetryCount = 0;
|
|
3860
|
+
applyGuideToSemanticScope(preRunGuide.text);
|
|
3797
3861
|
agentLog(`[${taskId}] 🧭 Applying ${preRunGuide.count} guide note(s) before iteration ${iteration}`);
|
|
3798
3862
|
this.send({ type: 'task_progress', taskId, agentId, roomId, output: 'Guide received; applying it to the current task...' });
|
|
3799
3863
|
iterationMessage = `${preRunGuide.text}\n\n${iterationMessage}`;
|
|
@@ -4112,6 +4176,7 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
4112
4176
|
nudgeCount = 0;
|
|
4113
4177
|
uiRepairNudgeCount = 0;
|
|
4114
4178
|
uiVerificationRetryCount = 0;
|
|
4179
|
+
applyGuideToSemanticScope(postRunGuide.text);
|
|
4115
4180
|
agentLog(`[${taskId}] 🧭 Applying ${postRunGuide.count} guide note(s) after iteration ${iteration}`);
|
|
4116
4181
|
this.send({ type: 'task_progress', taskId, agentId, roomId, output: 'Guide received; continuing with the updated direction...' });
|
|
4117
4182
|
iterationMessage = withTaskContext(`The task is: "${userMessage}"\n\n${postRunGuide.text}\n\nContinue with the active task using the guide as the newest user direction. Preserve useful work and context only when it does not conflict with the guide.`);
|
|
@@ -4559,9 +4624,15 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
4559
4624
|
throw new Error('UI task failed visual verification after repeated repair attempts');
|
|
4560
4625
|
}
|
|
4561
4626
|
const repairBudget = consumeUiRepairNudge('visual verification warnings', visualVerificationFailureNudge);
|
|
4627
|
+
const generatedResetNudge = this._formatGeneratedScopedUiResetNudge(
|
|
4628
|
+
this._restoreGeneratedScopedUiTargets(repoBaselines, scopeAwareUserMessage)
|
|
4629
|
+
);
|
|
4562
4630
|
nudgeCount = 0;
|
|
4563
4631
|
console.log(`[${taskId}] UI task visual verification still reported visible issues — retrying (${uiVerificationRetryCount}/${UI_REPAIR_NUDGE_LIMIT}, total UI repairs ${repairBudget})`);
|
|
4564
|
-
|
|
4632
|
+
const retryInstruction = generatedResetNudge
|
|
4633
|
+
? 'Rebuild the removed target page file(s) from already-inspected project context and comparable existing pages. Do not reuse the rejected generated page as the basis for the next attempt. Fix the visible issues reported by local browser verification, reopen each edited target screen locally after the final edit, and only then end with ✓ TASK_COMPLETE.'
|
|
4634
|
+
: 'Continue from the current changed files and latest browser evidence. Fix the visible issues reported by the local browser verification, reopen each edited target screen locally after the final edit, and only then end with ✓ TASK_COMPLETE.';
|
|
4635
|
+
iterationMessage = withTaskContext(`The task is: "${userMessage}"\n\n${[visualVerificationFailureNudge, generatedResetNudge].filter(Boolean).join('\n\n')}\n\n${retryInstruction}`);
|
|
4565
4636
|
} else if (hasMissingLocalUiVerification) {
|
|
4566
4637
|
uiVerificationRetryCount++;
|
|
4567
4638
|
const uiVerificationFailureDetails = this._extractUiVerificationFailureDetails(output);
|
|
@@ -4570,9 +4641,15 @@ export class AgentForgeWorker extends EventEmitter {
|
|
|
4570
4641
|
throw new Error('UI task failed visual verification after repeated repair attempts');
|
|
4571
4642
|
}
|
|
4572
4643
|
const repairBudget = consumeUiRepairNudge('missing local visual verification', uiVerificationFailureDetails);
|
|
4644
|
+
const generatedResetNudge = this._formatGeneratedScopedUiResetNudge(
|
|
4645
|
+
this._restoreGeneratedScopedUiTargets(repoBaselines, scopeAwareUserMessage)
|
|
4646
|
+
);
|
|
4573
4647
|
nudgeCount = 0;
|
|
4574
4648
|
console.log(`[${taskId}] UI task missing local visual verification — retrying with local-app repair instruction (${uiVerificationRetryCount}/${UI_REPAIR_NUDGE_LIMIT}, total UI repairs ${repairBudget})`);
|
|
4575
|
-
|
|
4649
|
+
const retryInstruction = generatedResetNudge
|
|
4650
|
+
? 'Rebuild the removed target page file(s) from already-inspected project context and comparable existing pages. Do not reuse the rejected generated page as the basis for the next attempt.'
|
|
4651
|
+
: 'Continue from the current changed files and already-inspected project context. Do not restart from scratch, repeat initial delete/reset/setup steps, discard existing progress, or reread site indexes, shared/global CSS, header/footer partials, or unrelated reference pages unless a specific verification issue requires it.';
|
|
4652
|
+
iterationMessage = withTaskContext(`The task is: "${userMessage}"\n\nYour edits are not complete because the changed UI was not successfully loaded and inspected cleanly in its actual local app URL.${uiVerificationFailureDetails ? `\n\nSpecific verification issue(s):\n${uiVerificationFailureDetails}` : ''}${generatedResetNudge ? `\n\n${generatedResetNudge}` : ''}\n\n${retryInstruction} Do not use external sites, site indexes, listing indexes, shared style files, or reference pages as final verification for scoped UI edits. Start or repair the project's local dev/static server if needed, use the port the project actually declares, open the real localhost/127.0.0.1 URL for each edited target screen, inspect the changed screen, fix visible issues, and only then end with ✓ TASK_COMPLETE.`);
|
|
4576
4653
|
} else if (hasIncompleteTurn) {
|
|
4577
4654
|
// openclaw reported an incomplete turn (payloads=0) after the agent used a tool.
|
|
4578
4655
|
// This is a tool timeout, not a narration. Reset nudgeCount and give a targeted retry hint.
|