@hamp10/agentforge 0.2.35 → 0.2.36
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/scripts/check-task-semantics.js +34 -0
- package/src/OpenClawCLI.js +30 -2
package/package.json
CHANGED
|
@@ -636,6 +636,40 @@ try {
|
|
|
636
636
|
} finally {
|
|
637
637
|
rmSync(linkedWorkspace, { recursive: true, force: true });
|
|
638
638
|
}
|
|
639
|
+
const knownProjectsRoot = mkdtempSync(path.join(tmpdir(), 'agentforge-known-projects-'));
|
|
640
|
+
const knownAgentWorkspace = mkdtempSync(path.join(tmpdir(), 'agentforge-known-agent-workspace-'));
|
|
641
|
+
try {
|
|
642
|
+
const knownProject = path.join(knownProjectsRoot, 'Hamp.com');
|
|
643
|
+
const knownDomainsDir = path.join(knownProject, 'public_html', 'domains');
|
|
644
|
+
mkdirSync(knownDomainsDir, { recursive: true });
|
|
645
|
+
writeFileSync(path.join(knownDomainsDir, 'agentforge-ai.html'), '<!doctype html><html><body><h1>AgentForge.ai</h1></body></html>');
|
|
646
|
+
writeFileSync(path.join(knownDomainsDir, 'adgenius-ai.html'), '<!doctype html><html><body><h1>AdGenius.ai</h1></body></html>');
|
|
647
|
+
symlinkSync(knownProject, path.join(knownAgentWorkspace, 'Hamp.com'), 'dir');
|
|
648
|
+
writeFileSync(path.join(knownAgentWorkspace, 'AGENTFORGE.md'), '# AgentForge.ai platform notes');
|
|
649
|
+
const knownProjectCli = Object.create(OpenClawCLI.prototype);
|
|
650
|
+
knownProjectCli._knownProjectsRoots = () => [knownProjectsRoot];
|
|
651
|
+
const mixedKnownProjectTask = 'Can you make Hamp.com listing pages for AgentBoard.ai and Scrimmage.ai from scratch, and fix the AgentForge.ai listing page?';
|
|
652
|
+
assert.doesNotThrow(
|
|
653
|
+
() => knownProjectCli._guardDirectFileWritePath(
|
|
654
|
+
path.join(knownAgentWorkspace, 'Hamp.com', 'public_html', 'domains', 'agentboard-ai.html'),
|
|
655
|
+
knownAgentWorkspace,
|
|
656
|
+
{ task: mixedKnownProjectTask }
|
|
657
|
+
),
|
|
658
|
+
'agent-workspace root files such as AGENTFORGE.md should not count as scoped project pages when the target resolves into a known project'
|
|
659
|
+
);
|
|
660
|
+
assert.throws(
|
|
661
|
+
() => knownProjectCli._guardDirectFileWritePath(
|
|
662
|
+
path.join(knownAgentWorkspace, 'Hamp.com', 'Hamp.com', 'public_html', 'domains', 'agentboard-ai.html'),
|
|
663
|
+
knownAgentWorkspace,
|
|
664
|
+
{ task: mixedKnownProjectTask }
|
|
665
|
+
),
|
|
666
|
+
/nested duplicate of the current project/i,
|
|
667
|
+
'known-project symlink writes should still reject same-name nested project-copy paths from temp agent workspaces'
|
|
668
|
+
);
|
|
669
|
+
} finally {
|
|
670
|
+
rmSync(knownProjectsRoot, { recursive: true, force: true });
|
|
671
|
+
rmSync(knownAgentWorkspace, { recursive: true, force: true });
|
|
672
|
+
}
|
|
639
673
|
assert.equal(
|
|
640
674
|
cli._directScopeFileCandidates(fixture.repo, ['gamma']).some(candidate => candidate.startsWith(`${path.basename(fixture.repo)}/`)),
|
|
641
675
|
false,
|
package/src/OpenClawCLI.js
CHANGED
|
@@ -415,7 +415,28 @@ export class OpenClawCLI extends EventEmitter {
|
|
|
415
415
|
|
|
416
416
|
_projectsRootForPath(candidate) {
|
|
417
417
|
if (!candidate) return null;
|
|
418
|
-
|
|
418
|
+
const realCandidate = this._realPathForMaybeMissingPath(candidate);
|
|
419
|
+
return this._knownProjectsRoots().find(root => {
|
|
420
|
+
if (!existsSync(root)) return false;
|
|
421
|
+
const realRoot = this._realPathForMaybeMissingPath(root);
|
|
422
|
+
return this._isPathInside(realCandidate, realRoot);
|
|
423
|
+
}) || null;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
_projectDirForKnownProjectPath(candidate) {
|
|
427
|
+
if (!candidate) return null;
|
|
428
|
+
const realCandidate = this._realPathForMaybeMissingPath(candidate);
|
|
429
|
+
const projectsRoot = this._projectsRootForPath(realCandidate);
|
|
430
|
+
if (!projectsRoot) return null;
|
|
431
|
+
let realProjectsRoot = projectsRoot;
|
|
432
|
+
try {
|
|
433
|
+
realProjectsRoot = realpathSync(projectsRoot);
|
|
434
|
+
} catch { /* non-fatal */ }
|
|
435
|
+
const relative = path.relative(realProjectsRoot, realCandidate);
|
|
436
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) return null;
|
|
437
|
+
const [projectName] = relative.split(path.sep).filter(Boolean);
|
|
438
|
+
if (!projectName) return null;
|
|
439
|
+
return path.join(realProjectsRoot, projectName);
|
|
419
440
|
}
|
|
420
441
|
|
|
421
442
|
_isProjectScopedWorkDir(workDir) {
|
|
@@ -988,7 +1009,14 @@ export class OpenClawCLI extends EventEmitter {
|
|
|
988
1009
|
}
|
|
989
1010
|
|
|
990
1011
|
_guardDirectFileWritePath(filePath, workDir, options = {}) {
|
|
991
|
-
|
|
1012
|
+
const realFilePath = this._realPathForMaybeMissingPath(filePath);
|
|
1013
|
+
const projectDirForFile = this._projectDirForKnownProjectPath(realFilePath);
|
|
1014
|
+
if (projectDirForFile && this._isPathInside(realFilePath, projectDirForFile)) {
|
|
1015
|
+
filePath = realFilePath;
|
|
1016
|
+
workDir = projectDirForFile;
|
|
1017
|
+
} else {
|
|
1018
|
+
filePath = this._canonicalizeLinkedProjectPath(filePath, workDir);
|
|
1019
|
+
}
|
|
992
1020
|
workDir = this._realPathForMaybeMissingPath(workDir);
|
|
993
1021
|
const { slugs, pageOnly } = this._extractDirectExplicitScope(options.task);
|
|
994
1022
|
const relative = path.relative(workDir, filePath);
|