Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project uses [independent versioning](README.md#versioning) for Framewo

---

## CLI 3.5.3 — `devtrail update` no longer leaks package internals into adopter projects

### Fixed (CLI)
- `devtrail update` (and `devtrail update-framework`) used to copy the framework's internal `dist-manifest.yml` and `dist-templates/` directory into the root of the adopter project. Both are package-internal artifacts: the manifest is the catalogue the CLI reads from the release ZIP, and `dist-templates/` is the source of agent-directive injections that are read into memory and merged via marker blocks — neither is meant to land on disk in the target project. `devtrail init` already filtered correctly via `manifest.files`; only the update path was inconsistent. Update now applies the same whitelist, so only files declared in the release manifest are copied. Existing projects affected by the bug can clean up by deleting `dist-manifest.yml` and `dist-templates/` from their project root and running `devtrail update-framework` again to regenerate `.devtrail/.checksums.json` without orphan entries.

---

## CLI 3.5.2 — Remove Undocumented Vim-Style Aliases (`l`, `h`)

### Changed (CLI)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ DevTrail uses independent version tags for each component:
| Component | Tag prefix | Example | Includes |
|-----------|-----------|---------|----------|
| Framework | `fw-` | `fw-4.3.0` | Templates (12 types), governance, directives |
| CLI | `cli-` | `cli-3.5.2` | The `devtrail` binary |
| CLI | `cli-` | `cli-3.5.3` | The `devtrail` binary |

Check installed versions with `devtrail status` or `devtrail about`.

Expand Down
2 changes: 1 addition & 1 deletion cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "devtrail-cli"
version = "3.5.2"
version = "3.5.3"
edition = "2021"
description = "CLI tool for DevTrail - Documentation Governance for AI-Assisted Development"
license = "MIT"
Expand Down
82 changes: 70 additions & 12 deletions cli/src/commands/update_framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ pub fn run() -> Result<()> {

// Update framework files
utils::info("Updating framework files...");
let stats = update_files(&target, &source_root, &current_checksums)?;
let stats = update_files(&target, &source_root, &manifest, &current_checksums)?;

// Update directive injections
utils::info("Updating AI agent directives...");
Expand Down Expand Up @@ -105,6 +105,7 @@ struct UpdateStats {
fn update_files(
target: &Path,
source_root: &Path,
manifest: &DistManifest,
checksums: &Checksums,
) -> Result<UpdateStats> {
let mut stats = UpdateStats {
Expand All @@ -121,20 +122,19 @@ fn update_files(
.strip_prefix(source_root)
.unwrap_or(&source_path)
.display()
.to_string();

// Skip user-generated documents
if utils::is_user_document(&source_path) {
continue;
}

// Skip checksums file
if relative == ".devtrail/.checksums.json" {
.to_string()
.replace('\\', "/");

// Only touch files declared by the release manifest. The release ZIP also
// ships internal artifacts (`dist-manifest.yml`, `dist-templates/`) that
// the CLI consumes from the temp dir but must never copy into the
// adopter's project. Mirrors `init.rs::extract_matching_files`.
if !matches_manifest(&relative, &manifest.files) {
continue;
}

// Skip dist-manifest.yml (we save it separately)
if relative == ".devtrail/dist-manifest.yml" {
// Skip user-generated documents
if utils::is_user_document(&source_path) {
continue;
}

Expand Down Expand Up @@ -325,6 +325,18 @@ fn find_source_root(extract_dir: &Path) -> Result<PathBuf> {
bail!("Could not find dist-manifest.yml in extracted archive");
}

/// Match a relative path (POSIX-style) against the manifest's `files` whitelist.
/// Patterns ending in `/` match any path under that directory; otherwise exact match.
fn matches_manifest(relative: &str, files: &[String]) -> bool {
files.iter().any(|pat| {
if pat.ends_with('/') {
relative.starts_with(pat.as_str())
} else {
relative == pat
}
})
}

fn walkdir(dir: PathBuf) -> Result<Vec<PathBuf>> {
let mut files = Vec::new();
if !dir.is_dir() {
Expand All @@ -343,3 +355,49 @@ fn walkdir(dir: PathBuf) -> Result<Vec<PathBuf>> {

Ok(files)
}

#[cfg(test)]
mod tests {
use super::matches_manifest;

fn manifest_files() -> Vec<String> {
// Matches `dist/dist-manifest.yml` (fw-4.3.0).
vec![
".devtrail/".to_string(),
"DEVTRAIL.md".to_string(),
".claude/skills/".to_string(),
".gemini/skills/".to_string(),
".agent/workflows/".to_string(),
".github/workflows/docs-validation.yml".to_string(),
]
}

#[test]
fn package_artifacts_are_rejected() {
let files = manifest_files();
// Regression for the bug where `devtrail update` deposited these in the
// adopter project. Both live at the ZIP root, neither is in `manifest.files`.
assert!(!matches_manifest("dist-manifest.yml", &files));
assert!(!matches_manifest("dist-templates/directives/CLAUDE.md", &files));
}

#[test]
fn declared_files_and_directories_match() {
let files = manifest_files();
assert!(matches_manifest("DEVTRAIL.md", &files));
assert!(matches_manifest(".devtrail/00-governance/AGENT-RULES.md", &files));
assert!(matches_manifest(".claude/skills/devtrail-new/SKILL.md", &files));
assert!(matches_manifest(
".github/workflows/docs-validation.yml",
&files
));
}

#[test]
fn undeclared_paths_are_rejected() {
let files = manifest_files();
assert!(!matches_manifest("README.md", &files));
assert!(!matches_manifest(".github/workflows/release-cli.yml", &files));
assert!(!matches_manifest(".claude/agents/foo.md", &files));
}
}
2 changes: 1 addition & 1 deletion docs/adopters/CLI-REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ DevTrail uses **independent version tags** for each component:
| Component | Tag prefix | Example | What it includes |
|-----------|-----------|---------|------------------|
| Framework | `fw-` | `fw-4.3.0` | Templates (12 types), governance docs, directives |
| CLI | `cli-` | `cli-3.5.2` | The `devtrail` binary |
| CLI | `cli-` | `cli-3.5.3` | The `devtrail` binary |

Framework and CLI are released independently. A framework update does not require a CLI update, and vice versa.

Expand Down
2 changes: 1 addition & 1 deletion docs/i18n/es/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ DevTrail usa tags de versión independientes para cada componente:
| Componente | Prefijo de tag | Ejemplo | Incluye |
|------------|---------------|---------|---------|
| Framework | `fw-` | `fw-4.3.0` | Plantillas (12 tipos), gobernanza, directivas |
| CLI | `cli-` | `cli-3.5.2` | El binario `devtrail` |
| CLI | `cli-` | `cli-3.5.3` | El binario `devtrail` |

Verifica las versiones instaladas con `devtrail status` o `devtrail about`.

Expand Down
2 changes: 1 addition & 1 deletion docs/i18n/es/adopters/CLI-REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ DevTrail usa **tags de versión independientes** para cada componente:
| Componente | Prefijo de tag | Ejemplo | Qué incluye |
|------------|---------------|---------|-------------|
| Framework | `fw-` | `fw-4.3.0` | Plantillas (12 tipos), docs de gobernanza, directivas |
| CLI | `cli-` | `cli-3.5.2` | El binario `devtrail` |
| CLI | `cli-` | `cli-3.5.3` | El binario `devtrail` |

Framework y CLI se publican de forma independiente. Una actualización del framework no requiere actualización del CLI, y viceversa.

Expand Down
2 changes: 1 addition & 1 deletion docs/i18n/zh-CN/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ DevTrail 为每个组件使用独立的版本标签:
| 组件 | 标签前缀 | 示例 | 包含内容 |
|------|----------|------|----------|
| Framework | `fw-` | `fw-4.3.0` | 模板(12 种类型)、治理文档、指令 |
| CLI | `cli-` | `cli-3.5.2` | `devtrail` 二进制文件 |
| CLI | `cli-` | `cli-3.5.3` | `devtrail` 二进制文件 |

使用 `devtrail status` 或 `devtrail about` 查看已安装的版本。

Expand Down
2 changes: 1 addition & 1 deletion docs/i18n/zh-CN/adopters/CLI-REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ DevTrail 为每个组件使用**独立的版本标签**:
| 组件 | 标签前缀 | 示例 | 包含内容 |
|------|----------|------|----------|
| Framework | `fw-` | `fw-4.3.0` | 模板(12 种类型)、治理文档、指令 |
| CLI | `cli-` | `cli-3.5.2` | `devtrail` 二进制文件 |
| CLI | `cli-` | `cli-3.5.3` | `devtrail` 二进制文件 |

Framework 和 CLI 独立发布。Framework 更新不需要 CLI 更新,反之亦然。

Expand Down