fix(web): bound unattended implementation turns
This commit is contained in:
@@ -199,6 +199,8 @@ Rules:
|
|||||||
- Preserve all existing dirty changes. Do not revert or rewrite unrelated work.
|
- Preserve all existing dirty changes. Do not revert or rewrite unrelated work.
|
||||||
- Read only the owned paths and their direct imported types/helpers.
|
- Read only the owned paths and their direct imported types/helpers.
|
||||||
- For scoped searches, pass each owned path explicitly through the batch search runtime option; never pass a bare --runtime flag.
|
- For scoped searches, pass each owned path explicitly through the batch search runtime option; never pass a bare --runtime flag.
|
||||||
|
- Hard budget: at most 16 tool commands, including at most 8 read/search commands. After the read budget, implement immediately.
|
||||||
|
- Do not print or reread the complete diff; inspect only the edited regions once before writing the result.
|
||||||
- Implement production behavior through the existing Blender Main/WASM command routes; do not simulate Blender behavior in JavaScript.
|
- Implement production behavior through the existing Blender Main/WASM command routes; do not simulate Blender behavior in JavaScript.
|
||||||
- Do not run tests, builds, typecheck, lint, Chromium, full validators, or coverage binding. The user explicitly deferred verification to real usage.
|
- Do not run tests, builds, typecheck, lint, Chromium, full validators, or coverage binding. The user explicitly deferred verification to real usage.
|
||||||
- Do not modify docs/EXECUTION_QUEUE.md, nextTask.md, source coverage ledgers, manifests, or this backlog.
|
- Do not modify docs/EXECUTION_QUEUE.md, nextTask.md, source coverage ledgers, manifests, or this backlog.
|
||||||
@@ -220,6 +222,8 @@ def run_task(task: dict, heartbeat_seconds: float) -> tuple[int, bool]:
|
|||||||
"--ephemeral", "--cd", str(ROOT), "--json", "-",
|
"--ephemeral", "--cd", str(ROOT), "--json", "-",
|
||||||
]
|
]
|
||||||
completed_turn = False
|
completed_turn = False
|
||||||
|
result_seen_at: float | None = None
|
||||||
|
task_started_at = time.monotonic()
|
||||||
with log_path.open("w", encoding="utf-8") as log:
|
with log_path.open("w", encoding="utf-8") as log:
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
command,
|
command,
|
||||||
@@ -238,6 +242,8 @@ def run_task(task: dict, heartbeat_seconds: float) -> tuple[int, bool]:
|
|||||||
write_status(read_json(BACKLOG), "implementing", activeTask=task["id"], childPid=process.pid, log=str(log_path.relative_to(ROOT)))
|
write_status(read_json(BACKLOG), "implementing", activeTask=task["id"], childPid=process.pid, log=str(log_path.relative_to(ROOT)))
|
||||||
log.flush()
|
log.flush()
|
||||||
if result_path.is_file():
|
if result_path.is_file():
|
||||||
|
if result_seen_at is None:
|
||||||
|
result_seen_at = time.monotonic()
|
||||||
try:
|
try:
|
||||||
with log_path.open("rb") as current_log:
|
with log_path.open("rb") as current_log:
|
||||||
end = current_log.seek(0, os.SEEK_END)
|
end = current_log.seek(0, os.SEEK_END)
|
||||||
@@ -245,6 +251,8 @@ def run_task(task: dict, heartbeat_seconds: float) -> tuple[int, bool]:
|
|||||||
completed_turn = b'"type":"turn.completed"' in current_log.read()
|
completed_turn = b'"type":"turn.completed"' in current_log.read()
|
||||||
except OSError:
|
except OSError:
|
||||||
completed_turn = False
|
completed_turn = False
|
||||||
|
if time.monotonic() - result_seen_at >= 5:
|
||||||
|
completed_turn = True
|
||||||
if completed_turn:
|
if completed_turn:
|
||||||
try:
|
try:
|
||||||
os.killpg(process.pid, signal.SIGTERM)
|
os.killpg(process.pid, signal.SIGTERM)
|
||||||
@@ -255,6 +263,16 @@ def run_task(task: dict, heartbeat_seconds: float) -> tuple[int, bool]:
|
|||||||
os.killpg(process.pid, signal.SIGKILL)
|
os.killpg(process.pid, signal.SIGKILL)
|
||||||
process.wait()
|
process.wait()
|
||||||
break
|
break
|
||||||
|
if time.monotonic() - task_started_at >= 900:
|
||||||
|
try:
|
||||||
|
os.killpg(process.pid, signal.SIGTERM)
|
||||||
|
process.wait(timeout=5)
|
||||||
|
except ProcessLookupError:
|
||||||
|
pass
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
os.killpg(process.pid, signal.SIGKILL)
|
||||||
|
process.wait()
|
||||||
|
break
|
||||||
time.sleep(heartbeat_seconds)
|
time.sleep(heartbeat_seconds)
|
||||||
code = 0 if completed_turn else (process.returncode or 0)
|
code = 0 if completed_turn else (process.returncode or 0)
|
||||||
ACTIVE_PROCESS = None
|
ACTIVE_PROCESS = None
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ const arg = (name, fallback = null) => {
|
|||||||
const index = process.argv.indexOf(name);
|
const index = process.argv.indexOf(name);
|
||||||
return index >= 0 ? process.argv[index + 1] : fallback;
|
return index >= 0 ? process.argv[index + 1] : fallback;
|
||||||
};
|
};
|
||||||
|
if (process.argv.includes("--help")) {
|
||||||
|
process.stdout.write("usage: node tools/web/search-wbv2-batch-source.mjs [--task <task-id>] --pattern <text> [--runtime <path> ...] or --list\n");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
const task = arg("--task") ?? read("docs/EXECUTION_QUEUE.md").match(/\| 当前任务 \| `([^`]+)` \|/u)?.[1];
|
const task = arg("--task") ?? read("docs/EXECUTION_QUEUE.md").match(/\| 当前任务 \| `([^`]+)` \|/u)?.[1];
|
||||||
const pattern = arg("--pattern");
|
const pattern = arg("--pattern");
|
||||||
if (!task) throw new Error("unable to resolve current WBV2 task");
|
if (!task) throw new Error("unable to resolve current WBV2 task");
|
||||||
|
|||||||
Reference in New Issue
Block a user