dsh-eval-guard 0.2.0 → 0.2.1

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.
Binary file
Binary file
Binary file
Binary file
Binary file
package/lib/index.js CHANGED
@@ -389,6 +389,20 @@ const SYSTEM_READ_DIRS = [
389
389
  "/sys",
390
390
  "/var/lib"
391
391
  ];
392
+ /** Python stdlib/venv directories that may live next to a workspace. */
393
+ function pythonRuntimeDirs(workspace) {
394
+ const dirs = /* @__PURE__ */ new Set();
395
+ for (const ancestor of [workspace, ...ancestorsOf(workspace)]) for (const lib of ["lib", "lib64"]) {
396
+ const base = path.join(ancestor, lib);
397
+ try {
398
+ for (const entry of fs.readdirSync(base, { withFileTypes: true })) if (entry.isDirectory() && entry.name.startsWith("python")) {
399
+ const real = fs.realpathSync.native(path.join(base, entry.name));
400
+ if (!SYSTEM_READ_DIRS.some((system) => real === system || real.startsWith(system + "/"))) dirs.add(real);
401
+ }
402
+ } catch {}
403
+ }
404
+ return [...dirs];
405
+ }
392
406
  /** Ancestors of a path, outermost first. */
393
407
  function ancestorsOf(target) {
394
408
  const out = [];
@@ -534,6 +548,10 @@ function writePolicy(workspace, rules) {
534
548
  }
535
549
  lines.push(line("read", runtime.node));
536
550
  for (const file of [runtime.ptcProcess, runtime.ptcControl]) if (file !== void 0) lines.push(line("read", file));
551
+ for (const dir of pythonRuntimeDirs(workspace)) {
552
+ lines.push(line("read", dir));
553
+ for (const ancestor of ancestorsOf(dir)) lines.push(line("exact", ancestor));
554
+ }
537
555
  for (const rule of rules) lines.push(line("rule", (rule.allow ? "allow " : "deny ") + rule.path));
538
556
  if (!(workspace === "/tmp" || workspace.startsWith("/tmp/"))) lines.push(line("tmpbind", path.join(workspace, ".tmp")));
539
557
  fs.writeFileSync(file, lines.join("\n") + "\n", {
@@ -579,6 +597,7 @@ function bwrapArgs(workspace, cwd, rules, runtime) {
579
597
  }
580
598
  for (const manifest of manifests) args.push("--ro-bind", manifest, manifest);
581
599
  for (const file of [runtime.ptcProcess, runtime.ptcControl]) if (file !== void 0) args.push("--ro-bind", file, file);
600
+ for (const dir of pythonRuntimeDirs(workspace)) args.push("--ro-bind", dir, dir);
582
601
  for (const rule of rules) {
583
602
  if (!rule.allow) continue;
584
603
  try {
@@ -1301,8 +1320,8 @@ var Guard = class {
1301
1320
  //#endregion
1302
1321
  //#region src/task.ts
1303
1322
  /**
1304
- * The tank task pack: packaged workspace.zip install, prompt construction, and the one
1305
- * run record the evaluator later reads.
1323
+ * Task packs: packaged workspace.zip install, original prompt construction, and
1324
+ * the run record the evaluators later read.
1306
1325
  * @module dsh-eval-guard/task
1307
1326
  */
1308
1327
  /** Tasks offered by the installer. */
@@ -1310,42 +1329,33 @@ const TASKS = [
1310
1329
  {
1311
1330
  id: TANK_TASK,
1312
1331
  label: TANK_TASK_LABEL,
1313
- description: "1v1 坦克大战 bot:解压 workspace.zip 后编写 workspace/submission/bot.cpp,评测时与基准及其它提交打循环赛。"
1332
+ description: "1v1 坦克大战 bot;解压 workspace.zip,提交 workspace/submission/bot.cpp。"
1314
1333
  },
1315
1334
  {
1316
1335
  id: WAREHOUSE_TASK,
1317
1336
  label: WAREHOUSE_TASK_LABEL,
1318
- description: "单人单次仓储调度优化:解压 workspace.zip 后改写 workspace/src/,在输出逐字节不变的前提下尽量提速。"
1337
+ description: "单人单次仓储调度优化;解压 workspace.zip,提交 workspace/src/。"
1319
1338
  },
1320
1339
  {
1321
1340
  id: LAND_TASK,
1322
1341
  label: LAND_TASK_LABEL,
1323
- description: "圈地 1v1/4 人混战 bot:解压 workspace.zip 后编写 workspace/submission/bot.cpp。"
1342
+ description: "圈地 1v1/4 人混战 bot;解压 workspace.zip,提交 workspace/submission/bot.cpp。"
1324
1343
  },
1325
1344
  {
1326
1345
  id: BOMBERMAN_TASK,
1327
1346
  label: BOMBERMAN_TASK_LABEL,
1328
- description: "炸弹人 2–10 人 bot:解压 workspace.zip 后编写 workspace/submission/bot.cpp。"
1347
+ description: "炸弹人 2–10 人 bot;解压 workspace.zip,提交 workspace/submission/bot.cpp。"
1329
1348
  },
1330
1349
  {
1331
1350
  id: "ctf",
1332
1351
  label: CTF_TASK_LABEL,
1333
- description: "夺旗 2–15 人 bot:解压 workspace.zip 后编写 workspace/submission/bot.cpp。"
1352
+ description: "夺旗 2–15 人 bot;解压 workspace.zip,提交 workspace/submission/bot.cpp。"
1334
1353
  }
1335
1354
  ];
1336
- /** Format a blacklist for the prompt. */
1337
- function blacklistBlock(blacklist) {
1338
- if (blacklist.length === 0) return "(当前没有需要特别列出的工具。)";
1339
- return blacklist.join("\n");
1355
+ /** Common workspace/clock sentence, keeping the original prompt's wording. */
1356
+ function clockLine(minutes) {
1357
+ return "本次是连续 " + String(minutes) + " 分钟的单次任务,请充分利用时间持续改进,不要提前交卷。";
1340
1358
  }
1341
- /** Wording shared by every task: difficulty, strong-agent comparison, no early submit. */
1342
- const COMPETITION_LINES = [
1343
- "## 竞争强度",
1344
- "",
1345
- "- 这个任务并不像看起来那么简单,不要低估隐藏边界、正确性细节和对手强度。",
1346
- "- 你的结果会与 meow-ai-arena 中其他强 agent(如 GPT-6 Astra、Opus、Kimi K3 等)的提交在同一口径下比较,而不只是和基准 bot 比较;请按能进入前列的标准要求自己。",
1347
- "- 不要过早交卷:在时间上限内尽量多验证、迭代和完善,只有确实完成时才结束。"
1348
- ];
1349
1359
  /** The tank task definition. */
1350
1360
  const TANK_DEFINITION = {
1351
1361
  id: TANK_TASK,
@@ -1353,39 +1363,25 @@ const TANK_DEFINITION = {
1353
1363
  description: TASKS[0].description,
1354
1364
  asset: path.join(packageRoot(), "assets", "tank", "workspace.zip"),
1355
1365
  prompt(blacklist, options) {
1366
+ const minutes = options.minutes ?? 90;
1356
1367
  return [
1357
- "这是一场用于评测 AI agent 能力的坦克大战编程任务。你需要在当前工作区里独立完成它。",
1358
- "",
1359
- "## 环境与限制",
1368
+ "按照要求编写尽可能强的坦克大战 bot。你的对手是其他顶尖 AI 模型写的 bot,它们可能主动设计战术。基准是一个中等强度、思路常规的 bot,它在正式比赛中是 0 分线;战胜基准不代表足够强,正式对手远强于基准。正式赛是 1 对 1 循环赛,用 Bradley-Terry 模型拟合实力值。",
1360
1369
  "",
1361
- "- 你只能读写当前工作区内的文件;工作区以外的任何位置都不能访问,包括 /tmp。",
1362
- "- 禁止联网、禁止调用其他 AI 或子代理、禁止与其他 agent 通信或读取其他工作区。",
1363
- "- 评测守护会阻止并记录违规行为;违规可能导致本次评测无效。",
1364
- "- 任务必须自主完成:不要向用户提问、不要请求审批、不要等待任何用户输入。",
1370
+ "解压 workspace.zip,阅读 README.md 和 RULES.md,然后开始。本次是连续 " + String(minutes) + " 分钟的单次任务,从对话开始时计时。",
1365
1371
  "",
1366
- "## 交付",
1372
+ "要点:",
1373
+ "- 时间规则:连续 " + String(minutes) + " 分钟;clock.py 从解压那一刻开始计算,实际计时从对话开始计算,它只能作为参考,请尽快解压以减小误差;到点会被强制终止;",
1374
+ "- 到点时 workspace/submission/bot.cpp 是什么就交什么:不要让它长时间停在编译不过的状态;",
1375
+ "- 允许使用本地工具、对战和复盘;禁止联网,禁止求助其他模型(包括启动子代理:subagent、Task / Agent 工具、后台并行代理之类),除主办方发给你的材料外禁止查看其他选手的资料;",
1376
+ "- 这台机器上同时运行着其他程序:只能结束你自己启动的进程(按进程号),不要按名字批量结束进程;",
1377
+ "- 只能读写当前工作区内的文件,包括 /tmp 在内的其他位置都不能访问;",
1378
+ "- 不要向我提问,也不要等待我确认。",
1367
1379
  "",
1368
- "- 解压工作区里的 workspace.zip,把最终 bot 保存到解压后的 workspace/submission/bot.cpp(只需要这一个文件)。",
1369
- "- 最后用几句话说明你的策略。",
1370
- "",
1371
- "## 时间规则",
1372
- "",
1373
- "- 本次是**连续 " + String(options.minutes ?? 90) + " 分钟的单次任务**,从对话开始时开始计时。",
1374
- "- 交付前检查并关闭所有后台任务;到点会被强制终止。",
1375
- "- clock.py 从解压那一刻开始计算,而实际计时从对话开始计算;它**只能作为参考**,请尽快解压以减小误差。实际时间以评测守护为准。",
1380
+ "完成后,用几句话简述你的策略。",
1376
1381
  "",
1377
1382
  "## 本次评测禁止调用的工具",
1378
1383
  "",
1379
- blacklistBlock(blacklist),
1380
- "",
1381
- "## 工作区内容",
1382
- "",
1383
- "工作区里有一个 workspace.zip;解压后进入 workspace/ 目录,先读 README.md 和 RULES.md,规则引擎是 tank.hpp。",
1384
- "本地工具(arena.py、check、play、batch、vs 等)和起步模板都在解压后的 workspace/ 里,可直接使用。",
1385
- "",
1386
- ...COMPETITION_LINES,
1387
- "",
1388
- "开始吧。"
1384
+ blacklist.length === 0 ? "(无)" : blacklist.join("\n")
1389
1385
  ].join("\n");
1390
1386
  }
1391
1387
  };
@@ -1396,124 +1392,78 @@ const WAREHOUSE_DEFINITION = {
1396
1392
  description: TASKS[1].description,
1397
1393
  asset: path.join(packageRoot(), "assets", "warehouse", "workspace.zip"),
1398
1394
  prompt(blacklist, options) {
1395
+ const minutes = options.minutes ?? 90;
1399
1396
  return [
1400
- "这是一场用于评测 AI agent 能力的仓储调度优化任务。你需要在当前工作区里独立完成它。",
1401
- "",
1402
- "## 环境与限制",
1403
- "",
1404
- "- 你只能读写当前工作区内的文件;工作区以外的任何位置都不能访问,包括 /tmp。",
1405
- "- 禁止联网、禁止调用其他 AI 或子代理、禁止与其他 agent 通信或读取其他工作区。",
1406
- "- 评测守护会阻止并记录违规行为;违规可能导致本次评测无效。",
1407
- "- 任务必须自主完成:不要向用户提问、不要请求审批、不要等待任何用户输入。",
1397
+ "这是一场 AI 编程赛。你接手了一个代码混乱的老系统:src/ 里是一个仓储机器人调度仿真系统,功能正确,但运行很慢。你的任务是在输出与基线逐字节相同的前提下,让 src/ 尽可能快。",
1408
1398
  "",
1409
- "## 交付",
1399
+ "当前目录里有 workspace.zip。请先自行解压,进入 workspace 文件夹,阅读 TASK.md,然后完全按照 TASK.md 的要求独立完成任务。",
1410
1400
  "",
1411
- "- 解压工作区里的 workspace.zip,进入解压后的 workspace/ 目录;只能修改 workspace/src/ 下的文件。",
1412
- "- 结束时 workspace/src/ 整个目录就是提交;不要修改 baseline/、workloads/、tools/。",
1413
- "- 最后用几句话说明你做了什么优化、如何验证输出不变。",
1401
+ "要点(详见 TASK.md):",
1402
+ "- 只能修改 src/;编译命令固定为 g++ -O2 -std=c++20 src/*.cpp,只用 C++ 标准库;",
1403
+ "- 对任何合法输入(以 tools/check_input.py --full 为准),输出都必须与基线逐字节相同;SPEC.md 是过时的旧文档,一切以基线代码的实际行为为准;",
1404
+ "- 本次是连续 " + String(minutes) + " 分钟的单次任务;clock.py 从解压那一刻开始计算,实际计时从对话开始计算,它只能作为参考,请尽快解压;",
1405
+ "- 你的结果会与其他强 agent 在同一口径下比较,而不只是和基准比较;不要提前交卷,充分利用时间继续优化和验证;",
1406
+ "- 只能读写当前文件夹里的文件;可以使用本环境的所有工具,但不能联网搜索;",
1407
+ "- 不要向我提问,也不要等待我确认,直到完成为止。",
1414
1408
  "",
1415
- "## 时间规则",
1416
- "",
1417
- "- 本次是**连续 " + String(options.minutes ?? 90) + " 分钟的单次任务**,从对话开始时开始计时。",
1418
- "- 交付前检查并关闭所有后台任务;到点会被强制终止,以当时的 src/ 为准。",
1419
- "- clock.py 从解压那一刻开始计算,而实际计时从对话开始计算;它**只能作为参考**,请尽快解压以减小误差。实际时间以评测守护为准。",
1409
+ "完成后请告诉我:src 文件夹的完整路径,并用几句话总结你做了什么。",
1420
1410
  "",
1421
1411
  "## 本次评测禁止调用的工具",
1422
1412
  "",
1423
- blacklistBlock(blacklist),
1424
- "",
1425
- "## 工作区内容",
1426
- "",
1427
- "解压后 workspace/ 里有 TASK.md、SPEC.md、baseline/、src/、workloads/public/ 和 tools/。",
1428
- "先读 TASK.md、baseline 代码和 SPEC.md;SPEC.md 是旧文档,与基线代码不一致时以基线代码的行为为准。",
1429
- "编译命令固定为 g++ -O2 -std=c++20 src/*.cpp;输出必须与 baseline 逐字节相同,包括所有能通过 tools/check_input.py --full 的输入。",
1430
- "用 python3 tools/bench.py 检查正确性和耗时,用 tools/gen.py 生成更多输入和基线对拍。",
1431
- "",
1432
- ...COMPETITION_LINES,
1433
- "",
1434
- "开始吧。"
1413
+ blacklist.length === 0 ? "(无)" : blacklist.join("\n")
1435
1414
  ].join("\n");
1436
1415
  }
1437
1416
  };
1438
- /** Shared prompt for the three bot-writing tasks. */
1439
- function botTaskPrompt(intro, submit, workspaceLines, blacklist, options) {
1440
- return [
1441
- intro,
1442
- "",
1443
- "## 环境与限制",
1444
- "",
1445
- "- 你只能读写当前工作区内的文件;工作区以外的任何位置都不能访问,包括 /tmp。",
1446
- "- 禁止联网、禁止调用其他 AI 或子代理、禁止与其他 agent 通信或读取其他工作区。",
1447
- "- 评测守护会阻止并记录违规行为;违规可能导致本次评测无效。",
1448
- "- 任务必须自主完成:不要向用户提问、不要请求审批、不要等待任何用户输入。",
1449
- "",
1450
- "## 交付",
1451
- "",
1452
- submit,
1453
- "- 最后用几句话说明你的策略。",
1454
- "",
1455
- "## 时间规则",
1456
- "",
1457
- "- 本次是**连续 " + String(options.minutes ?? 90) + " 分钟的单次任务**,从对话开始时开始计时。",
1458
- "- 交付前检查并关闭所有后台任务;到点会被强制终止。",
1459
- "- clock.py 从解压那一刻开始计算,而实际计时从对话开始计算;它**只能作为参考**,请尽快解压以减小误差。实际时间以评测守护为准。",
1460
- "",
1461
- "## 本次评测禁止调用的工具",
1462
- "",
1463
- blacklistBlock(blacklist),
1464
- "",
1465
- "## 工作区内容",
1466
- "",
1467
- ...workspaceLines,
1468
- "",
1469
- ...COMPETITION_LINES,
1470
- "",
1471
- "开始吧。"
1472
- ].join("\n");
1473
- }
1474
- /** Land (territory) bot task. */
1417
+ /** Land bot task, adapted from the original participant prompt. */
1475
1418
  const LAND_DEFINITION = {
1476
1419
  id: LAND_TASK,
1477
1420
  label: LAND_TASK_LABEL,
1478
1421
  description: TASKS[2].description,
1479
1422
  asset: path.join(packageRoot(), "assets", "land", "workspace.zip"),
1480
1423
  prompt(blacklist, options) {
1481
- return botTaskPrompt("这是一场用于评测 AI agent 能力的圈地对战 bot 编程任务。你需要在当前工作区里独立完成它。", "- 解压工作区里的 workspace.zip,进入 workspace/;从 starter/bot.cpp 起步,最终把单文件程序保存到 workspace/submission/bot.cpp。", [
1482
- "解压后 workspace/ 里有 RULES.md、TASK.md、engine/、anchors/、starter/ 和 submission/。",
1483
- "先读 RULES.md、TASK.md、engine/game.py 和 starter/bot.cpp;规则以 engine/game.py 为准。",
1484
- "本地裁判:python3 engine/referee.py submission/bot.cpp anchors/greedy.cpp --games 10(单挑),也可加多个 bot 打混战。",
1485
- "只能提交一个 bot.cpp,编译参数固定为 g++ -O2 -std=c++20,单文件、只用 C++ 标准库。"
1486
- ], blacklist, options);
1424
+ return [
1425
+ "这是一场正式的 AI 编程对抗赛,你的对手是其他顶尖 AI 模型写的 bot,它们会主动切断你、抢你的地。比赛结果会公开排名,请拿出你的最高水平。",
1426
+ "",
1427
+ "请解压当前目录的 workspace.zip,进入 workspace 文件夹,按 TASK.md 的要求编写一个尽可能强的圈地对战 bot,保存为 workspace/submission/bot.cpp。" + clockLine(options.minutes ?? 90) + "只能读写当前文件夹里的文件,不能联网搜索,不要向我提问。",
1428
+ "",
1429
+ "## 本次评测禁止调用的工具",
1430
+ "",
1431
+ blacklist.length === 0 ? "(无)" : blacklist.join("\n")
1432
+ ].join("\n");
1487
1433
  }
1488
1434
  };
1489
- /** Bomberman bot task. */
1435
+ /** Bomberman bot task, adapted from the original participant prompt. */
1490
1436
  const BOMBERMAN_DEFINITION = {
1491
1437
  id: BOMBERMAN_TASK,
1492
1438
  label: BOMBERMAN_TASK_LABEL,
1493
1439
  description: TASKS[3].description,
1494
1440
  asset: path.join(packageRoot(), "assets", "bomberman", "workspace.zip"),
1495
1441
  prompt(blacklist, options) {
1496
- return botTaskPrompt("这是一场用于评测 AI agent 能力的炸弹人对战 bot 编程任务。你需要在当前工作区里独立完成它。", "- 解压工作区里的 workspace.zip,进入 workspace/;最终把单文件程序保存到 workspace/submission/bot.cpp。", [
1497
- "解压后 workspace/ 里有 README.md、RULES.md、engine/、baseline.cpp 和 submission/。",
1498
- "先读 README.md、RULES.md 和 engine/engine.py;baseline.cpp 是公开练习对手,可以编译、对战和复盘。",
1499
- "同一程序要支持 2–10 人;编译参数固定为 g++ -O2 -std=c++20,单文件、只用 C++ 标准库。",
1500
- "用 engine/arena.py 或 README 里的本地命令做对战和回放验证。"
1501
- ], blacklist, options);
1442
+ return [
1443
+ "按照要求编写尽可能强bot,你的对手是全球其他顶尖ai,可能主动设计战术。基准只是很弱的bot,它在正式比赛为0分线。正式赛会对战多轮,用Bradley-Terry模型拟合实力值。",
1444
+ "解压 workspace.zip,阅读 README.md 和 RULES.md,编写支持2–10人的炸弹人 bot。" + clockLine(options.minutes ?? 90) + "允许本地工具、对战和复盘,禁止联网、调用其他AI或查看其他选手资料。提交 submission/bot.cpp,简述策略。",
1445
+ "",
1446
+ "## 本次评测禁止调用的工具",
1447
+ "",
1448
+ blacklist.length === 0 ? "(无)" : blacklist.join("\n")
1449
+ ].join("\n");
1502
1450
  }
1503
1451
  };
1504
- /** CTF (capture the flag) bot task. */
1452
+ /** CTF bot task, adapted from the original participant prompt. */
1505
1453
  const CTF_DEFINITION = {
1506
1454
  id: "ctf",
1507
1455
  label: CTF_TASK_LABEL,
1508
1456
  description: TASKS[4].description,
1509
1457
  asset: path.join(packageRoot(), "assets", "ctf", "workspace.zip"),
1510
1458
  prompt(blacklist, options) {
1511
- return botTaskPrompt("这是一场用于评测 AI agent 能力的夺旗对战 bot 编程任务。你需要在当前工作区里独立完成它。", "- 解压工作区里的 workspace.zip,进入 workspace/;最终把单文件程序保存到 workspace/submission/bot.cpp。", [
1512
- "解压后 workspace/ 里有 README.md、RULES.md、arena.py、engine.py、core.py、baseline.cpp 和 submission/bot.cpp 模板。",
1513
- "先读 README.md、RULES.md 和 submission/bot.cpp;一个程序统一控制己方 3 个角色,支持 2–15 个阵营。",
1514
- "本地对战:python3 arena.py play submission/bot.cpp baseline --seed 7,或 arena.py batch;baseline.cpp 是公开练习对手。",
1515
- "编译参数固定为 g++ -O2 -std=c++20,单文件、只用 C++ 标准库。"
1516
- ], blacklist, options);
1459
+ return [
1460
+ "按照要求编写尽可能强的 bot,你的对手是全球其他顶尖 AI,可能主动设计战术。基准是一个中等强度、思路常规的 bot,它在正式比赛是 0 分线;战胜基准不代表足够强,正式对手远强于基准。正式赛会对战多轮,用 Bradley-Terry 模型拟合实力值。",
1461
+ "解压 workspace.zip,阅读 README.md 和 RULES.md,编写支持 2–15 方的夺旗 bot。" + clockLine(options.minutes ?? 90) + "允许本地工具、对战和复盘,禁止联网、调用其他 AI 或查看其他选手资料。提交 workspace/submission/bot.cpp,简述策略。",
1462
+ "",
1463
+ "## 本次评测禁止调用的工具",
1464
+ "",
1465
+ blacklist.length === 0 ? "(无)" : blacklist.join("\n")
1466
+ ].join("\n");
1517
1467
  }
1518
1468
  };
1519
1469
  /** All task definitions keyed by id. */
@@ -1524,7 +1474,7 @@ const TASK_DEFINITIONS = {
1524
1474
  [BOMBERMAN_TASK]: BOMBERMAN_DEFINITION,
1525
1475
  ["ctf"]: CTF_DEFINITION
1526
1476
  };
1527
- /** Install, check, and prompt services for the task pack. */
1477
+ /** Install, check, and prompt services for the task packs. */
1528
1478
  var TaskService = class {
1529
1479
  guard;
1530
1480
  registry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-eval-guard",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Evaluation guard for DSH: workspace-only filesystem, no network/subagents, wall-clock limits, and task installation for the meow-ai-arena tank task.",
6
6
  "license": "MIT",