///|
fn moon_mod_content(name : String, description : String) -> String {
let content =
#|name = __NAME__
#|
#|version = "0.1.0"
#|
#|readme = "README.md"
#|
#|repository = ""
#|
#|license = "Apache-2.0"
#|
#|keywords = ["wasm", "skill", "agent"]
#|
#|description = __DESCRIPTION__
#|
#|preferred_target = "wasm"
#|
#|supported_targets = "wasm"
#|
#|import {
#| "moonbit-community/miniio@__MINIIO_VERSION__",
#|}
content
.replace_all(old="__NAME__", new=moon_string(name))
.replace_all(old="__DESCRIPTION__", new=moon_string(description))
.replace_all(old="__MINIIO_VERSION__", new=miniio_version)
}
///|
fn moon_pkg_content() -> String {
(
#|import {
#| "moonbit-community/miniio",
#| "moonbitlang/core/argparse",
#|}
#|
#|supported_targets = "wasm"
#|
#|options(
#| "is-main": true,
#|)
)
}
///|
fn main_mbt_content(name : String) -> String {
let content =
#|///|
#|fn main {
#| try {
#| let cli = @argparse.Command(__COMMAND_NAME__, about="Print a greeting.", options=[
#| @argparse.OptionArg(
#| "name",
#| short='n',
#| long="name",
#| about="Name to greet.",
#| default_values=["MoonBit"],
#| ),
#| ])
#| let matches = cli.parse()
#| let name = matches.values["name"][0]
#| @miniio.stdout.write_text("__GREETING__")
#| } catch {
#| err => {
#| println(err.to_string())
#| @miniio.exit(2)
#| }
#| }
#|}
content
.replace_all(old="__COMMAND_NAME__", new=moon_string(name))
.replace_all(old="__GREETING__", new="Hello, \\{name}!\\n")
}
///|
fn gitignore_content() -> String {
(
#|.DS_Store
#|_build/
#|target/
#|target
#|.mooncakes/
#|.moonagent/
#|_tmp_*
#|
)
}
///|
fn agents_md_content() -> String {
(
#|# Project Agents.md Guide
#|
#|This is a [MoonBit](https://docs.moonbitlang.com) project.
#|
#|You can browse and install extra skills here:
#|
#|
#|## Project Structure
#|
#|- MoonBit packages are organized per directory; each directory contains a
#| `moon.pkg` file listing its dependencies. Each package has its files and
#| blackbox test files (ending in `_test.mbt`) and whitebox test files (ending in
#| `_wbtest.mbt`).
#|
#|- In the toplevel directory, there is a `moon.mod` file listing module
#| metadata.
#|
#|## Coding convention
#|
#|- MoonBit code is organized in block style, each block is separated by `///|`,
#| the order of each block is irrelevant. In some refactorings, you can process
#| block by block independently.
#|
#|- Try to keep deprecated blocks in file called `deprecated.mbt` in each
#| directory.
#|
#|## Tooling
#|
#|- `moon fmt` is used to format your code properly.
#|
#|- `moon ide` provides project navigation helpers like `peek-def`, `outline`, and
#| `find-references`. See $moonbit-agent-guide for details.
#|
#|- `moon info` is used to update the generated interface of the package, each
#| package has a generated interface file `.mbti`, it is a brief formal
#| description of the package. If nothing in `.mbti` changes, this means your
#| change does not bring the visible changes to the external package users, it is
#| typically a safe refactoring.
#|
#|- In the last step, run `moon info && moon fmt` to update the interface and
#| format the code. Check the diffs of `.mbti` file to see if the changes are
#| expected.
#|
#|- Run `moon test` to check tests pass. MoonBit supports snapshot testing; when
#| changes affect outputs, run `moon test --update` to refresh snapshots.
#|
#|- Prefer `assert_eq` or `assert_true(pattern is Pattern(...))` for results that
#| are stable or very unlikely to change. For snapshot tests that record
#| structured debugging output, derive `Debug` and use `debug_inspect`, rather
#| than deriving `Show` for debugging. For solid, well-defined results (e.g.
#| scientific computations), prefer assertion tests. You can use
#| `moon coverage analyze > uncovered.log` to see which parts of your code are
#| not covered by tests.
#|
)
}
///|
fn readme_content(name : String, module_full_name : String) -> String {
let content =
#|# __NAME__
#|
#|Portable MoonBit WASM skill created by `meta-skill`.
#|
#|```sh
#|moon runwasm __MODULE__
#|moon runwasm __MODULE__ --name Agent
#|```
content
.replace_all(old="__NAME__", new=name)
.replace_all(old="__MODULE__", new=module_full_name)
}
///|
fn skill_md_content(
name : String,
module_full_name : String,
description : String,
) -> String {
let content =
#|---
#|name: __NAME__
#|description: __DESCRIPTION__
#|---
#|
#|# __NAME__
#|
#|Use this skill when the user asks to run this MoonBit WASM CLI or understand its command-line behavior.
#|
#|## Run
#|
#|```sh
#|moon runwasm __MODULE__
#|moon runwasm __MODULE__ --name Agent
#|```
#|
#|## Behavior
#|
#|- With no options, the CLI prints `Hello, MoonBit!`.
#|- `--name ` or `-n ` changes the name in the greeting.
#|- Argument and fatal I/O errors are written to stderr and exit nonzero.
content
.replace_all(old="__NAME__", new=name)
.replace_all(old="__MODULE__", new=module_full_name)
.replace_all(old="__DESCRIPTION__", new=moon_string(description))
}
///|
fn template_files(name : String, description : String) -> Array[TemplateFile] {
let module_full_name = module_name(name)
[
{
path: "moon.mod",
content: moon_mod_content(module_full_name, description),
},
{ path: "moon.pkg", content: moon_pkg_content() },
{ path: "main.mbt", content: main_mbt_content(name) },
{ path: ".gitignore", content: gitignore_content() },
{ path: "AGENTS.md", content: agents_md_content() },
{ path: "README.md", content: readme_content(name, module_full_name) },
{
path: "SKILL.md",
content: skill_md_content(name, module_full_name, description),
},
]
}
///|
fn create_wasm_skill(dir : String, description : String) -> Unit raise {
ensure_target_dir(dir)
let name = target_name(dir)
for file in template_files(name, description) {
@miniio.write_text_file(
path_join(dir, file.path),
file.content,
create_mode=@miniio.CreateMode::CreateNew,
)
}
}
///|
fn post_create_message(dir : String, name : String) -> String {
let mod_path = path_join(dir, "moon.mod")
let content =
#|created __DIR__
#|
#|Next steps for the AI agent:
#|1. Run `moon whoami` to get the current MoonBit username, then replace `username` in `__MOD_PATH__` so the module name becomes `name = "/__NAME__"`.
#|2. Run `cd __DIR__ && moon add -u moonbit-community/miniio` to refresh the MiniIO dependency.
content
.replace_all(old="__DIR__", new=dir)
.replace_all(old="__MOD_PATH__", new=mod_path)
.replace_all(old="__NAME__", new=name) +
"\n"
}