~/bend-docscommunity

domain/architecture/system/release/plugin/ops.bend source

domain/architecture/system/release/plugin/ops.bend on the hub · documented module

import Baseimport bend-net-json@0.3.0.0/json.bend as Jsonimport ./json.bend as Jimport ./type.bend as Plimport ./claude/ops.bend as ClOimport ./codex/ops.bend as CxO# A plugin's two manifests: the root plugin.json (Agent Plugins 1.0, which Codex reads) and# .claude-plugin/plugin.json (which Claude Code reads).def schema() -> String:  "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json"def version_show(v: Pl.Version) -> String:  match v:    case Pl.Version{major, minor, patch}:      Nat.show(major) ++ "." ++ Nat.show(minor) ++ "." ++ Nat.show(patch)def author(a: Pl.Author) -> Json.Val:  match a:    case Pl.Author{name, email, url}:      J.cat([[("name", Json.Str{name})], J.opt("email", J.text(email)), J.opt("url", J.text(url))])def keywords(xs: List<&2, String>) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:  match xs:    case []:      []    case x <> rest:      [("keywords", J.texts(x <> rest))]def core_keys(c: Pl.Core) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:  match c:    case Pl.Core{name, v, description, a, homepage, repository, license, ks}:      List.concat(&2, Sigma<&2, &2, String, _ => Json.Val>, [        [("name", Json.Str{name}), ("version", Json.Str{version_show(v)}), ("description", Json.Str{description}), ("author", author(a))],        J.opt("homepage", J.text(homepage)), J.opt("repository", J.text(repository)), J.opt("license", J.text(license)), keywords(ks)])# Codex's extension, or nothing when Codex adds nothing.def extensions(kvs: List<&2, Sigma<&2, &2, String, _ => Json.Val>>) -> List<&2, Sigma<&2, &2, String, _ => Json.Val>>:  match kvs:    case []:      []    case kv <> rest:      [("extensions", J.obj([("com.openai", J.obj(kv <> rest))]))]# The root plugin.json's text.def agent(p: Pl.Package) -> String:  match p:    case Pl.Package{c, _, cx}:      Json.encode(J.cat([[("$schema", Json.Str{schema()})], core_keys(c), extensions(CxO.keys(cx))])) ++ "\n"# .claude-plugin/plugin.json's text.def claude(p: Pl.Package) -> String:  match p:    case Pl.Package{c, cl, _}:      Json.encode(J.cat([core_keys(c), ClO.keys(cl)])) ++ "\n"def name_of(p: Pl.Package) -> String:  match p:    case Pl.Package{Pl.Core{n, _, _, _, _, _, _, _}, _, _}:      n# ---- the standard's rule for a name ----def name_char(+c: Char) -> Bool:  Char.is_lower(c) || Char.is_digit(c) || Char.is_eq(c, '.') || Char.is_eq(c, '-')def edge_char(+c: Char) -> Bool:  Char.is_lower(c) || Char.is_digit(c)def repeats(cs: List<&2, Char>, +prev: Char) -> Bool:  match cs:    case []:      False{}    case +c <> rest:      ((Char.is_eq(c, '-') || Char.is_eq(c, '.')) && Char.is_eq(c, prev)) || repeats(rest, c)def all_name_chars(cs: List<&2, Char>) -> Bool:  match cs:    case []:      True{}    case +c <> rest:      name_char(c) && all_name_chars(rest)def first_ok(cs: List<&2, Char>) -> Bool:  match cs:    case []:      False{}    case +c <> _:      edge_char(c)# 1 to 64 of a-z, 0-9, . and -, starting and ending with a letter or digit, with no -- or ..def name_ok(+n: String) -> Bool:  Nat.is_ge(String.length(n), 1n) && Nat.is_le(String.length(n), 64n) && all_name_chars(String.to_list(n)) &&  first_ok(String.to_list(n)) && first_ok(String.to_list(String.reverse(n))) && Bool.not(repeats(String.to_list(n), ' '))