use crate::common::TestProject;
use anyhow::Result;
use std::path::PathBuf;
use tokio::fs;
#[tokio::test]
async fn test_direct_and_transitive_same_resource_template_lookup() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let repo = project.create_source_repo("test").await?;
repo.add_resource(
"commands",
"checkpoint",
r#"---
description: Create a checkpoint
---
# Checkpoint Command
This creates a git checkpoint for safe editing.
CHECKPOINT_MARKER_CONTENT
"#,
)
.await?;
repo.add_resource(
"commands",
"squash",
r#"---
description: Squash commits
agpm:
templating: true
dependencies:
commands:
- path: ./checkpoint.md
install: false
---
# Squash Command
This command squashes commits. It uses the checkpoint command internally.
## Embedded Checkpoint:
{{ agpm.deps.commands.checkpoint.content }}
END_OF_SQUASH
"#,
)
.await?;
repo.commit_all("Add commands")?;
repo.tag_version("v1.0.0")?;
project
.write_manifest(&format!(
r#"
[sources]
test = "{}"
[commands]
checkpoint = {{ source = "test", path = "commands/checkpoint.md", version = "v1.0.0" }}
squash = {{ source = "test", path = "commands/squash.md", version = "v1.0.0" }}
"#,
repo.file_url()
))
.await?;
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. stderr: {}", output.stderr);
let squash_path = project.project_path().join(".claude/commands/agpm/squash.md");
let squash_content = fs::read_to_string(&squash_path).await?;
assert!(
squash_content.contains("CHECKPOINT_MARKER_CONTENT"),
"Squash should contain checkpoint content. Actual content:\n{}",
squash_content
);
assert!(squash_content.contains("END_OF_SQUASH"), "Squash should be fully rendered");
assert!(
!squash_content.contains("{{ agpm.deps"),
"Template syntax should be rendered, not raw. Content:\n{}",
squash_content
);
Ok(())
}
#[tokio::test]
async fn test_parent_relative_path_transitive_lookup() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let repo = project.create_source_repo("test").await?;
repo.add_resource(
"snippets",
"helper",
r#"---
description: Helper utilities
---
# Helper Snippet
HELPER_UNIQUE_CONTENT
"#,
)
.await?;
repo.add_resource(
"agents",
"parent",
r#"---
description: Parent agent
agpm:
templating: true
dependencies:
snippets:
- path: ../snippets/helper.md
install: false
---
# Parent Agent
Uses helper snippet:
{{ agpm.deps.snippets.helper.content }}
END_OF_PARENT
"#,
)
.await?;
repo.commit_all("Add resources")?;
repo.tag_version("v1.0.0")?;
project
.write_manifest(&format!(
r#"
[sources]
test = "{}"
[snippets]
helper = {{ source = "test", path = "snippets/helper.md", version = "v1.0.0" }}
[agents]
parent = {{ source = "test", path = "agents/parent.md", version = "v1.0.0" }}
"#,
repo.file_url()
))
.await?;
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. stderr: {}", output.stderr);
let parent_path = project.project_path().join(".claude/agents/agpm/parent.md");
let parent_content = fs::read_to_string(&parent_path).await?;
assert!(
parent_content.contains("HELPER_UNIQUE_CONTENT"),
"Parent should contain helper content. Actual content:\n{}",
parent_content
);
assert!(!parent_content.contains("{{ agpm.deps"), "Template syntax should be rendered");
Ok(())
}
#[tokio::test]
async fn test_local_deps_with_custom_name_transitive_lookup() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let artifacts_dir = project.project_path().parent().unwrap().join("artifacts");
let commands_dir = artifacts_dir.join("commands");
fs::create_dir_all(&commands_dir).await?;
let checkpoint_path = commands_dir.join("checkpoint.md");
fs::write(
&checkpoint_path,
r#"---
description: Create a checkpoint
---
# Checkpoint Command
CHECKPOINT_INSTALL_PATH_MARKER
"#,
)
.await?;
let squash_path = commands_dir.join("squash.md");
fs::write(
&squash_path,
r#"---
description: Squash commits
agpm:
templating: true
dependencies:
commands:
- name: checkpoint
path: ./checkpoint.md
---
# Squash Command
Uses checkpoint at: {{ agpm.deps.commands.checkpoint.install_path }}
END_OF_SQUASH
"#,
)
.await?;
let relative_path = PathBuf::from("../artifacts/commands");
project
.write_manifest(&format!(
r#"
[commands]
checkpoint = {{ path = "{}/checkpoint.md" }}
squash = {{ path = "{}/squash.md" }}
"#,
relative_path.display(),
relative_path.display()
))
.await?;
let output = project.run_agpm(&["install"])?;
assert!(output.success, "Install should succeed. stderr: {}", output.stderr);
let squash_installed_path = project.project_path().join(".claude/commands/agpm/squash.md");
let squash_content = fs::read_to_string(&squash_installed_path).await?;
assert!(
squash_content.contains(".claude/commands/agpm/checkpoint.md")
|| squash_content.contains(".claude\\commands\\agpm\\checkpoint.md")
|| squash_content.contains("commands/agpm/checkpoint")
|| squash_content.contains("commands\\agpm\\checkpoint"),
"Squash should contain checkpoint install_path. Actual content:\n{}",
squash_content
);
assert!(
!squash_content.contains("{{ agpm.deps"),
"Template syntax should be rendered, not raw. Content:\n{}",
squash_content
);
Ok(())
}
#[tokio::test]
async fn test_local_deps_transitive_content_access() -> Result<()> {
agpm_cli::test_utils::init_test_logging(None);
let project = TestProject::new().await?;
let artifacts_dir = project.project_path().parent().unwrap().join("artifacts2");
let commands_dir = artifacts_dir.join("commands");
fs::create_dir_all(&commands_dir).await?;
let helper_path = commands_dir.join("helper.md");
fs::write(
&helper_path,
r#"---
description: Helper utility
---
# Helper Command
HELPER_CONTENT_MARKER
"#,
)
.await?;
let main_path = commands_dir.join("main.md");
fs::write(
&main_path,
r#"---
description: Main command
agpm:
templating: true
dependencies:
commands:
- name: helper
path: ./helper.md
install: false
---
# Main Command
Embedded helper content:
{{ agpm.deps.commands.helper.content }}
END_OF_MAIN
"#,
)
.await?;
project
.write_manifest(
r#"
[commands]
helper = { path = "../artifacts2/commands/helper.md" }
main = { path = "../artifacts2/commands/main.md" }
"#,
)
.await?;
let output = project.run_agpm(&["install"])?;
let lockfile_content = project.read_lockfile().await.unwrap_or_default();
eprintln!("=== LOCKFILE ===\n{}\n=== END LOCKFILE ===", lockfile_content);
assert!(output.success, "Install should succeed. stderr: {}", output.stderr);
let main_installed_path = project.project_path().join(".claude/commands/agpm/main.md");
let main_content = fs::read_to_string(&main_installed_path).await?;
assert!(
main_content.contains("HELPER_CONTENT_MARKER"),
"Main should contain helper content. Actual content:\n{}",
main_content
);
assert!(
!main_content.contains("{{ agpm.deps"),
"Template syntax should be rendered, not raw. Content:\n{}",
main_content
);
Ok(())
}