blitz-cli 0.10.0__tar.gz → 0.11.0__tar.gz
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.
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/PKG-INFO +9 -9
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/README.md +8 -8
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/__init__.py +1 -1
- blitz_cli-0.10.0/blitz_cli/_implement.py → blitz_cli-0.11.0/blitz_cli/_execute.py +5 -5
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_ontology.py +4 -4
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/cli.py +26 -20
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/implement.md +3 -3
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/tasks.md +2 -2
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/templates/workspace_playbook.md.tmpl +1 -1
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/pyproject.toml +1 -1
- blitz_cli-0.11.0/specs/001-cli-model-namespace/checklists/requirements.md +34 -0
- blitz_cli-0.11.0/specs/001-cli-model-namespace/contracts/cli-commands.md +47 -0
- blitz_cli-0.11.0/specs/001-cli-model-namespace/plan.md +73 -0
- blitz_cli-0.11.0/specs/001-cli-model-namespace/quickstart.md +37 -0
- blitz_cli-0.11.0/specs/001-cli-model-namespace/research.md +34 -0
- blitz_cli-0.11.0/specs/001-cli-model-namespace/spec.md +69 -0
- blitz_cli-0.11.0/specs/001-cli-model-namespace/tasks.md +83 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_cli.py +19 -0
- blitz_cli-0.10.0/tests/test_implement.py → blitz_cli-0.11.0/tests/test_execute.py +27 -27
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_ontology.py +2 -2
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/.github/workflows/homebrew.yml +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/.github/workflows/publish.yml +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/.gitignore +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/.mcp.json +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/LICENSE +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_activity.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_code_graph.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_corpus.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_dataset.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_git.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_make.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_playbooks.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_redact.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_scaffold.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_tool_schemas.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/_train.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/__init__.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/__init__.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/analyze.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/clarify.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/plan.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/playbook.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/commands/specify.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/memory/playbook.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/check-prerequisites.sh +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/common.sh +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/create-new-feature.sh +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/setup-plan.sh +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/setup-tasks.sh +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/templates/plan-template.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/templates/spec-template.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/templates/tasks-template.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/workspace/__init__.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/workspace/huddle.md +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/templates/__init__.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/templates/locker_room_Makefile.tmpl +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/templates/locker_room_README.md.tmpl +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/templates/locker_room_compose.yml.tmpl +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_activity.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_corpus.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_make.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_playbooks.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_redact.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_scaffold.py +0 -0
- {blitz_cli-0.10.0 → blitz_cli-0.11.0}/tests/test_tool_schemas.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blitz-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Developer CLI for Blitz locker-room: spec-driven playbooks, a codebase/huddle ontology graph with an MCP tool, and the composable watcher/trainer/graph containers.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -31,7 +31,7 @@ The core CLI is stdlib plus `rich`. Two optional extras carry heavier deps only
|
|
|
31
31
|
when you need them: `blitz-cli[locker-room]` (the MCP server) and
|
|
32
32
|
`blitz-cli[train]` (the QLoRA trainer).
|
|
33
33
|
|
|
34
|
-
Top-level commands: `init`, `
|
|
34
|
+
Top-level commands: `init`, `model`, `locker-room`.
|
|
35
35
|
|
|
36
36
|
## Playbooks: spec-driven development commands
|
|
37
37
|
|
|
@@ -51,9 +51,9 @@ and `analyze`. Run at a folder of repos, `init` installs into each repo it finds
|
|
|
51
51
|
for coordinating a feature across repos. Use `--ignore PATH` to skip a repo and
|
|
52
52
|
`--root` to force a single install.
|
|
53
53
|
|
|
54
|
-
##
|
|
54
|
+
## Model execute: run a tasks.md with a local model
|
|
55
55
|
|
|
56
|
-
`blitz
|
|
56
|
+
`blitz model execute` drives a local model (served by Ollama) through a
|
|
57
57
|
playbook-generated `tasks.md`, one task at a time. The model only proposes
|
|
58
58
|
actions (full-file writes and shell commands); the driver applies them, runs
|
|
59
59
|
each phase's machine-runnable verification, retries with the failure fed back
|
|
@@ -61,17 +61,17 @@ each phase's machine-runnable verification, retries with the failure fed back
|
|
|
61
61
|
`- [x]` in the tasks.md. A task that keeps failing stops the run so the state
|
|
62
62
|
stays inspectable. Per-attempt model replies, snapshots, and exact token
|
|
63
63
|
accounting (`usage.json`, per task and total) land under
|
|
64
|
-
`.blitz/
|
|
64
|
+
`.blitz/execute/runs/<timestamp>/`.
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
blitz
|
|
68
|
-
blitz
|
|
69
|
-
blitz
|
|
67
|
+
blitz model execute # auto-detect the open specs/*/tasks.md
|
|
68
|
+
blitz model execute specs/001-my-feature/tasks.md # or name it
|
|
69
|
+
blitz model execute --model qwen2.5-14b-28k --start-at T005
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Tasks whose text says "optional manual" are skipped and left unchecked. The
|
|
73
73
|
Ollama endpoint comes from `--ollama-url` or `OLLAMA_HOST`; the model from
|
|
74
|
-
`--model` or `
|
|
74
|
+
`--model` or `BLITZ_EXECUTE_MODEL`.
|
|
75
75
|
|
|
76
76
|
## Locker-room: ontology graph, watcher, trainer, MCP
|
|
77
77
|
|
|
@@ -12,7 +12,7 @@ The core CLI is stdlib plus `rich`. Two optional extras carry heavier deps only
|
|
|
12
12
|
when you need them: `blitz-cli[locker-room]` (the MCP server) and
|
|
13
13
|
`blitz-cli[train]` (the QLoRA trainer).
|
|
14
14
|
|
|
15
|
-
Top-level commands: `init`, `
|
|
15
|
+
Top-level commands: `init`, `model`, `locker-room`.
|
|
16
16
|
|
|
17
17
|
## Playbooks: spec-driven development commands
|
|
18
18
|
|
|
@@ -32,9 +32,9 @@ and `analyze`. Run at a folder of repos, `init` installs into each repo it finds
|
|
|
32
32
|
for coordinating a feature across repos. Use `--ignore PATH` to skip a repo and
|
|
33
33
|
`--root` to force a single install.
|
|
34
34
|
|
|
35
|
-
##
|
|
35
|
+
## Model execute: run a tasks.md with a local model
|
|
36
36
|
|
|
37
|
-
`blitz
|
|
37
|
+
`blitz model execute` drives a local model (served by Ollama) through a
|
|
38
38
|
playbook-generated `tasks.md`, one task at a time. The model only proposes
|
|
39
39
|
actions (full-file writes and shell commands); the driver applies them, runs
|
|
40
40
|
each phase's machine-runnable verification, retries with the failure fed back
|
|
@@ -42,17 +42,17 @@ each phase's machine-runnable verification, retries with the failure fed back
|
|
|
42
42
|
`- [x]` in the tasks.md. A task that keeps failing stops the run so the state
|
|
43
43
|
stays inspectable. Per-attempt model replies, snapshots, and exact token
|
|
44
44
|
accounting (`usage.json`, per task and total) land under
|
|
45
|
-
`.blitz/
|
|
45
|
+
`.blitz/execute/runs/<timestamp>/`.
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
blitz
|
|
49
|
-
blitz
|
|
50
|
-
blitz
|
|
48
|
+
blitz model execute # auto-detect the open specs/*/tasks.md
|
|
49
|
+
blitz model execute specs/001-my-feature/tasks.md # or name it
|
|
50
|
+
blitz model execute --model qwen2.5-14b-28k --start-at T005
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
Tasks whose text says "optional manual" are skipped and left unchecked. The
|
|
54
54
|
Ollama endpoint comes from `--ollama-url` or `OLLAMA_HOST`; the model from
|
|
55
|
-
`--model` or `
|
|
55
|
+
`--model` or `BLITZ_EXECUTE_MODEL`.
|
|
56
56
|
|
|
57
57
|
## Locker-room: ontology graph, watcher, trainer, MCP
|
|
58
58
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Drive a local model (served by Ollama) through a playbook-generated
|
|
2
2
|
tasks.md, one task at a time — the local-model execution backend for the
|
|
3
|
-
`
|
|
3
|
+
`blitz model execute` command.
|
|
4
4
|
|
|
5
5
|
The model never touches the repo directly: it only proposes actions
|
|
6
6
|
(full-file ===WRITE=== blocks and ===RUN=== commands) and this driver applies
|
|
@@ -237,12 +237,12 @@ def local_model_config(repo: Path) -> dict:
|
|
|
237
237
|
|
|
238
238
|
|
|
239
239
|
def usage_by_spec(repo: Path) -> dict:
|
|
240
|
-
"""Aggregate every
|
|
241
|
-
.blitz/
|
|
240
|
+
"""Aggregate every execute run's usage.json under
|
|
241
|
+
.blitz/execute/runs/, keyed by spec: total input/output tokens, model
|
|
242
242
|
calls, run count, and the models used. This is what the locker-room
|
|
243
243
|
ontologizer attaches to Feature nodes so the UI can show per-spec cost."""
|
|
244
244
|
totals: dict = {}
|
|
245
|
-
for f in sorted(repo.glob(".blitz/
|
|
245
|
+
for f in sorted(repo.glob(".blitz/execute/runs/*/usage.json")):
|
|
246
246
|
try:
|
|
247
247
|
record = json.loads(f.read_text())
|
|
248
248
|
except (OSError, ValueError):
|
|
@@ -289,7 +289,7 @@ def run(
|
|
|
289
289
|
"""Execute every unchecked task in tasks_file. Returns 0 on success, 1 when a
|
|
290
290
|
task fails after all retries (the run stops there so state stays inspectable)."""
|
|
291
291
|
call_model = call_model or (lambda messages: call_ollama(ollama_url, model, messages))
|
|
292
|
-
run_root = run_root or (repo / ".blitz" / "
|
|
292
|
+
run_root = run_root or (repo / ".blitz" / "execute" / "runs")
|
|
293
293
|
rundir = run_root / datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
|
294
294
|
snapdir = rundir / "snapshots"
|
|
295
295
|
snapdir.mkdir(parents=True, exist_ok=True)
|
|
@@ -16,7 +16,7 @@ import re
|
|
|
16
16
|
import sqlite3
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
|
-
from blitz_cli import _activity,
|
|
19
|
+
from blitz_cli import _activity, _execute, _playbooks
|
|
20
20
|
|
|
21
21
|
# --- graph store -------------------------------------------------------------
|
|
22
22
|
|
|
@@ -349,10 +349,10 @@ def _read_active_feature(repo: Path) -> str | None:
|
|
|
349
349
|
|
|
350
350
|
def _tasks_complete(tasks_md: Path) -> bool:
|
|
351
351
|
"""True when every required task in a tasks.md is checked off. Tasks whose
|
|
352
|
-
text says "optional manual" don't count against completion (the
|
|
352
|
+
text says "optional manual" don't count against completion (the execute
|
|
353
353
|
driver skips them by design)."""
|
|
354
354
|
try:
|
|
355
|
-
tasks, _ =
|
|
355
|
+
tasks, _ = _execute.parse_tasks(tasks_md.read_text(encoding="utf-8"))
|
|
356
356
|
except OSError:
|
|
357
357
|
return False
|
|
358
358
|
required = [t for t in tasks if "optional manual" not in t["body"].lower()]
|
|
@@ -527,7 +527,7 @@ def ontologize(workspace_root, db_path, ignore=None, code=True,
|
|
|
527
527
|
_code_graph.scan_repo(store, repo, rid, max_file_bytes=max_file_bytes)
|
|
528
528
|
|
|
529
529
|
active = _read_active_feature(repo)
|
|
530
|
-
usage =
|
|
530
|
+
usage = _execute.usage_by_spec(repo)
|
|
531
531
|
specs = repo / "specs"
|
|
532
532
|
if specs.is_dir():
|
|
533
533
|
for feat in sorted(specs.iterdir()):
|
|
@@ -59,8 +59,8 @@ def _cmd_locker_room_make(args: argparse.Namespace) -> int:
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
def
|
|
63
|
-
from blitz_cli import
|
|
62
|
+
def _cmd_execute(args: argparse.Namespace) -> int:
|
|
63
|
+
from blitz_cli import _execute
|
|
64
64
|
|
|
65
65
|
repo = Path(args.repo).resolve()
|
|
66
66
|
if args.tasks:
|
|
@@ -68,7 +68,7 @@ def _cmd_implement(args: argparse.Namespace) -> int:
|
|
|
68
68
|
if not tasks_file.is_absolute():
|
|
69
69
|
tasks_file = repo / tasks_file
|
|
70
70
|
else:
|
|
71
|
-
tasks_file =
|
|
71
|
+
tasks_file = _execute.find_tasks_file(repo)
|
|
72
72
|
if tasks_file is None:
|
|
73
73
|
_eprint(
|
|
74
74
|
f"error: could not auto-detect a unique specs/*/tasks.md with "
|
|
@@ -80,16 +80,16 @@ def _cmd_implement(args: argparse.Namespace) -> int:
|
|
|
80
80
|
_eprint(f"error: no tasks file at {tasks_file}.")
|
|
81
81
|
return 2
|
|
82
82
|
|
|
83
|
-
# Model resolution: --model flag >
|
|
83
|
+
# Model resolution: --model flag > BLITZ_EXECUTE_MODEL env >
|
|
84
84
|
# .blitz/config.json local_model.model (repo, then workspace) > default.
|
|
85
85
|
model = (
|
|
86
86
|
args.model
|
|
87
|
-
or os.environ.get("
|
|
88
|
-
or
|
|
89
|
-
or
|
|
87
|
+
or os.environ.get("BLITZ_EXECUTE_MODEL")
|
|
88
|
+
or _execute.local_model_config(repo).get("model")
|
|
89
|
+
or _execute.DEFAULT_MODEL
|
|
90
90
|
)
|
|
91
91
|
|
|
92
|
-
return
|
|
92
|
+
return _execute.run(
|
|
93
93
|
repo=repo,
|
|
94
94
|
tasks_file=tasks_file,
|
|
95
95
|
model=model,
|
|
@@ -290,48 +290,54 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
290
290
|
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
291
291
|
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
"
|
|
293
|
+
model = sub.add_parser(
|
|
294
|
+
"model",
|
|
295
|
+
help="Model lifecycle commands (e.g. execute a tasks.md with a local model).",
|
|
296
|
+
)
|
|
297
|
+
model_sub = model.add_subparsers(dest="model_cmd", required=True)
|
|
298
|
+
|
|
299
|
+
execute = model_sub.add_parser(
|
|
300
|
+
"execute",
|
|
295
301
|
help="Execute a playbook-generated tasks.md with a local model served by "
|
|
296
302
|
"Ollama: one task per call, driver-side verification, bounded retries, "
|
|
297
|
-
"snapshots under .blitz/
|
|
303
|
+
"snapshots under .blitz/execute/runs/.",
|
|
298
304
|
)
|
|
299
|
-
|
|
305
|
+
execute.add_argument(
|
|
300
306
|
"tasks", nargs="?", default=None,
|
|
301
307
|
help="Path to the tasks.md (relative to --repo). Default: the unique "
|
|
302
308
|
"specs/*/tasks.md that still has unchecked tasks.",
|
|
303
309
|
)
|
|
304
|
-
|
|
310
|
+
execute.add_argument(
|
|
305
311
|
"--repo", default=".", help="Repo root the tasks operate on (default: current dir)."
|
|
306
312
|
)
|
|
307
|
-
|
|
313
|
+
execute.add_argument(
|
|
308
314
|
"--model",
|
|
309
315
|
default=None,
|
|
310
316
|
help="Ollama model to drive. Default resolution: this flag, then "
|
|
311
|
-
"
|
|
317
|
+
"BLITZ_EXECUTE_MODEL, then local_model.model in .blitz/config.json "
|
|
312
318
|
"(repo, then workspace), then qwen2.5-14b-28k.",
|
|
313
319
|
)
|
|
314
|
-
|
|
320
|
+
execute.add_argument(
|
|
315
321
|
"--local-only", action="store_true",
|
|
316
322
|
help="Execute only tasks marked [L] (local-model eligible), stopping at "
|
|
317
323
|
"the first unchecked task without the marker so an orchestrating agent "
|
|
318
324
|
"can take over. Used to split a tasks.md between the local model and a "
|
|
319
325
|
"frontier agent.",
|
|
320
326
|
)
|
|
321
|
-
|
|
327
|
+
execute.add_argument(
|
|
322
328
|
"--ollama-url",
|
|
323
329
|
default=os.environ.get("OLLAMA_HOST", "http://localhost:11434"),
|
|
324
330
|
help="Ollama base URL (default http://localhost:11434; env OLLAMA_HOST).",
|
|
325
331
|
)
|
|
326
|
-
|
|
332
|
+
execute.add_argument(
|
|
327
333
|
"--max-retries", type=int, default=2,
|
|
328
334
|
help="Retries per task with the failure fed back before stopping the run (default 2).",
|
|
329
335
|
)
|
|
330
|
-
|
|
336
|
+
execute.add_argument(
|
|
331
337
|
"--start-at", default=None, metavar="TASK_ID",
|
|
332
338
|
help="Skip ahead to this task id (e.g. T005) before executing.",
|
|
333
339
|
)
|
|
334
|
-
|
|
340
|
+
execute.set_defaults(func=_cmd_execute)
|
|
335
341
|
|
|
336
342
|
sp_init = sub.add_parser(
|
|
337
343
|
"init",
|
|
@@ -151,15 +151,15 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|
|
151
151
|
that is the point of the marker: the user is paying for frontier tokens only where needed.
|
|
152
152
|
- Work through the task list in ID order with this loop:
|
|
153
153
|
1. Find the next unchecked, non-"optional manual" task.
|
|
154
|
-
2. If it is marked `[L]`: run `blitz
|
|
154
|
+
2. If it is marked `[L]`: run `blitz model execute <path-to-tasks.md> --local-only --start-at <TaskID>`
|
|
155
155
|
and wait. The command executes the contiguous run of `[L]` tasks, checks them off in
|
|
156
156
|
tasks.md, and exits 0 when it reaches a task without the marker (or finishes).
|
|
157
157
|
Exit 1 means a local task failed after retries — take that task over yourself
|
|
158
|
-
(its per-attempt replies are in `.blitz/
|
|
158
|
+
(its per-attempt replies are in `.blitz/execute/runs/<stamp>/`), mark it off,
|
|
159
159
|
then resume the loop.
|
|
160
160
|
3. If it is NOT marked `[L]`: execute it yourself as described below, mark it off,
|
|
161
161
|
and resume the loop.
|
|
162
|
-
4. After every `blitz
|
|
162
|
+
4. After every `blitz model execute` invocation, RE-READ tasks.md — the file changed on disk.
|
|
163
163
|
- Never execute an `[L]` task yourself while the CLI is available unless it has already
|
|
164
164
|
failed a local run.
|
|
165
165
|
|
|
@@ -206,7 +206,7 @@ files that are exactly specified and unforgiving of drift.
|
|
|
206
206
|
### Executor Annotation ([L] marker)
|
|
207
207
|
|
|
208
208
|
Task lists can be executed by a mix of a frontier agent and the user's own local model (via
|
|
209
|
-
`blitz
|
|
209
|
+
`blitz model execute --local-only`). Whether a local model is available — and what it can handle —
|
|
210
210
|
is configured, not guessed:
|
|
211
211
|
|
|
212
212
|
1. Read `.blitz/config.json` in the repo root. If it has no `local_model` key, read
|
|
@@ -240,7 +240,7 @@ is configured, not guessed:
|
|
|
240
240
|
|
|
241
241
|
4. Place `[L]` after `[P]` and before the `[Story]` label:
|
|
242
242
|
`- [ ] T003 [P] [L] [US1] CREATE ...`
|
|
243
|
-
5. The marker is load-bearing and machine-parsed: `blitz
|
|
243
|
+
5. The marker is load-bearing and machine-parsed: `blitz model execute --local-only` executes
|
|
244
244
|
consecutive `[L]` tasks and stops at the first task without the marker, handing control back
|
|
245
245
|
to the orchestrating agent. Keep runs of local-eligible tasks contiguous where dependencies
|
|
246
246
|
allow — interleaving one frontier task between local ones forces a round-trip per task.
|
|
@@ -21,7 +21,7 @@ and what code a feature touches via lineage queries.
|
|
|
21
21
|
## Executor routing
|
|
22
22
|
|
|
23
23
|
`.blitz/config.json` may define a `local_model`. Tasks marked `[L]` in a
|
|
24
|
-
tasks.md are executable by that model via `blitz
|
|
24
|
+
tasks.md are executable by that model via `blitz model execute --local-only`;
|
|
25
25
|
frontier agents handle the rest. See the /implement command for the handoff
|
|
26
26
|
loop.
|
|
27
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "blitz-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.11.0"
|
|
4
4
|
description = "Developer CLI for Blitz locker-room: spec-driven playbooks, a codebase/huddle ontology graph with an MCP tool, and the composable watcher/trainer/graph containers."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Specification Quality Checklist: CLI model namespace (retire "implement")
|
|
2
|
+
|
|
3
|
+
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
|
4
|
+
**Created**: 2026-07-14
|
|
5
|
+
**Feature**: [spec.md](../spec.md)
|
|
6
|
+
|
|
7
|
+
## Content Quality
|
|
8
|
+
|
|
9
|
+
- [x] No implementation details (languages, frameworks, APIs)
|
|
10
|
+
- [x] Focused on user value and business needs
|
|
11
|
+
- [x] Written for non-technical stakeholders
|
|
12
|
+
- [x] All mandatory sections completed
|
|
13
|
+
|
|
14
|
+
## Requirement Completeness
|
|
15
|
+
|
|
16
|
+
- [x] No [NEEDS CLARIFICATION] markers remain
|
|
17
|
+
- [x] Requirements are testable and unambiguous
|
|
18
|
+
- [x] Success criteria are measurable
|
|
19
|
+
- [x] Success criteria are technology-agnostic (no implementation details)
|
|
20
|
+
- [x] All acceptance scenarios are defined
|
|
21
|
+
- [x] Edge cases are identified
|
|
22
|
+
- [x] Scope is clearly bounded
|
|
23
|
+
- [x] Dependencies and assumptions identified
|
|
24
|
+
|
|
25
|
+
## Feature Readiness
|
|
26
|
+
|
|
27
|
+
- [x] All functional requirements have clear acceptance criteria
|
|
28
|
+
- [x] User scenarios cover primary flows
|
|
29
|
+
- [x] Feature meets measurable outcomes defined in Success Criteria
|
|
30
|
+
- [x] No implementation details leak into specification
|
|
31
|
+
|
|
32
|
+
## Notes
|
|
33
|
+
|
|
34
|
+
- Hard-rename decision resolved with the user; no open clarifications. Spec ready for `/plan`.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# CLI Command Surface Contract
|
|
2
|
+
|
|
3
|
+
## Before
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
blitz implement [tasks] [--repo DIR] [--model M] [--local-only]
|
|
7
|
+
[--ollama-url URL] [--max-retries N] [--start-at TASK_ID]
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## After
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
blitz model execute [tasks] [--repo DIR] [--model M] [--local-only]
|
|
14
|
+
[--ollama-url URL] [--max-retries N] [--start-at TASK_ID]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- `blitz model` (no subcommand) → prints `model` group help, exits non-zero (subparser `required=True`).
|
|
18
|
+
- `blitz model execute …` → identical arguments, defaults, behavior, and exit codes as the former `blitz implement`. Handler: `_cmd_execute`.
|
|
19
|
+
- `blitz --help` → lists `model`; does NOT list `implement`.
|
|
20
|
+
- `blitz model --help` → lists `execute` with the help text formerly on `implement`.
|
|
21
|
+
- `blitz implement …` → **removed**. Argparse default "invalid choice: 'implement'" error, non-zero exit. No stub, no forwarding.
|
|
22
|
+
|
|
23
|
+
## Arguments carried onto `execute` (unchanged)
|
|
24
|
+
|
|
25
|
+
| Arg | Type | Default |
|
|
26
|
+
|-----|------|---------|
|
|
27
|
+
| `tasks` | positional, optional | None (auto-detect open `specs/*/tasks.md`) |
|
|
28
|
+
| `--repo` | str | `.` |
|
|
29
|
+
| `--model` | str | None (resolves via flag → `BLITZ_EXECUTE_MODEL` → config → `qwen2.5-14b-28k`) |
|
|
30
|
+
| `--local-only` | flag | False |
|
|
31
|
+
| `--ollama-url` | str | `$OLLAMA_HOST` or `http://localhost:11434` |
|
|
32
|
+
| `--max-retries` | int | 2 |
|
|
33
|
+
| `--start-at` | str (TASK_ID) | None |
|
|
34
|
+
|
|
35
|
+
## Renamed identifiers (breaking, no migration)
|
|
36
|
+
|
|
37
|
+
| Old | New |
|
|
38
|
+
|-----|-----|
|
|
39
|
+
| env `BLITZ_IMPLEMENT_MODEL` | env `BLITZ_EXECUTE_MODEL` |
|
|
40
|
+
| path `.blitz/implement/runs/` | path `.blitz/execute/runs/` |
|
|
41
|
+
| module `blitz_cli/_implement.py` | module `blitz_cli/_execute.py` |
|
|
42
|
+
| handler `_cmd_implement` | handler `_cmd_execute` |
|
|
43
|
+
| test `tests/test_implement.py` | test `tests/test_execute.py` |
|
|
44
|
+
|
|
45
|
+
## Not changed
|
|
46
|
+
|
|
47
|
+
The `/implement` playbook SDD slash-command, the `"implemented"` lifecycle stage, and generic "implementation" prose are out of scope.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Implementation Plan: CLI model namespace (retire "implement")
|
|
2
|
+
|
|
3
|
+
**Branch**: `001-cli-model-namespace` | **Date**: 2026-07-14 | **Spec**: [spec.md](./spec.md)
|
|
4
|
+
|
|
5
|
+
**Input**: Feature specification from `specs/001-cli-model-namespace/spec.md`
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
Move the top-level `blitz implement` subcommand under a new `model` command group and rename it to `execute` (`blitz model execute`), and purge the "implement" nomenclature that names this command. The engine behavior is reused unchanged, but the module, handler, env var, and run-snapshot path are all renamed to "execute". The old `blitz implement` is removed outright (no error stub) — argparse reports an invalid choice. This is a breaking change with no migration of existing `.blitz/implement/runs/` snapshots or `BLITZ_IMPLEMENT_MODEL` settings.
|
|
10
|
+
|
|
11
|
+
Out of scope (distinct concept, NOT renamed): the `/implement` playbook SDD slash-command and its `__SPECKIT_COMMAND_IMPLEMENT__` token; the `"implemented"` feature lifecycle stage in `_ontology.py`; generic "implementation" prose.
|
|
12
|
+
|
|
13
|
+
## Technical Context
|
|
14
|
+
|
|
15
|
+
**Language/Version**: Python 3 (stdlib + `rich`); `argparse` CLI.
|
|
16
|
+
**Primary Dependencies**: stdlib `argparse`; no new deps.
|
|
17
|
+
**Storage**: On-disk run snapshots move `.blitz/implement/runs/` → `.blitz/execute/runs/` (breaking, no migration).
|
|
18
|
+
**Testing**: `pytest`; `tests/test_implement.py` → `tests/test_execute.py`; plus `tests/test_cli.py`, `tests/test_ontology.py`.
|
|
19
|
+
**Target Platform**: Local developer machines (pip-installed CLI).
|
|
20
|
+
**Project Type**: Single-project CLI (`blitz_cli/`).
|
|
21
|
+
**Performance Goals**: N/A (rename/refactor).
|
|
22
|
+
**Constraints**: Backward-incompatible by design; no compatibility shims.
|
|
23
|
+
**Scale/Scope**: One subparser relocation+rename, module/handler/env/path rename across ~4 source files + tests + docs.
|
|
24
|
+
|
|
25
|
+
## Playbook Check
|
|
26
|
+
|
|
27
|
+
`.blitz/memory/playbook.md` is the unfilled template — no concrete gates. PASS.
|
|
28
|
+
|
|
29
|
+
## Project Structure
|
|
30
|
+
|
|
31
|
+
### Documentation (this feature)
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
specs/001-cli-model-namespace/
|
|
35
|
+
├── plan.md · research.md · quickstart.md
|
|
36
|
+
├── contracts/cli-commands.md
|
|
37
|
+
├── checklists/requirements.md
|
|
38
|
+
└── tasks.md
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
(No data-model.md — no entities.)
|
|
42
|
+
|
|
43
|
+
### Source Code — files touched
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
blitz_cli/
|
|
47
|
+
├── cli.py # EDIT: build_parser() — replace top-level `implement` parser with
|
|
48
|
+
│ # `model` group + `execute` child; rename _cmd_implement → _cmd_execute;
|
|
49
|
+
│ # import _execute; read BLITZ_EXECUTE_MODEL; update help text
|
|
50
|
+
├── _implement.py # RENAME → _execute.py; update `.blitz/implement/runs` → `.blitz/execute/runs`
|
|
51
|
+
│ # (lines ~240,241,245,292) and the module docstring
|
|
52
|
+
├── _ontology.py # EDIT: import _execute (was _implement); `.blitz/implement/runs` → `.blitz/execute/runs`
|
|
53
|
+
│ # at line ~68-equivalent usage; KEEP "implemented" stage + prose
|
|
54
|
+
README.md # EDIT: command list, examples, BLITZ_IMPLEMENT_MODEL → BLITZ_EXECUTE_MODEL,
|
|
55
|
+
│ # `.blitz/implement/runs` → `.blitz/execute/runs`
|
|
56
|
+
blitz_cli/playbooks/commands/implement.md # EDIT: `blitz implement … --local-only` → `blitz model execute …`
|
|
57
|
+
blitz_cli/playbooks/commands/tasks.md # EDIT: same CLI-ref update
|
|
58
|
+
blitz_cli/templates/workspace_playbook.md.tmpl # EDIT: same CLI-ref update
|
|
59
|
+
tests/test_implement.py # RENAME → tests/test_execute.py; `_implement` → `_execute`; path updates
|
|
60
|
+
tests/test_cli.py # EDIT/ADD: assert `model execute` wired; `implement` absent
|
|
61
|
+
tests/test_ontology.py # EDIT: `.blitz/implement/runs` → `.blitz/execute/runs` (line ~68); test name optional
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Structure Decision**: Single-project CLI; `model` group follows the `locker-room` nested-subparser pattern. `execute` carries the identical argument set and `func=_cmd_execute`.
|
|
65
|
+
|
|
66
|
+
## Complexity Tracking
|
|
67
|
+
|
|
68
|
+
No playbook violations.
|
|
69
|
+
|
|
70
|
+
## Phases
|
|
71
|
+
|
|
72
|
+
- **Phase 0 (research.md)**: decisions recorded — hard rename (no stub), nested `model` group, full nomenclature purge (breaking), out-of-scope list, playbook-ref updates.
|
|
73
|
+
- **Phase 1 (contracts/, quickstart.md)**: command surface + renamed-identifier table; runnable validation incl. a grep for stray nomenclature. No data-model.md.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Quickstart / Validation: model namespace
|
|
2
|
+
|
|
3
|
+
Prerequisites: editable install of blitz-cli (`pip install -e .`) or run via `python -m blitz_cli`.
|
|
4
|
+
|
|
5
|
+
## Validate the new surface
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
blitz --help # expect: `model` listed; `implement` NOT listed
|
|
9
|
+
blitz model --help # expect: `execute` subcommand listed
|
|
10
|
+
blitz model execute --help # expect: same flags as the old `blitz implement --help`
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Validate the old command is gone
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
blitz implement ; echo "exit=$?" # expect: argparse "invalid choice: 'implement'"; exit != 0
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Validate behavior parity + renamed path/env
|
|
20
|
+
|
|
21
|
+
Run `blitz model execute` against a spec's tasks.md as before; confirm identical driver behavior and that snapshots are written under `.blitz/execute/runs/` (not `.blitz/implement/runs/`). Confirm `BLITZ_EXECUTE_MODEL` selects the model.
|
|
22
|
+
|
|
23
|
+
## No stray nomenclature
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
grep -rnE "blitz implement|BLITZ_IMPLEMENT_MODEL|\.blitz/implement/runs|_cmd_implement|_implement" \
|
|
27
|
+
blitz_cli README.md tests
|
|
28
|
+
# expect: no matches (out-of-scope /implement slash-command & "implemented" stage excluded from this pattern set)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Test suite
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pytest -q # expect: all pass, including renamed tests/test_execute.py
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Contract reference: [contracts/cli-commands.md](./contracts/cli-commands.md).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Research: CLI model namespace (retire "implement")
|
|
2
|
+
|
|
3
|
+
## Decision 1 — Hard rename, no error stub
|
|
4
|
+
|
|
5
|
+
- **Decision**: Delete the `implement` parser entirely. `blitz implement` produces argparse's default "invalid choice" error and non-zero exit.
|
|
6
|
+
- **Rationale**: User explicitly does not want an error stub forwarding to `model execute`. Simplest surface; no dangling "implement" reference.
|
|
7
|
+
- **Alternatives considered**: Error stub naming the replacement — rejected by user.
|
|
8
|
+
|
|
9
|
+
## Decision 2 — `model` group mirrors the `locker-room` pattern
|
|
10
|
+
|
|
11
|
+
- **Decision**: `model = sub.add_parser("model", ...)`; `model_sub = model.add_subparsers(dest="model_cmd", required=True)`; register `execute` under it.
|
|
12
|
+
- **Rationale**: `build_parser()` already uses this nested pattern for `locker-room`; stay consistent and extensible.
|
|
13
|
+
|
|
14
|
+
## Decision 3 — Full nomenclature purge (breaking, no migration)
|
|
15
|
+
|
|
16
|
+
- **Decision**: Rename everything that names this command:
|
|
17
|
+
- env var `BLITZ_IMPLEMENT_MODEL` → `BLITZ_EXECUTE_MODEL`
|
|
18
|
+
- run-snapshot path `.blitz/implement/runs/` → `.blitz/execute/runs/`
|
|
19
|
+
- module `blitz_cli/_implement.py` → `blitz_cli/_execute.py`
|
|
20
|
+
- handler `_cmd_implement` → `_cmd_execute`
|
|
21
|
+
- test file `tests/test_implement.py` → `tests/test_execute.py`
|
|
22
|
+
- all imports/usages in `cli.py`, `_ontology.py`, tests
|
|
23
|
+
- **Rationale**: User wants the "implement" nomenclature gone. These are internal but user-facing (env var, on-disk path).
|
|
24
|
+
- **Consequence**: Existing `.blitz/implement/runs/` snapshots and `BLITZ_IMPLEMENT_MODEL` settings stop working; no migration is provided (accepted by user).
|
|
25
|
+
|
|
26
|
+
## Decision 4 — What is explicitly NOT renamed
|
|
27
|
+
|
|
28
|
+
- The `/implement` playbook SDD slash-command and its `__SPECKIT_COMMAND_IMPLEMENT__` token — a separate lifecycle verb shared across the playbook ecosystem.
|
|
29
|
+
- The `"implemented"` feature lifecycle stage in `_ontology.py` (`_infer_stage`) and its test.
|
|
30
|
+
- Generic English "implementation"/"implementer" prose (docstrings, plan-template title, SYSTEM_PROMPT).
|
|
31
|
+
|
|
32
|
+
## Decision 5 — Rendered playbook CLI references
|
|
33
|
+
|
|
34
|
+
- **Decision**: Update `blitz implement … --local-only` invocations inside `playbooks/commands/implement.md`, `playbooks/commands/tasks.md`, and `templates/workspace_playbook.md.tmpl` to `blitz model execute …`. Do not rename the `/implement` slash-command itself.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Feature Specification: CLI model namespace (retire "implement")
|
|
2
|
+
|
|
3
|
+
**Feature Branch**: `001-cli-model-namespace`
|
|
4
|
+
|
|
5
|
+
**Created**: 2026-07-14
|
|
6
|
+
|
|
7
|
+
**Status**: Draft
|
|
8
|
+
|
|
9
|
+
**Input**: User description: "Update blitz-cli to put the implement command under a 'model' namespace and rename implement to execute (`blitz model execute`). Hard rename with no error stub, and remove the 'implement' nomenclature everywhere it names this command — including the env var, the run-snapshot path, and internal module/handler names."
|
|
10
|
+
|
|
11
|
+
## User Scenarios & Testing *(mandatory)*
|
|
12
|
+
|
|
13
|
+
### User Story 1 - Run the execution flow via the new namespaced command (Priority: P1)
|
|
14
|
+
|
|
15
|
+
A developer who previously ran `blitz implement` now runs `blitz model execute` and gets the identical behavior, flags, and output. The command lives under a new `model` command group so related model-lifecycle commands can be added there later.
|
|
16
|
+
|
|
17
|
+
**Why this priority**: This is the core of the feature.
|
|
18
|
+
|
|
19
|
+
**Independent Test**: Run `blitz model execute` with the arguments previously passed to `blitz implement` and confirm identical behavior. `blitz model --help` lists `execute`; `blitz --help` lists `model` and not `implement`.
|
|
20
|
+
|
|
21
|
+
**Acceptance Scenarios**:
|
|
22
|
+
|
|
23
|
+
1. **Given** a repo where `blitz implement <args>` previously worked, **When** the user runs `blitz model execute <args>`, **Then** the command performs the same work and produces equivalent output/exit code.
|
|
24
|
+
2. **Given** the CLI is installed, **When** the user runs `blitz model --help`, **Then** `execute` appears with the help text formerly shown for `implement`.
|
|
25
|
+
3. **Given** the CLI is installed, **When** the user runs `blitz --help`, **Then** `model` appears and `implement` does not.
|
|
26
|
+
4. **Given** the CLI is installed, **When** the user runs `blitz implement`, **Then** the standard argparse "invalid choice" error is shown and exit is non-zero (no special stub, no forwarding).
|
|
27
|
+
|
|
28
|
+
### Edge Cases
|
|
29
|
+
|
|
30
|
+
- `blitz model` with no subcommand: prints the `model` group help and exits non-zero (subparser required).
|
|
31
|
+
- All flags/positional arguments previously accepted by `implement` are accepted unchanged by `execute`.
|
|
32
|
+
- The model-selection env var is now `BLITZ_EXECUTE_MODEL`; the old `BLITZ_IMPLEMENT_MODEL` is no longer read (breaking change, accepted).
|
|
33
|
+
- Run snapshots are now written under `.blitz/execute/runs/`; the old `.blitz/implement/runs/` path is no longer read or written (breaking change, accepted — no migration).
|
|
34
|
+
|
|
35
|
+
## Requirements *(mandatory)*
|
|
36
|
+
|
|
37
|
+
### Functional Requirements
|
|
38
|
+
|
|
39
|
+
- **FR-001**: The CLI MUST expose a `model` command group at the top level.
|
|
40
|
+
- **FR-002**: The CLI MUST provide `model execute` performing exactly the behavior of the former top-level `implement` command, with identical flags, positional arguments, defaults, and exit codes.
|
|
41
|
+
- **FR-003**: The CLI MUST NOT expose a top-level `implement` command in any form (no working command and no special error stub); invoking `blitz implement` yields the default argparse invalid-choice failure.
|
|
42
|
+
- **FR-004**: Help output MUST reflect the new structure: `model` at top level, `execute` under `model`, no `implement` anywhere.
|
|
43
|
+
- **FR-005**: README and any in-repo documentation or rendered playbook command text referencing the `blitz implement` CLI invocation MUST be updated to `blitz model execute`.
|
|
44
|
+
- **FR-006**: The "implement" nomenclature naming THIS command MUST be removed from the code: the env var `BLITZ_IMPLEMENT_MODEL` becomes `BLITZ_EXECUTE_MODEL`; the run-snapshot path `.blitz/implement/runs/` becomes `.blitz/execute/runs/`; the module `_implement.py` becomes `_execute.py`; the handler `_cmd_implement` becomes `_cmd_execute`; all imports/references update accordingly.
|
|
45
|
+
- **FR-007**: The existing test suite MUST be updated to the new command, env var, path, and module names (including renaming `tests/test_implement.py` to `tests/test_execute.py`), and a test MUST assert `blitz model execute` is wired and no top-level `implement` command exists.
|
|
46
|
+
|
|
47
|
+
**Out of scope (NOT renamed)**: the separate `/implement` playbook SDD lifecycle slash-command and its `__SPECKIT_COMMAND_IMPLEMENT__` token; the "implemented" feature lifecycle stage in `_ontology.py`; generic English "implementation" prose. These are distinct from the `blitz implement` CLI command.
|
|
48
|
+
|
|
49
|
+
### Key Entities
|
|
50
|
+
|
|
51
|
+
- **`model` command group**: A namespace for model-lifecycle commands; currently holds `execute`.
|
|
52
|
+
- **`execute` subcommand**: The relocated, renamed former `implement` command; unchanged behavior.
|
|
53
|
+
|
|
54
|
+
## Success Criteria *(mandatory)*
|
|
55
|
+
|
|
56
|
+
### Measurable Outcomes
|
|
57
|
+
|
|
58
|
+
- **SC-001**: 100% of the behavior/flags previously under `blitz implement` are available under `blitz model execute`.
|
|
59
|
+
- **SC-002**: `blitz implement` no longer runs anything; it exits non-zero with the standard invalid-choice error.
|
|
60
|
+
- **SC-003**: No occurrence of the strings `blitz implement`, `BLITZ_IMPLEMENT_MODEL`, `.blitz/implement/runs`, `_implement`, or `_cmd_implement` remains in `blitz_cli/`, `README.md`, `tests/`, or rendered playbook CLI references (verifiable by search). Matches limited to the out-of-scope items above are acceptable.
|
|
61
|
+
- **SC-004**: The full test suite passes after the rename.
|
|
62
|
+
|
|
63
|
+
## Assumptions
|
|
64
|
+
|
|
65
|
+
- Hard rename confirmed: no alias, no error stub. `blitz implement` simply ceases to exist as a choice.
|
|
66
|
+
- Full nomenclature purge confirmed for env var, run-snapshot path, and internal module/handler names — breaking, with no migration of existing `.blitz/implement/runs/` snapshots or `BLITZ_IMPLEMENT_MODEL` settings.
|
|
67
|
+
- The `_execute` engine behavior (task driving, retries, snapshots) is otherwise reused unchanged; only names and the snapshot directory change.
|
|
68
|
+
- `homebrew-tap` and other repos are unaffected (they package the binary, not subcommands).
|
|
69
|
+
- The `/implement` playbook SDD command and the `"implemented"` lifecycle stage are explicitly out of scope.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Task list for CLI model namespace (retire 'implement')"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tasks: CLI model namespace (retire "implement")
|
|
6
|
+
|
|
7
|
+
**Input**: Design documents from `specs/001-cli-model-namespace/`
|
|
8
|
+
|
|
9
|
+
**Prerequisites**: plan.md, spec.md, research.md, contracts/cli-commands.md, quickstart.md
|
|
10
|
+
|
|
11
|
+
**Tests**: Included — FR-007 requires migrating/renaming the suite.
|
|
12
|
+
|
|
13
|
+
**Organization**: Single user story (US1) — the new `model execute` surface plus the full nomenclature purge. No error-stub story.
|
|
14
|
+
|
|
15
|
+
## Format: `[ID] [P?] [L?] [US1] Description`
|
|
16
|
+
|
|
17
|
+
- **[P]**: parallelizable (different file)
|
|
18
|
+
- **[L]**: local-model eligible (shell command verified by exit code)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Phase 1: Setup
|
|
23
|
+
|
|
24
|
+
- [X] T001 [L] Baseline green: `cd /home/ike/companies/sparepartslabs/blitz-dev-tools/blitz-cli && pip install -e . >/dev/null 2>&1 && pytest -q`. Expected: passes before changes.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Phase 2: User Story 1 — `blitz model execute` + retire "implement" (P1) 🎯 MVP
|
|
29
|
+
|
|
30
|
+
**Goal**: `blitz model execute` replaces `blitz implement` with identical behavior; the "implement" nomenclature naming this command is gone from code, env var, run path, and tests. `blitz implement` is an invalid choice.
|
|
31
|
+
|
|
32
|
+
**Independent Test**: quickstart.md — help output correct, `blitz implement` errors, snapshots land under `.blitz/execute/runs/`, grep finds no stray nomenclature, `pytest` passes.
|
|
33
|
+
|
|
34
|
+
### Engine module rename
|
|
35
|
+
|
|
36
|
+
- [X] T002 [L] [US1] Rename the engine module: `cd /home/ike/companies/sparepartslabs/blitz-dev-tools/blitz-cli && git mv blitz_cli/_implement.py blitz_cli/_execute.py` (use `mv` if not tracked). Expected: exit 0.
|
|
37
|
+
- [X] T003 [US1] In `blitz_cli/_execute.py`, update the run-snapshot path from `.blitz/implement/runs` to `.blitz/execute/runs` at every occurrence (currently the docstring ~L240-241, the glob `.blitz/implement/runs/*/usage.json` ~L245, and `repo / ".blitz" / "implement" / "runs"` ~L292), and update the module docstring's `implement` playbook reference to `execute`. Do NOT change the `SYSTEM_PROMPT` "code implementer" prose.
|
|
38
|
+
|
|
39
|
+
### CLI wiring
|
|
40
|
+
|
|
41
|
+
- [X] T004 [US1] In `blitz_cli/cli.py`, rename handler `def _cmd_implement(args)` → `def _cmd_execute(args)`; change its `from blitz_cli import _implement` to `from blitz_cli import _execute` and update all `_implement.` references in the function body to `_execute.` (find_tasks_file, local_model_config, DEFAULT_MODEL, run); change the env read `os.environ.get("BLITZ_IMPLEMENT_MODEL")` → `os.environ.get("BLITZ_EXECUTE_MODEL")` and the adjacent comment.
|
|
42
|
+
- [X] T005 [US1] In `blitz_cli/cli.py` `build_parser()`, replace the whole top-level `impl = sub.add_parser("implement", ...)` block (through `impl.set_defaults(func=_cmd_implement)`, ~L293-334) with: `model = sub.add_parser("model", help="Model lifecycle commands.")`; `model_sub = model.add_subparsers(dest="model_cmd", required=True)`; `execute = model_sub.add_parser("execute", help=...)` re-attaching the identical arguments (`tasks`, `--repo`, `--model`, `--local-only`, `--ollama-url`, `--max-retries`, `--start-at`) verbatim; update the `--model` help text `BLITZ_IMPLEMENT_MODEL` → `BLITZ_EXECUTE_MODEL` and `snapshots under .blitz/implement/runs/` → `.blitz/execute/runs/`; end with `execute.set_defaults(func=_cmd_execute)`. Follow the `locker-room` nested pattern. No `implement` parser remains.
|
|
43
|
+
|
|
44
|
+
### Ontology reference
|
|
45
|
+
|
|
46
|
+
- [X] T006 [US1] In `blitz_cli/_ontology.py`, change `from blitz_cli import _activity, _implement, _playbooks` → `... _execute ...` and update every `_implement.` usage (~L355 parse_tasks, ~L530 usage_by_spec) to `_execute.`. KEEP the `"implemented"` return in `_infer_stage` (~L366) and the "the implement" comment's meaning — those are the lifecycle stage, not the CLI command. If `_ontology.py` builds any `.blitz/implement/runs` path, change it to `.blitz/execute/runs`.
|
|
47
|
+
|
|
48
|
+
### Docs & rendered playbook refs
|
|
49
|
+
|
|
50
|
+
- [X] T007 [P] [US1] Update `README.md`: "Top-level commands" line (~L15) list `model` not `implement`; the `## Implement:` section heading and body (~L35-50) → `blitz model execute` usage; `BLITZ_IMPLEMENT_MODEL` (~L55) → `BLITZ_EXECUTE_MODEL`; `.blitz/implement/runs/` (~L45) → `.blitz/execute/runs/`.
|
|
51
|
+
- [X] T008 [P] [US1] Update rendered playbook CLI refs to `blitz model execute … --local-only`: `blitz_cli/playbooks/commands/implement.md` (~L154, L158, L162), `blitz_cli/playbooks/commands/tasks.md` (~L209, L243), `blitz_cli/templates/workspace_playbook.md.tmpl` (~L24-25). Do NOT rename the `/implement` slash-command, its filename, or `agent: implement` frontmatter.
|
|
52
|
+
|
|
53
|
+
### Tests
|
|
54
|
+
|
|
55
|
+
- [X] T009 [US1] Rename `tests/test_implement.py` → `tests/test_execute.py` (`git mv`), change `from blitz_cli import _implement` → `_execute` and every `_implement.` → `_execute.`, and update the `.blitz/implement/runs` path (~L233) → `.blitz/execute/runs`.
|
|
56
|
+
- [X] T010 [US1] In `tests/test_ontology.py`, update the run dir `.blitz/implement/runs` (~L68) → `.blitz/execute/runs`. Keep the `"implemented"` stage assertions (~L49) unchanged; the test name `test_feature_node_carries_implement_usage` may be left or renamed to `..._execute_usage` (cosmetic).
|
|
57
|
+
- [X] T011 [P] [US1] In `tests/test_cli.py`, add tests: (a) `build_parser().parse_args(["model","execute"])` resolves `func == _cmd_execute`; (b) parsing `["implement"]` raises `SystemExit` (invalid choice); (c) `model` is present and `implement` absent in the top-level choices.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Phase 3: Verification
|
|
62
|
+
|
|
63
|
+
- [X] T012 [L] Run the suite: `cd /home/ike/companies/sparepartslabs/blitz-dev-tools/blitz-cli && pytest -q`. Expected: all pass.
|
|
64
|
+
- [X] T013 [L] No stray nomenclature: `cd /home/ike/companies/sparepartslabs/blitz-dev-tools/blitz-cli && ! grep -rnE "blitz implement|BLITZ_IMPLEMENT_MODEL|\.blitz/implement/runs|_cmd_implement|_implement" blitz_cli README.md tests`. Expected: exit 0 (no matches).
|
|
65
|
+
- [X] T014 [L] Surface check per quickstart.md: `blitz --help`, `blitz model --help`, `blitz model execute --help`, `blitz implement; echo exit=$?`. Confirm `model`/`execute` present, `implement` invalid.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Dependencies
|
|
70
|
+
|
|
71
|
+
- T001 → all.
|
|
72
|
+
- T002 (module move) → T003, T004, T006, T009 (they reference `_execute`).
|
|
73
|
+
- T004 → T005 (handler must exist before `set_defaults(func=_cmd_execute)`), same file `cli.py`, sequential.
|
|
74
|
+
- T007, T008, T011 [P] — independent files.
|
|
75
|
+
- T012-T014 last (after all edits).
|
|
76
|
+
|
|
77
|
+
## Parallel opportunities
|
|
78
|
+
|
|
79
|
+
- T007, T008 (docs/templates) and T011 (test_cli.py) run in parallel once code edits land.
|
|
80
|
+
|
|
81
|
+
## MVP scope
|
|
82
|
+
|
|
83
|
+
All of US1 is the deliverable; there is no separate secondary story.
|
|
@@ -43,6 +43,25 @@ def test_locker_room_make_verbs_resolve_to_the_make_passthrough():
|
|
|
43
43
|
assert logs.run_dir == "./x"
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def test_model_execute_resolves():
|
|
47
|
+
args = cli.build_parser().parse_args(["model", "execute", "specs/001/tasks.md"])
|
|
48
|
+
assert args.func is cli._cmd_execute
|
|
49
|
+
assert args.tasks == "specs/001/tasks.md"
|
|
50
|
+
assert args.max_retries == 2
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_old_implement_command_is_gone():
|
|
54
|
+
import pytest
|
|
55
|
+
with pytest.raises(SystemExit):
|
|
56
|
+
cli.build_parser().parse_args(["implement"])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_model_group_requires_subcommand():
|
|
60
|
+
import pytest
|
|
61
|
+
with pytest.raises(SystemExit):
|
|
62
|
+
cli.build_parser().parse_args(["model"])
|
|
63
|
+
|
|
64
|
+
|
|
46
65
|
def test_runtime_commands_are_not_in_the_cli():
|
|
47
66
|
# The node runs watch/ontologize/mcp; the CLI must not expose them.
|
|
48
67
|
parser = cli.build_parser()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
|
-
from blitz_cli import
|
|
3
|
+
from blitz_cli import _execute
|
|
4
4
|
|
|
5
5
|
TASKS_MD = """\
|
|
6
6
|
# Tasks: Example
|
|
@@ -33,7 +33,7 @@ def _write_tasks(tmp_path):
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
def test_parse_tasks_ids_done_phases_and_verify():
|
|
36
|
-
tasks, verify =
|
|
36
|
+
tasks, verify = _execute.parse_tasks(TASKS_MD)
|
|
37
37
|
assert [t["id"] for t in tasks] == ["T001", "T002", "T003", "T004"]
|
|
38
38
|
assert [t["done"] for t in tasks] == [False, True, False, False]
|
|
39
39
|
assert [t["phase"] for t in tasks] == [1, 1, 2, 2]
|
|
@@ -48,7 +48,7 @@ def test_parse_actions_orders_writes_and_runs():
|
|
|
48
48
|
"===RUN===\n```\nmkdir -p tests\n```\n"
|
|
49
49
|
"===WRITE src/mod.py===\n```python\nX = 1\n```\n"
|
|
50
50
|
)
|
|
51
|
-
actions =
|
|
51
|
+
actions = _execute.parse_actions(reply)
|
|
52
52
|
assert actions == [("run", "mkdir -p tests", None), ("write", "src/mod.py", "X = 1")]
|
|
53
53
|
|
|
54
54
|
|
|
@@ -59,14 +59,14 @@ def test_apply_actions_writes_snapshots_and_rejects_escape(tmp_path):
|
|
|
59
59
|
snap.mkdir()
|
|
60
60
|
(repo / "a.txt").write_text("old\n")
|
|
61
61
|
|
|
62
|
-
ok, err =
|
|
62
|
+
ok, err = _execute.apply_actions(
|
|
63
63
|
repo, [("write", "a.txt", "new")], snap, "T001", 0, print_fn=lambda *_: None
|
|
64
64
|
)
|
|
65
65
|
assert ok, err
|
|
66
66
|
assert (repo / "a.txt").read_text() == "new\n"
|
|
67
67
|
assert (snap / "T001.a0.a.txt").read_text() == "old\n"
|
|
68
68
|
|
|
69
|
-
ok, err =
|
|
69
|
+
ok, err = _execute.apply_actions(
|
|
70
70
|
repo, [("write", "../evil.txt", "x")], snap, "T001", 0, print_fn=lambda *_: None
|
|
71
71
|
)
|
|
72
72
|
assert not ok and "escapes the repo" in err
|
|
@@ -74,14 +74,14 @@ def test_apply_actions_writes_snapshots_and_rejects_escape(tmp_path):
|
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
def test_apply_actions_reports_failed_command(tmp_path):
|
|
77
|
-
ok, err =
|
|
77
|
+
ok, err = _execute.apply_actions(
|
|
78
78
|
tmp_path, [("run", "exit 3", None)], tmp_path, "T001", 0, print_fn=lambda *_: None
|
|
79
79
|
)
|
|
80
80
|
assert not ok and "exit 3" in err
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
def test_apply_actions_empty_reply_is_an_error(tmp_path):
|
|
84
|
-
ok, err =
|
|
84
|
+
ok, err = _execute.apply_actions(
|
|
85
85
|
tmp_path, [], tmp_path, "T001", 0, print_fn=lambda *_: None
|
|
86
86
|
)
|
|
87
87
|
assert not ok and "No action blocks" in err
|
|
@@ -89,7 +89,7 @@ def test_apply_actions_empty_reply_is_an_error(tmp_path):
|
|
|
89
89
|
|
|
90
90
|
def test_mark_done_checks_exactly_one_box(tmp_path):
|
|
91
91
|
f = _write_tasks(tmp_path)
|
|
92
|
-
|
|
92
|
+
_execute.mark_done(f, "T001")
|
|
93
93
|
text = f.read_text()
|
|
94
94
|
assert "- [x] T001 " in text
|
|
95
95
|
assert "- [ ] T003 " in text
|
|
@@ -98,7 +98,7 @@ def test_mark_done_checks_exactly_one_box(tmp_path):
|
|
|
98
98
|
def test_gather_context_inlines_referenced_files(tmp_path):
|
|
99
99
|
(tmp_path / "src").mkdir()
|
|
100
100
|
(tmp_path / "src" / "mod.py").write_text("X = 1\n")
|
|
101
|
-
ctx =
|
|
101
|
+
ctx = _execute.gather_context(tmp_path, "EDIT `src/mod.py` and `src/missing.py`.")
|
|
102
102
|
assert "current contents of src/mod.py" in ctx
|
|
103
103
|
assert "1\tX = 1" in ctx
|
|
104
104
|
assert "missing.py" not in ctx
|
|
@@ -111,10 +111,10 @@ def test_find_tasks_file_unique_incomplete(tmp_path):
|
|
|
111
111
|
open_.mkdir(parents=True)
|
|
112
112
|
done.joinpath("tasks.md").write_text("- [x] T001 done\n")
|
|
113
113
|
open_.joinpath("tasks.md").write_text("- [ ] T001 todo\n")
|
|
114
|
-
assert
|
|
114
|
+
assert _execute.find_tasks_file(tmp_path) == open_ / "tasks.md"
|
|
115
115
|
# Two incomplete lists -> ambiguous -> None.
|
|
116
116
|
done.joinpath("tasks.md").write_text("- [ ] T001 todo\n")
|
|
117
|
-
assert
|
|
117
|
+
assert _execute.find_tasks_file(tmp_path) is None
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
def test_run_end_to_end_with_fake_model(tmp_path):
|
|
@@ -131,7 +131,7 @@ def test_run_end_to_end_with_fake_model(tmp_path):
|
|
|
131
131
|
return replies[tid]
|
|
132
132
|
|
|
133
133
|
logs = []
|
|
134
|
-
rc =
|
|
134
|
+
rc = _execute.run(
|
|
135
135
|
repo=repo, tasks_file=tasks_file, call_model=fake_model,
|
|
136
136
|
run_root=tmp_path / "runs", print_fn=logs.append,
|
|
137
137
|
)
|
|
@@ -148,7 +148,7 @@ def test_run_end_to_end_with_fake_model(tmp_path):
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
def test_parse_tasks_local_marker():
|
|
151
|
-
tasks, _ =
|
|
151
|
+
tasks, _ = _execute.parse_tasks(
|
|
152
152
|
"## Phase 1: x\n\n"
|
|
153
153
|
"- [ ] T001 [P] [L] CREATE a file.\n"
|
|
154
154
|
"- [ ] T002 [L] [US1] Run `true`.\n"
|
|
@@ -169,14 +169,14 @@ def test_local_model_config_walks_up_to_workspace(tmp_path):
|
|
|
169
169
|
json.dumps({"local_model": {"model": "ws-model"}})
|
|
170
170
|
)
|
|
171
171
|
# No repo-level config -> workspace config wins.
|
|
172
|
-
assert
|
|
172
|
+
assert _execute.local_model_config(repo) == {"model": "ws-model"}
|
|
173
173
|
# Repo-level config takes precedence.
|
|
174
174
|
(repo / ".blitz" / "config.json").write_text(
|
|
175
175
|
json.dumps({"local_model": {"model": "repo-model"}})
|
|
176
176
|
)
|
|
177
|
-
assert
|
|
177
|
+
assert _execute.local_model_config(repo) == {"model": "repo-model"}
|
|
178
178
|
# Nothing configured anywhere -> {}.
|
|
179
|
-
assert
|
|
179
|
+
assert _execute.local_model_config(tmp_path) == {}
|
|
180
180
|
|
|
181
181
|
|
|
182
182
|
def test_run_local_only_stops_at_first_frontier_task(tmp_path):
|
|
@@ -196,7 +196,7 @@ def test_run_local_only_stops_at_first_frontier_task(tmp_path):
|
|
|
196
196
|
return "===RUN===\n```\ntrue\n```"
|
|
197
197
|
|
|
198
198
|
logs = []
|
|
199
|
-
rc =
|
|
199
|
+
rc = _execute.run(
|
|
200
200
|
repo=repo, tasks_file=tasks_file, call_model=fake_model,
|
|
201
201
|
local_only=True, run_root=tmp_path / "runs", print_fn=logs.append,
|
|
202
202
|
)
|
|
@@ -212,7 +212,7 @@ def test_run_local_only_warns_when_no_markers(tmp_path):
|
|
|
212
212
|
tasks_file = tmp_path / "tasks.md"
|
|
213
213
|
tasks_file.write_text("- [ ] T001 Do a thing.\n")
|
|
214
214
|
logs = []
|
|
215
|
-
rc =
|
|
215
|
+
rc = _execute.run(
|
|
216
216
|
repo=tmp_path, tasks_file=tasks_file, call_model=lambda m: "",
|
|
217
217
|
local_only=True, run_root=tmp_path / "runs", print_fn=logs.append,
|
|
218
218
|
)
|
|
@@ -222,15 +222,15 @@ def test_run_local_only_warns_when_no_markers(tmp_path):
|
|
|
222
222
|
|
|
223
223
|
def test_spec_name_from_specs_layout(tmp_path):
|
|
224
224
|
tasks = tmp_path / "specs" / "001-my-feature" / "tasks.md"
|
|
225
|
-
assert
|
|
225
|
+
assert _execute.spec_name(tmp_path, tasks) == "001-my-feature"
|
|
226
226
|
other = tmp_path / "docs" / "tasks.md"
|
|
227
|
-
assert
|
|
227
|
+
assert _execute.spec_name(tmp_path, other) == "docs/tasks.md"
|
|
228
228
|
|
|
229
229
|
|
|
230
230
|
def test_usage_by_spec_aggregates_runs(tmp_path):
|
|
231
231
|
import json
|
|
232
232
|
|
|
233
|
-
runs = tmp_path / ".blitz" / "
|
|
233
|
+
runs = tmp_path / ".blitz" / "execute" / "runs"
|
|
234
234
|
for stamp, out in (("20260714-1", 100), ("20260714-2", 50)):
|
|
235
235
|
d = runs / stamp
|
|
236
236
|
d.mkdir(parents=True)
|
|
@@ -241,7 +241,7 @@ def test_usage_by_spec_aggregates_runs(tmp_path):
|
|
|
241
241
|
(runs / "broken").mkdir()
|
|
242
242
|
(runs / "broken" / "usage.json").write_text("not json")
|
|
243
243
|
|
|
244
|
-
agg =
|
|
244
|
+
agg = _execute.usage_by_spec(tmp_path)
|
|
245
245
|
assert agg == {"001-a": {
|
|
246
246
|
"input": 2000, "output": 150, "calls": 6, "runs": 2,
|
|
247
247
|
"models": ["qwen2.5-14b-28k"],
|
|
@@ -264,7 +264,7 @@ def test_run_records_token_usage(tmp_path):
|
|
|
264
264
|
return replies[tid], {"input": 100, "output": 10}
|
|
265
265
|
|
|
266
266
|
logs = []
|
|
267
|
-
rc =
|
|
267
|
+
rc = _execute.run(
|
|
268
268
|
repo=repo, tasks_file=tasks_file, call_model=fake_model,
|
|
269
269
|
run_root=tmp_path / "runs", print_fn=logs.append,
|
|
270
270
|
)
|
|
@@ -272,7 +272,7 @@ def test_run_records_token_usage(tmp_path):
|
|
|
272
272
|
rundir = next((tmp_path / "runs").iterdir())
|
|
273
273
|
usage = json.loads((rundir / "usage.json").read_text())
|
|
274
274
|
assert usage["spec"] == str(tasks_file.relative_to(repo)) # not under specs/
|
|
275
|
-
assert usage["model"] ==
|
|
275
|
+
assert usage["model"] == _execute.DEFAULT_MODEL
|
|
276
276
|
assert usage["tasks"]["T001"] == {"input": 100, "output": 10, "calls": 1}
|
|
277
277
|
assert usage["total"] == {"input": 200, "output": 20, "calls": 2}
|
|
278
278
|
assert any("T001: DONE (100 in / 10 out tokens)" in ln for ln in logs)
|
|
@@ -286,7 +286,7 @@ def test_run_flushes_usage_on_failure(tmp_path):
|
|
|
286
286
|
tasks_file = repo / "tasks.md"
|
|
287
287
|
tasks_file.write_text("## Phase 1: x\n\n- [ ] T001 Run `false`.\n")
|
|
288
288
|
|
|
289
|
-
rc =
|
|
289
|
+
rc = _execute.run(
|
|
290
290
|
repo=repo, tasks_file=tasks_file,
|
|
291
291
|
call_model=lambda m: ("===RUN===\n```\nexit 7\n```", {"input": 50, "output": 5}),
|
|
292
292
|
max_retries=1, run_root=tmp_path / "runs", print_fn=lambda *_: None,
|
|
@@ -308,7 +308,7 @@ def test_run_retries_with_error_feedback_then_stops(tmp_path):
|
|
|
308
308
|
calls.append(messages)
|
|
309
309
|
return "===RUN===\n```\nexit 7\n```"
|
|
310
310
|
|
|
311
|
-
rc =
|
|
311
|
+
rc = _execute.run(
|
|
312
312
|
repo=repo, tasks_file=tasks_file, call_model=failing_model,
|
|
313
313
|
max_retries=1, run_root=tmp_path / "runs", print_fn=lambda *_: None,
|
|
314
314
|
)
|
|
@@ -327,7 +327,7 @@ def test_run_phase_verify_failure_fails_last_task(tmp_path):
|
|
|
327
327
|
"**Phase 1 verification**: `test -f produced.txt` succeeds.\n"
|
|
328
328
|
)
|
|
329
329
|
|
|
330
|
-
rc =
|
|
330
|
+
rc = _execute.run(
|
|
331
331
|
repo=repo, tasks_file=tasks_file,
|
|
332
332
|
call_model=lambda m: "===RUN===\n```\ntrue\n```",
|
|
333
333
|
max_retries=0, run_root=tmp_path / "runs", print_fn=lambda *_: None,
|
|
@@ -62,10 +62,10 @@ def test_playbook_nodes_carry_command_docs(workspace):
|
|
|
62
62
|
assert docs["playbook"].strip()
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def
|
|
65
|
+
def test_feature_node_carries_execute_usage(tmp_path):
|
|
66
66
|
ws = tmp_path / "ws"
|
|
67
67
|
repo = _make_repo(ws, "api", specs={"001-endpoint": {"spec.md": "# s", "tasks.md": "# t"}})
|
|
68
|
-
rundir = repo / ".blitz" / "
|
|
68
|
+
rundir = repo / ".blitz" / "execute" / "runs" / "20260714-120000"
|
|
69
69
|
rundir.mkdir(parents=True)
|
|
70
70
|
(rundir / "usage.json").write_text(json.dumps({
|
|
71
71
|
"spec": "001-endpoint", "model": "qwen2.5-14b-28k",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/memory/playbook.md
RENAMED
|
File without changes
|
|
File without changes
|
{blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/common.sh
RENAMED
|
File without changes
|
|
File without changes
|
{blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/scripts/bash/setup-plan.sh
RENAMED
|
File without changes
|
|
File without changes
|
{blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/templates/plan-template.md
RENAMED
|
File without changes
|
{blitz_cli-0.10.0 → blitz_cli-0.11.0}/blitz_cli/playbooks/scaffold/.blitz/templates/spec-template.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|