sync: update from private repo (dfadcd5f)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-23 06:38:48 +00:00
parent 6a2f2cc736
commit 29ccaf1e92
377 changed files with 31028 additions and 8994 deletions
+109
View File
@@ -888,3 +888,112 @@ describe('ReadUserAgents / UpdateUserAgents', () => {
expect(TOOL_DEFS['UpdateUserAgents']).toBeDefined();
});
});
// ── spaces foundation: AGENTS.md / memory は folderContext を尊重する ──────────
// バグ回帰: ケーススペースで作業中、AGENTS.md / memory が個人ユーザーフォルダ
// (userFolderRoot/userId)に書かれてしまい、スペースの AGENTS.md を編集できなかった。
// folderContext が在れば (rootDir, leafId) を使い、無ければ従来の個人フォルダ。
describe('user-folder tools honor ctx.folderContext (space resolution)', () => {
let spacesRoot: string;
const SPACE_ID = 'space-xyz';
beforeEach(() => {
spacesRoot = join(tempDir, 'spaces');
mkdirSync(join(spacesRoot, SPACE_ID, 'memory'), { recursive: true });
mkdirSync(join(spacesRoot, SPACE_ID, 'trash'), { recursive: true });
});
const spaceCtx = () =>
buildCtx({ userId: TEST_USER, folderContext: { rootDir: spacesRoot, leafId: SPACE_ID } });
it('UpdateUserAgents writes to the SPACE folder, not the personal user folder', async () => {
const res = await executeTool(
'UpdateUserAgents',
{ mode: 'append', new_text: '# Space rules\nuse the space brief' },
spaceCtx(),
);
expect(res.isError).toBe(false);
// Written under spaces/<id>/AGENTS.md ...
const spaceAgents = join(spacesRoot, SPACE_ID, 'AGENTS.md');
expect(readFileSync(spaceAgents, 'utf-8')).toContain('use the space brief');
// ... and NOT under the personal user folder.
expect(() => readFileSync(join(userFolderRoot, TEST_USER, 'AGENTS.md'), 'utf-8')).toThrow();
});
it('ReadUserAgents reads the SPACE AGENTS.md', async () => {
writeFileSync(join(spacesRoot, SPACE_ID, 'AGENTS.md'), 'SPACE-ONLY-MARKER');
// personal one would mislead if resolution were wrong
writeFileSync(join(userFolderRoot, TEST_USER, 'AGENTS.md'), 'PERSONAL-MARKER');
const res = await executeTool('ReadUserAgents', {}, spaceCtx());
expect(res.output).toContain('SPACE-ONLY-MARKER');
expect(res.output).not.toContain('PERSONAL-MARKER');
});
it('UpdateUserMemory / ReadUserMemory target the SPACE memory dir', async () => {
const up = await executeTool(
'UpdateUserMemory',
{ action: 'upsert', name: 'sp-note', type: 'project', description: 'd', body: 'space body' },
spaceCtx(),
);
expect(up.isError).toBe(false);
expect(readFileSync(join(spacesRoot, SPACE_ID, 'memory', 'sp-note.md'), 'utf-8')).toContain('space body');
// Not in the personal memory dir.
expect(() => readFileSync(join(userFolderRoot, TEST_USER, 'memory', 'sp-note.md'), 'utf-8')).toThrow();
// And readable back through the space context.
const rd = await executeTool('ReadUserMemory', { name: 'sp-note' }, spaceCtx());
expect(rd.isError).toBe(false);
expect(rd.output).toContain('space body');
});
it('without folderContext, still writes to the personal user folder (legacy)', async () => {
const res = await executeTool(
'UpdateUserAgents',
{ mode: 'append', new_text: 'personal rule' },
buildCtx({ userId: TEST_USER }),
);
expect(res.isError).toBe(false);
expect(readFileSync(join(userFolderRoot, TEST_USER, 'AGENTS.md'), 'utf-8')).toContain('personal rule');
});
// ── workstream 2: browser-macros / recordings honor folderContext ──────────
it('WriteUserScript writes the macro into the SPACE browser-macros/, not personal', async () => {
mkdirSync(join(spacesRoot, SPACE_ID, 'browser-macros'), { recursive: true });
const res = await executeTool(
'WriteUserScript',
{ name: 'space-macro', content: 'async function main() { return 1; }' },
spaceCtx(),
);
expect(res.isError).toBe(false);
expect(readFileSync(join(spacesRoot, SPACE_ID, 'browser-macros', 'space-macro.js'), 'utf-8')).toContain('main');
// NOT in the personal folder.
expect(() => readFileSync(join(userFolderRoot, TEST_USER, 'browser-macros', 'space-macro.js'), 'utf-8')).toThrow();
});
it('RunUserScript resolves the macro from the SPACE folder', async () => {
mkdirSync(join(spacesRoot, SPACE_ID, 'browser-macros'), { recursive: true });
writeFileSync(join(spacesRoot, SPACE_ID, 'browser-macros', 'sp-run.js'), SCRIPT_NO_FM);
const res = await executeTool('RunUserScript', { name: 'sp-run' }, spaceCtx());
expect(res.isError).toBe(false);
expect(res.output).toContain('42');
});
it('ListUserAssets lists the SPACE browser-macros, not the personal ones', async () => {
mkdirSync(join(spacesRoot, SPACE_ID, 'browser-macros'), { recursive: true });
writeFileSync(join(spacesRoot, SPACE_ID, 'browser-macros', 'sp-macro.js'), SCRIPT_BAR);
writeFileSync(join(userFolderRoot, TEST_USER, 'browser-macros', 'personal-macro.js'), SCRIPT_FOO);
const res = await executeTool('ListUserAssets', { kind: 'browser-macros' }, spaceCtx());
expect(res.isError).toBe(false);
expect(res.output).toContain('sp-macro.js');
expect(res.output).not.toContain('personal-macro.js');
});
it('without folderContext, WriteUserScript still targets the personal folder', async () => {
const res = await executeTool(
'WriteUserScript',
{ name: 'personal-macro', content: 'async function main() { return 2; }' },
buildCtx({ userId: TEST_USER }),
);
expect(res.isError).toBe(false);
expect(readFileSync(join(userFolderRoot, TEST_USER, 'browser-macros', 'personal-macro.js'), 'utf-8')).toContain('main');
});
});