takana: etapa 2 del renombre + los dos puntos de la hoja de marca

Etapa 2 (ADR 0016): el binario canónico es `takana` y `hammer` se sigue
emitiendo. Son DOS [[bin]] al mismo main.rs, no un symlink: la siembra de la
granja excluye /target (un symlink del hub no existiría en el worker) y
`cargo clean` lo borraría. Ningún llamador tocado; los 124 siguen andando.

Adoptados los dos puntos de la hoja de marca que chocaban con contratos:

- `forja` como ALIAS de clap sobre `build`, no como reemplazo. El canónico
  sigue siendo el inglés, que es lo que usan scripts, cron y runbooks. Y se
  enmienda la regla 4 de CLAUDE.md en el mismo commit: cambiar el
  comportamiento dejando escrito el contrato viejo es lo peor de las dos
  opciones, porque el otro agente del repo aplica lo que lee.

- `.tkn` como extensión de paquete. Salió barato y por una razón medida: la
  extensión no es lógica sino salida — se escribe en UN solo lugar
  (main.rs:1800) y el descubrimiento va por índice, no por glob
  (PackageEntry.file, repo.rs:75). Los repos con entradas .swm siguen
  resolviendo y un repo mixto es válido; cero ficheros .swm versionados.
  Los tipos Swm/SwmBuild/swm_bridge no se tocan: son internos, van en la
  etapa 4.

287 tests en verde (hammer-cli + hammer-core), incluidos los que fabrican
repos con nombres .swm a mano — que son justamente la prueba de que la
compatibilidad hacia atrás se sostiene.
This commit is contained in:
Sergio
2026-09-09 18:22:15 +00:00
parent 7358a1054f
commit 80319d9bab
4 changed files with 67 additions and 21 deletions
+9 -1
View File
@@ -5,7 +5,15 @@ edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
description = "El binario `hammer`: orquesta build, hydrate, try/commit, apply/export y ctl."
description = "El binario `takana`: orquesta build, hydrate, try/commit, apply/export y ctl."
# ADR 0016 — renombre hammer→takana, etapa 2. Los DOS binarios se emiten a
# propósito, en vez de un symlink: la siembra de la granja excluye `/target`, así
# que un symlink hecho en el hub no existiría en el worker, y `cargo clean` lo
# borra. Dos `[[bin]]` sobreviven a las dos cosas. `hammer` se retira en la etapa 6.
[[bin]]
name = "takana"
path = "src/main.rs"
[[bin]]
name = "hammer"
+12 -3
View File
@@ -19,10 +19,10 @@ const DEFAULT_REPO: &str = "/var/lib/hammer/repo";
#[derive(Parser)]
#[command(
name = "hammer",
name = "takana",
version,
about = "Laboratorio funcional en el sótano, terminal mutable arriba.",
long_about = "hammer: distro AI-nativa. Ver docs/ para el diseño completo."
long_about = "takana: la forja determinista de tawasuyu — distro AI-nativa. Ver docs/ para el diseño completo."
)]
struct Cli {
/// Ruta del content-addressed store.
@@ -36,6 +36,12 @@ struct Cli {
#[derive(Subcommand)]
enum Cmd {
/// [Fase 0] Compila una receta y la sella en el store.
///
/// `forja` es alias de marca (ADR 0016): el verbo CANÓNICO sigue siendo `build` —
/// es el que usan los 124 llamadores, el cron y los runbooks. El alias existe para
/// que la invocación de la hoja de marca (`takana forja …`) funcione, no para
/// reemplazarlo.
#[command(alias = "forja")]
Build {
/// Ruta a la receta TOML.
recipe: String,
@@ -1788,7 +1794,10 @@ fn run_pack(
if let Some(repo_dir) = repo {
// Publicar: el repo asigna la identidad (nombre+versión de la receta). El `.swm` en sí
// no lleva nombre — el índice es el namespace. Upsert por nombre (idempotente).
let file_name = format!("{}-{}.swm", recipe.name, recipe.version);
// ADR 0016: los paquetes nuevos se escriben `.tkn`. Los repos existentes NO se
// rompen — `PackageEntry.file` guarda el nombre real de cada fichero, así que un
// índice con entradas `.swm` sigue resolviendo y un repo mixto es válido.
let file_name = format!("{}-{}.tkn", recipe.name, recipe.version);
std::fs::create_dir_all(repo_dir)?;
std::fs::write(repo_dir.join(&file_name), &yaml)?;
let mut index = hammer_core::RepoIndex::load(repo_dir)?;