fix(agent): recover stale runs and improve new-user OA delivery
Fix DEV logout cookie clearing, materialize selected MindSpace OA assets before agent runs, and recover zombie runs from synced workspace pages. Add client run wait timeout, harness retry limits, page-edit asset forwarding, and logout/john2 scenario tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -112,10 +112,12 @@ test('syncUserWorkspace imports new workspace files into asset library', async (
|
||||
user_id: params[1],
|
||||
category_id: params[3],
|
||||
original_filename: params[6],
|
||||
checksum: params[10],
|
||||
size_bytes: params[9],
|
||||
current_version_id: params[8],
|
||||
status: params[13],
|
||||
checksum: params[11],
|
||||
size_bytes: params[10],
|
||||
current_version_id: params[9],
|
||||
risk_level: params[12],
|
||||
visibility: params[13],
|
||||
status: params[14],
|
||||
source_type: 'workspace',
|
||||
});
|
||||
return [[]];
|
||||
@@ -203,6 +205,111 @@ test('syncUserWorkspace imports new workspace files into asset library', async (
|
||||
]);
|
||||
});
|
||||
|
||||
test('syncUserWorkspace imports sandboxable public html as warned ready asset', async () => {
|
||||
const h5Root = await fs.mkdtemp(path.join(os.tmpdir(), 'h5-sync-public-html-'));
|
||||
const storageRoot = path.join(h5Root, 'data', 'mindspace');
|
||||
const workspace = resolveUserWorkspaceRoot(h5Root, { id: 'user-1', username: 'john' });
|
||||
await fs.mkdir(path.join(workspace, 'public'), { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(workspace, 'public', 'dashboard.html'),
|
||||
`<!doctype html>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
|
||||
<script>new Chart(document.createElement('canvas'), { type: 'bar' });</script>`,
|
||||
);
|
||||
|
||||
const state = {
|
||||
users: [{ id: 'user-1', username: 'john' }],
|
||||
categories: [
|
||||
{ id: 'cat-public', user_id: 'user-1', space_id: 'space-1', category_code: 'public' },
|
||||
],
|
||||
spaces: [
|
||||
{
|
||||
id: 'space-1',
|
||||
user_id: 'user-1',
|
||||
quota_bytes: 5 * 1024 * 1024,
|
||||
used_bytes: 0,
|
||||
reserved_bytes: 0,
|
||||
status: 'active',
|
||||
},
|
||||
],
|
||||
assets: [],
|
||||
versions: [],
|
||||
};
|
||||
|
||||
let nextId = 0;
|
||||
const pool = {
|
||||
async query(sql, params = []) {
|
||||
if (sql.includes('SELECT username FROM h5_users')) {
|
||||
return [[{ username: 'john' }]];
|
||||
}
|
||||
if (sql.includes('FROM h5_space_categories c') && sql.includes('category_code = ?')) {
|
||||
const category = state.categories.find(
|
||||
(item) => item.user_id === params[0] && item.category_code === params[1],
|
||||
);
|
||||
return [category ? [category] : []];
|
||||
}
|
||||
if (sql.includes('FROM h5_assets')) return [[]];
|
||||
return [[]];
|
||||
},
|
||||
async getConnection() {
|
||||
return {
|
||||
async beginTransaction() {},
|
||||
async commit() {},
|
||||
async rollback() {},
|
||||
release() {},
|
||||
async query(sql, params = []) {
|
||||
if (sql.includes('FROM h5_user_spaces') && sql.includes('FOR UPDATE')) {
|
||||
return [[state.spaces[0]]];
|
||||
}
|
||||
if (sql.includes('INSERT INTO h5_assets')) {
|
||||
state.assets.push({
|
||||
id: params[0],
|
||||
original_filename: params[6],
|
||||
workspace_relative_path: params[8],
|
||||
size_bytes: params[10],
|
||||
checksum: params[11],
|
||||
risk_level: params[12],
|
||||
visibility: params[13],
|
||||
status: params[14],
|
||||
});
|
||||
return [[]];
|
||||
}
|
||||
if (sql.includes('INSERT INTO h5_asset_versions')) {
|
||||
state.versions.push({
|
||||
id: params[0],
|
||||
asset_id: params[1],
|
||||
storage_key: params[2],
|
||||
scan_status: params[7],
|
||||
});
|
||||
return [[]];
|
||||
}
|
||||
if (sql.includes('used_bytes = used_bytes +')) {
|
||||
state.spaces[0].used_bytes += params[0];
|
||||
return [[]];
|
||||
}
|
||||
return pool.query(sql, params);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const sync = createWorkspaceAssetSync({
|
||||
pool,
|
||||
storageRoot,
|
||||
h5Root,
|
||||
maxFileBytes: 1024 * 1024,
|
||||
idFactory: () => `id-${++nextId}`,
|
||||
});
|
||||
|
||||
const result = await sync.syncUserWorkspace('user-1', { categoryCode: 'public' });
|
||||
assert.equal(result.imported, 1);
|
||||
assert.equal(state.assets[0].status, 'ready');
|
||||
assert.equal(state.assets[0].risk_level, 'medium');
|
||||
assert.equal(state.assets[0].visibility, 'public_candidate');
|
||||
assert.equal(state.versions[0].scan_status, 'warned');
|
||||
assert.match(state.versions[0].storage_key, /^workspace:\/\/user-1\/public\/dashboard\.html$/);
|
||||
});
|
||||
|
||||
test('syncUserWorkspace imports nested workspace files into asset library', async () => {
|
||||
const h5Root = await fs.mkdtemp(path.join(os.tmpdir(), 'h5-sync-nested-'));
|
||||
const storageRoot = path.join(h5Root, 'data', 'mindspace');
|
||||
@@ -270,10 +377,12 @@ test('syncUserWorkspace imports nested workspace files into asset library', asyn
|
||||
user_id: params[1],
|
||||
category_id: params[3],
|
||||
original_filename: params[6],
|
||||
checksum: params[10],
|
||||
size_bytes: params[9],
|
||||
current_version_id: params[8],
|
||||
status: params[13],
|
||||
checksum: params[11],
|
||||
size_bytes: params[10],
|
||||
current_version_id: params[9],
|
||||
risk_level: params[12],
|
||||
visibility: params[13],
|
||||
status: params[14],
|
||||
source_type: 'workspace',
|
||||
});
|
||||
return [[]];
|
||||
|
||||
Reference in New Issue
Block a user