101c8ec2e7
Dockerfile: SHELL [/bin/bash] before Swift layer — fixes ${var//pattern} bash-ism that dash chokes on
2026-04-29 17:16:43 +00:00
4eab869df0
v0.1 wave 3 (steps 9+10): autonomous patch loop + production recipes
...
Step 9 — autonomous patch loop:
- patcher.py: clawdforge session → unified diff → worktree apply → verify recipe → push branch → open Gitea PR
- migration 007: patch_attempts (UNIQUE per finding+attempt, max 3 attempts)
- runner.py: post-parse hook fires patcher.maybe_draft_for_job when notify.auto_patch=true
- server.py: POST /jobs/{id}/patches, GET /patches, GET /patches/{id}
- digest.py: patch-drafted lines + open-follow-up count via Gitea PR state check
- mcp: crafting_table_draft_patch stub replaced with real implementation
- tests/test_patcher.py + tests/test_patches_api.py: 27 new tests
No auto-merge — patches stop at PR-open. Cobb merges.
Step 10 — production recipes:
- examples/recipes/clawdforge.json: 14 subprojects across all SDKs, audit nightly
- examples/recipes/cauldron.json: single Flask subproject, audit nightly
- examples/recipes/tradecraft.json: nightly audit, auto_patch=false (manual review)
- examples/register-all.sh: bulk-register helper with GITEA_TOKEN substitution
- README "Autonomous patch loop" + "First production recipes" sections
Tests: server 116→143, mcp 65→67. All green.
Spec: memory/spec-crafting-table.md
2026-04-29 09:04:48 -07:00
ecb9d76e6d
v0.1 wave 2B (step 7): MCP server — stdio JSON-RPC, 8 tools
...
- mcp/ subpackage: crafting-table-mcp (separate pip install)
- Self-contained requests-based HTTP client (mirrors clawdforge_mcp pattern)
- 8 tools: list_projects / register_project / run_audit / run_build / run_test / get_job / get_findings / draft_patch (stub)
- draft_patch is stubbed — full impl lands in wave 3 / step 9
- tests/: client + tool coverage, 401/404 surfacing
- Tools designed for LLM consumption; descriptions tuned for "when to use" guidance
Spec: memory/spec-crafting-table.md
2026-04-29 08:38:29 -07:00
d467b2f5be
v0.1 wave 2A (steps 5+6): per-language parsers + findings extraction
...
- parsers/ package: rust / python / go / typescript / generic
- parser registry with language+recipe -> fallback resolution
- fingerprint hash (kind+file+line+code) for cross-run dedup
- runner.py post-exec hook: parse log, persist findings, count on job row
(extraction runs before mark_job_finished so callers polling on terminal
status see findings_count populated atomically)
- db.insert_finding / list_findings / increment_findings_count DAOs already
shipped in wave 1; wired here
- GET /jobs/{id}/findings now returns real data (server route already
shipped; was returning empty list because nothing populated the table)
- tests/test_parsers/: 6 modules + 11 fixtures (rust/python/go/typescript)
- tests/test_runner_findings.py: 3 integration tests
- README: tick steps 2-6, add Findings section
Suite: 108 passing (62 wave-1 + 46 new).
Spec: memory/spec-crafting-table.md
2026-04-29 08:36:16 -07:00
98306ca2e0
v0.1 wave 2C (step 8): email digest scheduler
...
- digest.py: DigestScheduler with daily 06:00 PT loop
- SmtpConfig env-driven (CRAFTING_SMTP_*)
- notify.on event filter respected per project
- GET /digests/{date} + POST /admin/digest/run-now (dry_run flag)
- migration 006: digest_runs (idempotency via UNIQUE(date, project_name))
- text + HTML email bodies; matches spec's worked example
- Server lifespan integration; gracefully disables if SMTP not configured
- tests/test_digest.py: 8 tests (aggregation / filter / smtp mock / idempotency / endpoint)
Patch-drafted line is a placeholder until wave 3 / step 9 ships.
Spec: memory/spec-crafting-table.md
2026-04-29 08:33:37 -07:00
2e16ec886d
wave 1 wiring: Dockerfile API stage + compose API command + README quickstart
...
- Dockerfile: pip-install requirements.txt and copy crafting_table/ into
/app, switch CMD from /bin/bash to uvicorn server (port 8810). pip lands
in /usr/local/bin so the crafter user runs uvicorn without elevation.
- compose.yml: replace smoke.sh entrypoint with the API server command;
bind 192.168.0.5:8810:8810 (LAN-only); switch named volumes to real
Lucy appdata paths so /data + /workspace + /caches survive recreate.
env_file marked optional so a fresh checkout boots without copying
.env.example.
- README.md: tick steps 1-4 done, document API surface table, add
curl-based quickstart (mint token → register project → kick off job →
poll → stream log), and an architecture-notes section covering the
recipe-immutability snapshot, process-group SIGTERM/SIGKILL escalation,
WAL+single-writer trade-off, and the recipe-security stance.
Smoke remains runnable on demand:
docker compose run --rm crafting-table /usr/local/bin/smoke.sh
2026-04-29 08:28:51 -07:00
0ec3a04676
v0.1 wave 1 (steps 2+3+4): SQLite ledger + FastAPI skeleton + async job runner
...
- db.py: migrations + DAOs for tokens / projects / jobs / findings (SQLite WAL)
- auth.py: SHA-256 bearer hashing + LAN-CIDR allowlist + admin/app token tiers
- models.py: Pydantic shapes (Project, Subproject, Schedule, Notify, Job, CreateJobRequest)
- server.py: FastAPI on port 8810; /healthz, /admin/tokens/*, /projects/*, /jobs, /jobs/{id}, /jobs/{id}/log, /jobs/{id}/findings
- runner.py: bounded asyncio pool, per-job timeout with process-group SIGTERM→SIGKILL escalation, orphaned-job recovery on boot
- workspace.py: bare-clone + worktree materialization, gc
- config.py: env-driven
- 62 tests across db / auth / projects / jobs / runner / e2e — all green
Cross-token project access returns 404 (not 403) — existence-leak guard.
Bearer tokens hashed at rest; admin token bootstrapped on first boot.
Recipe subprocess uses start_new_session=True so killpg targets the
whole process tree on timeout — child processes can't escape SIGKILL.
Pump task guarded with wait_for(2s) + cancel fallback against any
orphan that survives the group kill.
Wave 2 (parsers + findings extraction + MCP + email digest) pending.
Spec: memory/spec-crafting-table.md
2026-04-29 08:17:41 -07:00
4e668a79e1
v0.1 step 1: Dockerfile + per-language toolchain smoke
...
Monolith image with every toolchain in the spec:
- Python 3.12 + uv/ruff/mypy/pytest/pip-audit/semgrep
- Node 22 LTS + bun
- Go 1.22 + govulncheck/staticcheck
- Rust stable + cargo-audit/cargo-deny
- Ruby 3.x + bundler-audit
- PHP 8.x + composer/phpstan
- JDK 17 + 21 + Maven + Gradle
- .NET 8 SDK
- Swift 5.9.2
- Kotlin 1.9.25
- clang + cmake + valgrind + ASan/UBSan/TSan
- bash + shellcheck
smoke.sh proves each toolchain compiles + runs a hello-world.
compose.yml uses the existing 'sulkta' bridge network.
No API yet (steps 2-3); no MCP yet (step 7); no runner yet (step 4).
This is the foundation.
NOTE: docker build + smoke verification not yet run — sandbox doesn't
have docker. Needs `docker compose build && docker compose up` on Lucy
or any real Docker host before we trust the Dockerfile.
Spec: memory/spec-crafting-table.md
2026-04-29 07:29:53 -07:00
5bd1b1de7e
Initial commit
2026-04-29 07:22:04 -07:00