mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 04:26:24 +00:00
feat(repos): add an "Initialize mise" option to the add-repo step
Some repos an operator wants to manage don't yet define the `.mise.toml` `[tasks.test]` task the spawn gate hard-requires — a chicken-and-egg, since you can't run an agent to author that file without it. This adds a one-click bootstrap. Ticking "Initialize mise" on the add step enqueues a `mise_init` command after the clone. The worker launches a dedicated agent that detects the repo's stack, writes a `.mise.toml` with a canonical `[tasks.test]` task, and commits + pushes it. That agent runs with the test-task gate off (creating the task is the point) and a `HANDLER_MISE_INIT` marker on, so its hooks enforce a bootstrap contract instead of the normal test gate: - Stop hook blocks the turn until `.mise.toml` defines `[tasks.test]` and the change is committed (clean tree) and pushed (no commits ahead of an upstream) — so claude cannot end before the work has actually landed. - git-push hook lets the bootstrap push through, skipping the test/build gate (there may be no working suite yet) so the file reaches the remote. Backend: `mise_init` command type (+ migration 0006), a shared `control.mise` helper for the test-task check, `spawn(require_tests=, mise_init=)`, gitops `is_clean`/`ahead_count`, and `init_mise` on the project-create API (only acts when a git remote exists to push to). Frontend: the checkbox, plumbed through the store, following the launch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BxKY28XKCM6o4ag3nmaVsZ
This commit is contained in:
@@ -95,6 +95,53 @@ def test_approve_command_records_operator_verdict_with_head_sha(env, fake_gitops
|
||||
assert ap["approved_sha"] == fake_gitops["sha"] # read from the agent's working dir
|
||||
|
||||
|
||||
def test_mise_init_command_spawns_bootstrap_agent(env, monkeypatch):
|
||||
_seed_project()
|
||||
calls = {}
|
||||
|
||||
def fake_spawn(project_id, name, **kw):
|
||||
calls.update(project_id=project_id, name=name, **kw)
|
||||
return {"id": 7, "name": name, "working_dir": "/tmp/p/mise-init"}
|
||||
|
||||
monkeypatch.setattr(spawn, "spawn", fake_spawn)
|
||||
cmd = _enqueue(type="mise_init", project_id="p")
|
||||
|
||||
assert worker.drain("w") == 1
|
||||
done = _get(cmd["id"])
|
||||
assert done["status"] == "done"
|
||||
assert done["result"]["agent_id"] == 7
|
||||
assert done["result"]["name"] == "mise-init"
|
||||
# Launched with the test gate off and the bootstrap marker on, with the default task.
|
||||
assert calls["require_tests"] is False
|
||||
assert calls["mise_init"] is True
|
||||
assert ".mise.toml" in calls["task"]
|
||||
|
||||
|
||||
def test_mise_init_command_honors_payload_overrides(env, monkeypatch):
|
||||
_seed_project()
|
||||
calls = {}
|
||||
|
||||
def fake_spawn(project_id, name, **kw):
|
||||
calls.update(name=name, **kw)
|
||||
return {"id": 8, "name": name, "working_dir": "/tmp/p/x"}
|
||||
|
||||
monkeypatch.setattr(spawn, "spawn", fake_spawn)
|
||||
cmd = _enqueue(
|
||||
type="mise_init", project_id="p", payload={"name": "boot", "task": "custom task"}
|
||||
)
|
||||
|
||||
worker.drain("w")
|
||||
assert _get(cmd["id"])["status"] == "done"
|
||||
assert calls["name"] == "boot"
|
||||
assert calls["task"] == "custom task"
|
||||
|
||||
|
||||
def test_mise_init_without_project_is_failed(env):
|
||||
cmd = _enqueue(type="mise_init")
|
||||
assert worker.drain("w") == 1
|
||||
assert _get(cmd["id"])["status"] == "failed"
|
||||
|
||||
|
||||
def test_poll_ci_command_returns_summary(env, monkeypatch):
|
||||
_seed_project()
|
||||
summary = {"checked": 0, "resolved": 0, "pending": 0}
|
||||
|
||||
Reference in New Issue
Block a user