@hamp10/agentforge 0.2.48 → 0.2.49

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hamp10/agentforge",
3
- "version": "0.2.48",
3
+ "version": "0.2.49",
4
4
  "description": "AgentForge worker — connect your machine to agentforge.ai",
5
5
  "type": "module",
6
6
  "bin": {
@@ -549,6 +549,44 @@ try {
549
549
  /The task is:|Delete and rebuild both/i,
550
550
  'missing-target retries should not put the original reset-heavy task text at the top of the retry prompt'
551
551
  );
552
+ assert.throws(
553
+ () => cli._guardDirectFileWritePath(
554
+ path.join(fixture.repo, 'public_html', 'domains', 'alpha.html'),
555
+ fixture.repo,
556
+ { task: incompleteRepairLead }
557
+ ),
558
+ /focused retry pass/i,
559
+ 'direct writes should block already-touched scoped pages during a missing-target retry pass'
560
+ );
561
+ assert.doesNotThrow(
562
+ () => cli._guardDirectFileWritePath(
563
+ path.join(fixture.repo, 'public_html', 'domains', 'beta.html'),
564
+ fixture.repo,
565
+ { task: incompleteRepairLead }
566
+ ),
567
+ 'direct writes should allow the missing scoped page during a missing-target retry pass'
568
+ );
569
+ const visualRepairLead = worker._formatVisualRepairTaskLead(
570
+ 'Work on the Example.com listing pages for Alpha.ai and Beta.ai. Make both visually polished.',
571
+ 'beta-ai: Visual warning: heading is clipped.'
572
+ );
573
+ assert.throws(
574
+ () => cli._guardDirectFileWritePath(
575
+ path.join(fixture.repo, 'public_html', 'domains', 'alpha.html'),
576
+ fixture.repo,
577
+ { task: visualRepairLead }
578
+ ),
579
+ /focused retry pass/i,
580
+ 'direct writes should block non-failing scoped pages during a focused visual repair pass'
581
+ );
582
+ assert.doesNotThrow(
583
+ () => cli._guardDirectFileWritePath(
584
+ path.join(fixture.repo, 'public_html', 'domains', 'beta.html'),
585
+ fixture.repo,
586
+ { task: visualRepairLead }
587
+ ),
588
+ 'direct writes should allow the failing scoped page during a focused visual repair pass'
589
+ );
552
590
  assert.equal(
553
591
  worker._formatRepeatedVisualRepairNudge(2),
554
592
  '',
@@ -914,6 +914,24 @@ export class OpenClawCLI extends EventEmitter {
914
914
  return err;
915
915
  }
916
916
 
917
+ _directFocusedRetryAllowedSlugs(task) {
918
+ const text = String(task || '');
919
+ const patterns = [
920
+ /missing-target pass for target page\(s\) not yet changed in the current diff:\s*([^\n.]+)/i,
921
+ /visual repair pass for currently failing target page\(s\):\s*([^\n.]+)/i,
922
+ ];
923
+ for (const pattern of patterns) {
924
+ const match = text.match(pattern);
925
+ if (!match) continue;
926
+ const slugs = String(match[1] || '')
927
+ .split(/[,;]/)
928
+ .map(item => scopeSlug(item.trim()))
929
+ .filter(Boolean);
930
+ if (slugs.length > 0) return new Set(slugs);
931
+ }
932
+ return null;
933
+ }
934
+
917
935
  _isNestedProjectCopyPath(filePath, workDir) {
918
936
  const relative = path.relative(workDir, filePath);
919
937
  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) return false;
@@ -1048,6 +1066,20 @@ export class OpenClawCLI extends EventEmitter {
1048
1066
  if (!this._directTaskScopeAllowsPath(filePath, workDir, options.task)) {
1049
1067
  throw this._directScopeViolationError(this._formatDirectScopeError(filePath, workDir, options.task));
1050
1068
  }
1069
+ const focusedRetrySlugs = this._directFocusedRetryAllowedSlugs(options.task);
1070
+ if (focusedRetrySlugs && slugs.length > 0) {
1071
+ const matchedScopedSlugs = this._directScopeSlugsMatchingText(lowerRelativePath, slugs);
1072
+ const matchesFocusedSlug = matchedScopedSlugs.some(slug => focusedRetrySlugs.has(slug));
1073
+ if (matchedScopedSlugs.length > 0 && !matchesFocusedSlug) {
1074
+ throw this._directScopeViolationError([
1075
+ 'Refusing to rewrite an already-addressed scoped target during a focused retry pass.',
1076
+ `Requested path: ${relativePath}`,
1077
+ `Current retry target(s): ${[...focusedRetrySlugs].join(', ')}.`,
1078
+ `Path appears to belong to: ${matchedScopedSlugs.join(', ')}.`,
1079
+ 'Continue from the current repo state and edit the focused target page(s) named by the retry instruction, then verify every requested target page locally.',
1080
+ ].join(' '));
1081
+ }
1082
+ }
1051
1083
  const collectionViolation = this._directNewHtmlPageCollectionViolation(
1052
1084
  filePath,
1053
1085
  workDir,