Files
memind/scripts/check-goosed-v149-sandbox-page.mjs
T
john 1274943f33 test(goose): add sandbox page and Portal resume integration smokes
Verify write_file/edit_file land public HTML via call_tool, and Portal can
start/resume v1.49 sessions without 404 on the resume path.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 21:37:27 +08:00

111 lines
3.5 KiB
JavaScript

#!/usr/bin/env node
/**
* Verify sandbox-fs write_file + edit_file materialize HTML via /agent/call_tool.
*/
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { createV149Client } from './goose-v149-sse.mjs';
const memindRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
const nodeExec = process.env.GOOSED_MCP_NODE_PATH || process.execPath;
const serverPath =
process.env.GOOSED_MCP_SERVER_PATH || path.join(memindRoot, 'mindspace-sandbox-mcp.mjs');
const pollMs = Number(process.env.GOOSE_V149_SANDBOX_POLL_MS || 500);
const timeoutMs = Number(process.env.GOOSE_V149_SANDBOX_TIMEOUT_MS || 45_000);
const pageRel = 'public/goose-v149-sandbox-page.html';
const client = createV149Client();
const sandboxRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'goose-v149-page-'));
fs.mkdirSync(path.join(sandboxRoot, 'public'), { recursive: true });
async function waitForWriteTool(sessionId) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const response = await client.apiFetch(
`/agent/tools?session_id=${encodeURIComponent(sessionId)}&extension_name=sandbox-fs`,
{ method: 'GET' },
);
const tools = await response.json();
if (tools.some((tool) => tool.name === 'sandbox-fs__write_file')) return;
await new Promise((resolve) => setTimeout(resolve, pollMs));
}
throw new Error(`sandbox-fs write tool not ready within ${timeoutMs}ms`);
}
async function callTool(sessionId, name, arguments_) {
return client.apiJson('/agent/call_tool', {
session_id: sessionId,
name,
arguments: arguments_,
});
}
async function main() {
if (!fs.existsSync(serverPath)) {
throw new Error(`MCP entry missing: ${serverPath}`);
}
const session = await client.apiJson('/agent/start', {
working_dir: memindRoot,
extension_overrides: [
{
type: 'stdio',
name: 'sandbox-fs',
description: 'MindSpace sandbox page smoke',
cmd: nodeExec,
args: [serverPath, sandboxRoot],
envs: {
ALLOWED_TOOLS: 'write_file,edit_file,read_file,create_dir,list_dir',
SANDBOX_ROOT: sandboxRoot,
},
available_tools: ['write_file', 'read_file', 'edit_file', 'create_dir', 'list_dir'],
},
],
});
if (!session?.id) throw new Error('missing session id');
await waitForWriteTool(session.id);
const initialHtml = `<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>Goose v1.49 Sandbox</title></head>
<body><h1>苏州一日游</h1><p>初始段落</p></body>
</html>`;
await callTool(session.id, 'sandbox-fs__write_file', {
path: pageRel,
content: initialHtml,
});
const absPath = path.join(sandboxRoot, pageRel);
if (!fs.existsSync(absPath)) {
throw new Error(`write_file did not create ${pageRel}`);
}
await callTool(session.id, 'sandbox-fs__edit_file', {
path: pageRel,
old_str: '初始段落',
new_str: '已编辑段落 · v1.49',
});
const updated = fs.readFileSync(absPath, 'utf8');
if (!updated.includes('已编辑段落 · v1.49')) {
throw new Error('edit_file did not apply patch');
}
if (!updated.includes('苏州一日游')) {
throw new Error('edit_file removed expected page content');
}
console.log(
`GOOSE_V149_SANDBOX_PAGE_OK: session=${session.id} file=${pageRel} sandbox=${sandboxRoot}`,
);
}
main().catch((error) => {
console.error(`GOOSE_V149_SANDBOX_PAGE_FAIL: ${error.message}`);
process.exit(1);
});