inst/tinytest/test_skill_manifest.R

local({
    root <- tempfile("skills-")
    dir.create(root)
    on.exit(unlink(root, recursive = TRUE))
    put <- function(path, text) {
        dir.create(dirname(path), recursive = TRUE, showWarnings = FALSE)
        writeBin(charToRaw(text), path)
    }
    package <- function(path, name = "example", version = "1.0.0") {
        put(file.path(path, "DESCRIPTION"),
            paste0("Package: ", name, "\nVersion: ", version, "\n"))
    }
    bundle <- function(base, dir = "alpha", name = "alpha",
                       description = "A compact description.") {
        path <- file.path(base, dir, "SKILL.md")
        put(path, paste0("---\nname: ", name, "\ndescription: ", description,
                         "\n---\n\nPRIVATE_BODY_SENTINEL\n"))
        path
    }
    empty <- skill_manifest(packages = character(), lib.loc = character())
    expect_equal(nrow(empty$entries), 0L)
    expect_equal(length(empty$resources), 0L)
    expect_error(skill_manifest(roots = c(root, root)), "unique stable names")
    expect_error(skill_manifest(project_dirs = NA_character_), "nonempty strings")
    personal <- file.path(root, "personal")
    main <- bundle(personal)
    folded <- bundle(personal, "category/beta", "beta", ">-\n  Folded first line\n  and second line.")
    quoted <- bundle(personal, "gamma", "gamma", "\"Use a colon: safely.\"")
    bundle(personal, "delta", "delta", "'Use a doubled ''quote'' safely.'")
    bundle(personal, "epsilon", "epsilon", "|\n  Literal first\n  second.")
    put(file.path(personal, "README.md"), "Not a skill.")
    reference <- file.path(personal, "alpha", "references", "detail.md")
    exact <- "Heading\r\n\r\n  Indented text.\r\n"
    put(reference, exact)
    discover <- function(...) skill_manifest(packages = character(), lib.loc = character(),
        roots = c(personal = personal), ...)
    m <- discover()
    expect_equal(nrow(m$entries), 5L)
    expect_equal(sum(m$entries$selected), 5L)
    expect_equal(m$entries$description[m$entries$name == "beta"],
                 "Folded first line and second line.")
    expect_equal(m$entries$description[m$entries$name == "gamma"], "Use a colon: safely.")
    expect_equal(m$entries$description[m$entries$name == "delta"], "Use a doubled 'quote' safely.")
    expect_equal(m$entries$description[m$entries$name == "epsilon"], "Literal first second.")
    expect_equal(skill_read(m, "root:personal/alpha", "references/detail.md"), exact)
    expect_true(grepl("PRIVATE_BODY_SENTINEL", skill_read(m, "root:personal/alpha")))
    expect_false(any(grepl("PRIVATE_BODY_SENTINEL", capture.output(print(m)))))
    expect_error(skill_read(m, "alpha"), "not selected")
    expect_error(skill_read(m, "root:personal/alpha", "../beta/SKILL.md"), "relative")
    expect_error(skill_read(m, "root:personal/alpha", "/etc/passwd"), "relative")
    expect_error(skill_read(m, "root:personal/alpha", "C:\\outside"), "relative")
    expect_error(skill_read(m, "root:personal/alpha", "new.md"), "not in")
    put(file.path(personal, "alpha", "new.md"), "Added after discovery.")
    expect_error(skill_read(m, "root:personal/alpha", "new.md"), "not in")
    put(reference, "Changed supporting reference.")
    expect_error(skill_read(m, "root:personal/alpha", "references/detail.md"), "drifted")
    put(reference, exact)
    put(main, paste0(skill_read(m, "root:personal/alpha"), "Changed body."))
    expect_error(skill_read(m, "root:personal/alpha"), "drifted")
    expect_true(grepl("Changed body", skill_read(discover(), "root:personal/alpha")))
    disabled <- discover(disabled = "root:personal/beta")
    expect_false(disabled$entries$selected[disabled$entries$name == "beta"])
    expect_error(skill_read(disabled, "root:personal/beta"), "not selected")
    bundle(personal, "duplicate", "alpha")
    duplicate <- discover()
    expect_false(any(duplicate$entries$selected[duplicate$entries$name == "alpha"]))
    expect_true(all(duplicate$entries$reason[duplicate$entries$name == "alpha"] == "duplicate_id"))
    bad <- bundle(personal, "bad", "bad", ">")
    malformed <- discover()
    expect_true(nrow(malformed$diagnostics) > 0L)
    expect_false("bad" %in% malformed$entries$name)
    put(bad, "---\nname: bad\nname: twice\ndescription: plain\n---\n")
    expect_true(nrow(discover()$diagnostics) > 0L)

    # Whole-root precedence avoids mixing skills from different package builds.
    source <- file.path(root, "checkout")
    lib <- file.path(root, "library")
    installed <- file.path(lib, "example")
    package(source, version = "2.0.0")
    package(installed)
    bundle(file.path(source, "inst", "skills"))
    bundle(file.path(installed, "skills"), "example/alpha")
    bundle(file.path(installed, "skills"), "example/installed-only", "installed-only")
    pm <- skill_manifest(lib.loc = lib, project_dirs = source)
    expect_equal(sum(pm$entries$selected), 1L)
    expect_equal(pm$entries$version[pm$entries$selected], "2.0.0")
    expect_equal(pm$entries$id[pm$entries$selected], "package:example/alpha")
    im <- skill_manifest(lib.loc = lib, project_dirs = source, prefer = "installed")
    expect_equal(sum(im$entries$selected), 2L)
    expect_true(all(im$entries$version[im$entries$selected] == "1.0.0"))
    expect_true(grepl("PRIVATE_BODY_SENTINEL", skill_read(im, "package:example/alpha")))
    another <- file.path(lib, "another")
    package(another, name = "another")
    bundle(file.path(another, "skills"))
    expect_equal(sum(skill_manifest(lib.loc = lib)$entries$selected), 3L)
    expect_equal(sum(skill_manifest(packages = "another", lib.loc = lib)$entries$selected), 1L)
    lib2 <- file.path(root, "library2")
    package(file.path(lib2, "example"), version = "0.5.0")
    bundle(file.path(lib2, "example", "skills"))
    lm <- skill_manifest(lib.loc = c(lib, lib2))
    expect_equal(lm$entries$version[lm$entries$selected & lm$entries$package == "example"], rep("1.0.0", 2L))

    # An alias root is allowed; resources cannot escape or change identity.
    alias <- file.path(root, "alias")
    if (isTRUE(suppressWarnings(file.symlink(source, alias)))) {
        am <- skill_manifest(lib.loc = character(), project_dirs = c(alias, source))
        expect_equal(sum(am$entries$selected), 1L)
        expect_equal(nrow(am$roots), 1L)
        safe <- file.path(root, "safe")
        outside <- file.path(root, "outside.md")
        bundle(safe)
        put(outside, "Outside resource.")
        link <- file.path(safe, "alpha", "outside.md")
        expect_true(file.symlink(outside, link))
        unsafe <- skill_manifest(lib.loc = character(), roots = c(test = safe))
        expect_equal(sum(unsafe$entries$selected), 0L)
        expect_true(nrow(unsafe$diagnostics) > 0L)
        unlink(link)
        sm <- skill_manifest(lib.loc = character(), roots = c(test = safe))
        moved <- file.path(root, "safe-moved")
        expect_true(file.rename(safe, moved))
        expect_true(file.symlink(moved, safe))
        expect_error(skill_read(sm, "root:test/alpha"), "drifted")
    }
})

Try the saber package in your browser

Any scripts or data that you put into this service are public.

saber documentation built on Nov. 10, 2026, 9:06 a.m.