/**
* `harn init` and `harn new` ported to .harn — see harn#2308 (W8).
*
* Renders the eight project starter templates (basic, agent, chat,
* mcp-server, eval, pipeline-lab, package, connector) and writes each
* template file to disk, skipping files that already exist (mirrors the
* Rust `write_if_new` semantics). The dispatch shim in
* crates/harn-cli/src/commands/init.rs resolves args, creates the
* destination dir, and hands the rendered project name + template
* identifier to this script via env vars.
*
* Inputs (set by the shim before dispatch):
* HARN_INIT_NAME — optional human project name shown by "cd"
* HARN_INIT_PROJECT_NAME — sanitized project name embedded in
* manifests and README headers
* HARN_INIT_DIR — destination directory (already created)
* HARN_INIT_TEMPLATE — one of: basic, agent, chat, mcp-server,
* eval, pipeline-lab, package, connector
* HARN_INIT_HARN_RANGE — current harn version range (e.g. ">=0.7,<0.8")
* HARN_INIT_MODE — "init" or "new" (informational, not currently
* branched on but kept for future divergence)
*/
fn __basic_manifest(project_name: string) -> string {
return "[package]\n"
+ "name = \""
+ project_name
+ "\"\n"
+ "version = \"0.1.0\"\n"
+ "\n"
+ "[dependencies]\n"
}
fn __chat_manifest(project_name: string) -> string {
return "[package]\n"
+ "name = \""
+ project_name
+ "\"\n"
+ "version = \"0.1.0\"\n"
+ "\n"
+ "[dependencies]\n"
+ "\n"
+ "[llm.aliases]\n"
+ "chat = { id = \"llama3.2\", provider = \"ollama\" }\n"
}
fn __package_manifest(project_name: string, harn_range: string) -> string {
return "[package]\n"
+ "name = \""
+ project_name
+ "\"\n"
+ "version = \"0.1.0\"\n"
+ "description = \"Reusable Harn package.\"\n"
+ "license = \"MIT OR Apache-2.0\"\n"
+ "repository = \"https://github.com/OWNER/"
+ project_name
+ "\"\n"
+ "harn = \""
+ harn_range
+ "\"\n"
+ "docs_url = \"docs/api.md\"\n"
+ "\n"
+ "[exports]\n"
+ "lib = \"lib/main.harn\"\n"
+ "\n"
+ "[dependencies]\n"
}
fn __connector_manifest(project_name: string, harn_range: string) -> string {
return "[package]\n"
+ "name = \""
+ project_name
+ "\"\n"
+ "version = \"0.1.0\"\n"
+ "description = \"Pure-Harn connector package.\"\n"
+ "license = \"MIT OR Apache-2.0\"\n"
+ "repository = \"https://github.com/OWNER/"
+ project_name
+ "\"\n"
+ "harn = \""
+ harn_range
+ "\"\n"
+ "docs_url = \"docs/api.md\"\n"
+ "\n"
+ "[exports]\n"
+ "connector = \"connectors/echo.harn\"\n"
+ "\n"
+ "[[providers]]\n"
+ "id = \"echo\"\n"
+ "connector = { harn = \"connectors/echo\" }\n"
+ "\n"
+ "[connector_contract]\n"
+ "version = 1\n"
+ "\n"
+ "[[connector_contract.fixtures]]\n"
+ "provider = \"echo\"\n"
+ "name = \"message\"\n"
+ "kind = \"webhook\"\n"
+ "body_json = { message = \"hello\" }\n"
+ "expect_type = \"event\"\n"
+ "expect_kind = \"webhook\"\n"
+ "expect_event_count = 1\n"
+ "\n"
+ "[dependencies]\n"
}
fn __basic_files(project_name: string, harn_range: string) -> list {
return [
["harn.toml", __basic_manifest(project_name)],
[
"main.harn",
"import \"lib/helpers\"\n"
+ "\n"
+ "pipeline default(task) {\n"
+ " let greeting = greet(\"world\")\n"
+ " log(greeting)\n"
+ "}\n",
],
[
"lib/helpers.harn",
"fn greet(name) {\n"
+ " return \"Hello, \" + name + \"!\"\n"
+ "}\n"
+ "\n"
+ "fn add(a, b) {\n"
+ " return a + b\n"
+ "}\n",
],
[
"tests/test_main.harn",
"import \"../lib/helpers\"\n"
+ "\n"
+ "pipeline test_greet(task) {\n"
+ " assert_eq(greet(\"world\"), \"Hello, world!\")\n"
+ " assert_eq(greet(\"Harn\"), \"Hello, Harn!\")\n"
+ "}\n"
+ "\n"
+ "pipeline test_add(task) {\n"
+ " assert_eq(add(2, 3), 5)\n"
+ " assert_eq(add(-1, 1), 0)\n"
+ " assert_eq(add(0, 0), 0)\n"
+ "}\n",
],
]
}
fn __agent_files(project_name: string, harn_range: string) -> list {
let main_harn = "import { agent_host_tools } from \"std/agent/host_tools\"\n"
+ "import { audit_agent } from \"std/agent/presets\"\n"
+ "\n"
+ "fn main(harness: Harness) {\n"
+ " let task = harness.env.get_or(\"HARN_TASK\", \"Review the repository\")\n"
+ " let root = cwd()\n"
+ " let tools = agent_host_tools(\n"
+ " nil,\n"
+ " {\n"
+ " root: root,\n"
+ " cwd: root,\n"
+ " enabled_tools: [\"list_directory\", \"read_file\", \"search_files\"],\n"
+ " max_inline_bytes: 6000,\n"
+ " search_exclude_globs: [\".git/**\", \".harn/**\", \"target/**\", \"node_modules/**\"],\n"
+ " },\n"
+ " )\n"
+ " let result = audit_agent(\n"
+ " task,\n"
+ " {\n"
+ " system: \"You are a careful repository auditor. Use the read-only tools to inspect before answering. Do not guess file contents, and do not discuss provider, model, harness, or system-prompt details.\",\n"
+ " tools: tools,\n"
+ " max_iterations: 6,\n"
+ " llm_options: {temperature: 0},\n"
+ " },\n"
+ " )\n"
+ " harness.stdio.println(result.visible_text ?? result.text ?? \"\")\n"
+ "}\n"
// Triple-quoted in the Rust source — embed the literal Harn snippet
// inside the mock-driven test exactly as the original handler did.
let test_harn = "import { audit_agent } from \"std/agent/presets\"\n"
+ "\n"
+ "pipeline test_agent_smoke(task) {\n"
+ " llm_mock_clear()\n"
+ " llm_mock({text: \"<user_response>Repository looks healthy.</user_response>\\n<done>##DONE##</done>\"})\n"
+ " let result = audit_agent(\n"
+ " \"Review the repository\",\n"
+ " {provider: \"mock\", model: \"mock\", loop_until_done: false, max_iterations: 1},\n"
+ " )\n"
+ " assert_eq(result.status, \"done\")\n"
+ "}\n"
let readme = "# " + project_name + "\n"
+ "\n"
+ "Read-only agent starter for Harn.\n"
+ "\n"
+ "## Run\n"
+ "\n"
+ "```bash\n"
+ "HARN_TASK=\"Summarize this repository\" harn run main.harn\n"
+ "```\n"
+ "\n"
+ "Run `harn quickstart` first if this project does not already have an LLM\n"
+ "provider configured. The starter uses scoped read-only tools by default; add\n"
+ "write or command tools only when the task needs them.\n"
return [
["harn.toml", __basic_manifest(project_name)],
["main.harn", main_harn],
["tests/test_agent.harn", test_harn],
["README.md", readme],
]
}
fn __chat_files(project_name: string, harn_range: string) -> list {
let main_harn = "fn build_chat_prompt(history, message) {\n"
+ " if history == \"\" {\n"
+ " return \"User: \" + message\n"
+ " }\n"
+ " return history + \"\\nUser: \" + message\n"
+ "}\n"
+ "\n"
+ "fn stream_reply(harness: Harness, prompt, system, options) {\n"
+ " var answer = \"\"\n"
+ " let chunks = llm_stream_call(prompt, system, options)\n"
+ " for chunk in chunks {\n"
+ " harness.stdio.print(chunk.visible_delta)\n"
+ " answer = chunk.partial\n"
+ " }\n"
+ " harness.stdio.println(\"\")\n"
+ " return answer\n"
+ "}\n"
+ "\n"
+ "fn main(harness: Harness) {\n"
+ " let system = env_or(\"HARN_CHAT_SYSTEM\", \"You are a concise, helpful assistant.\")\n"
+ " let model = env_or(\"HARN_CHAT_MODEL\", \"chat\")\n"
+ " let options = {model: model, max_tokens: 2048, temperature: 0.7}\n"
+ " var history = \"\"\n"
+ " harness.stdio.println(\"Harn chat. Type /clear to reset history or /exit to quit.\")\n"
+ " while true {\n"
+ " harness.stdio.print(\"you> \")\n"
+ " let raw = harness.stdio.read_line()\n"
+ " if !raw.ok {\n"
+ " break\n"
+ " }\n"
+ " let message = trim(raw.value)\n"
+ " if message == \"\" {\n"
+ " continue\n"
+ " }\n"
+ " if message == \"/exit\" || message == \"/quit\" {\n"
+ " break\n"
+ " }\n"
+ " if message == \"/clear\" {\n"
+ " history = \"\"\n"
+ " harness.stdio.println(\"history cleared\")\n"
+ " continue\n"
+ " }\n"
+ " let prompt = build_chat_prompt(history, message)\n"
+ " harness.stdio.print(\"assistant> \")\n"
+ " let answer = stream_reply(harness, prompt, system, options)\n"
+ " history = prompt + \"\\nAssistant: \" + answer + \"\\n\"\n"
+ " }\n"
+ "}\n"
let readme = "# " + project_name + "\n"
+ "\n"
+ "Streaming chat starter for Harn.\n"
+ "\n"
+ "## Provider\n"
+ "\n"
+ "`harn.toml` defines a `chat` model alias backed by Ollama's `llama3.2` model:\n"
+ "\n"
+ "```toml\n"
+ "[llm.aliases]\n"
+ "chat = { id = \"llama3.2\", provider = \"ollama\" }\n"
+ "```\n"
+ "\n"
+ "Edit that alias to use any configured provider, or set `HARN_CHAT_MODEL` when\n"
+ "running the project.\n"
+ "\n"
+ "## Run\n"
+ "\n"
+ "```bash\n"
+ "harn run main.harn\n"
+ "```\n"
+ "\n"
+ "Inside the chat loop, type `/clear` to reset local history and `/exit` to quit.\n"
return [["harn.toml", __chat_manifest(project_name)], ["main.harn", main_harn], ["README.md", readme]]
}
fn __mcp_files(project_name: string, harn_range: string) -> list {
let main_harn = "pipeline default(task) {\n"
+ " var tools = tool_registry()\n"
+ " tools = tool_define(tools, \"ping\", \"Return a pong response\", {\n"
+ " parameters: {\n"
+ " type: \"object\",\n"
+ " properties: {\n"
+ " message: {type: \"string\"}\n"
+ " },\n"
+ " required: [\"message\"]\n"
+ " },\n"
+ " returns: {\n"
+ " type: \"object\",\n"
+ " properties: {\n"
+ " message: {type: \"string\"},\n"
+ " echoed: {type: \"string\"}\n"
+ " }\n"
+ " },\n"
+ " handler: fn(args) {\n"
+ " return {\n"
+ " message: \"pong\",\n"
+ " echoed: args.message\n"
+ " }\n"
+ " }\n"
+ " })\n"
+ "\n"
+ " mcp_tools(tools)\n"
+ " mcp_resource({\n"
+ " uri: \"info://server\",\n"
+ " name: \"server-info\",\n"
+ " text: \"Harn MCP starter server\"\n"
+ " })\n"
+ "}\n"
return [["harn.toml", __basic_manifest(project_name)], ["main.harn", main_harn]]
}
fn __eval_files(project_name: string, harn_range: string) -> list {
let main_harn = "pipeline default(task) {\n"
+ " let input = \"hello world\"\n"
+ " let output = input.upper()\n"
+ " let passed = output == \"HELLO WORLD\"\n"
+ "\n"
+ " eval_metric(\"passed\", passed)\n"
+ " eval_metric(\"output_length\", len(output))\n"
+ "\n"
+ " log(json_stringify({\n"
+ " input: input,\n"
+ " output: output,\n"
+ " passed: passed\n"
+ " }))\n"
+ "}\n"
let test_harn = "pipeline test_eval_metrics(task) {\n"
+ " eval_metric(\"accuracy\", 1.0, {suite: \"smoke\"})\n"
+ " let metrics = eval_metrics()\n"
+ "\n"
+ " assert_eq(len(metrics), 1)\n"
+ " assert_eq(metrics[0].name, \"accuracy\")\n"
+ "}\n"
let suite = "{\n"
+ " \"_type\": \"eval_suite_manifest\",\n"
+ " \"id\": \"sample-suite\",\n"
+ " \"name\": \"Sample Eval Suite\",\n"
+ " \"base_dir\": \".\",\n"
+ " \"cases\": [\n"
+ " {\n"
+ " \"label\": \"replace-with-a-run-record\",\n"
+ " \"run_path\": \".harn-runs/sample-run.json\"\n"
+ " }\n"
+ " ]\n"
+ "}\n"
return [
["harn.toml", __basic_manifest(project_name)],
["main.harn", main_harn],
["tests/test_eval.harn", test_harn],
["eval-suite.json", suite],
]
}
fn __pipeline_lab_files(project_name: string, harn_range: string) -> list {
let host_harn = "pub fn build_context(task) {\n"
+ " return {\n"
+ " task: task,\n"
+ " cwd: cwd(),\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "pub fn request_permission(tool_name, request_args) -> bool {\n"
+ " return true\n"
+ "}\n"
let pipeline_harn = "pipeline default(task) {\n"
+ " let context = build_context(env_or(\"HARN_TASK\", \"\"))\n"
+ " let result = llm_call(\n"
+ " \"Task: \" + context.task + \"\\nWorkspace: \" + context.cwd,\n"
+ " \"You are a concise coding assistant. Reply in 3 bullets max.\",\n"
+ " )\n"
+ " log(result.text)\n"
+ "}\n"
let readme = "# Pipeline Lab\n"
+ "\n"
+ "Use this project to iterate on a Harn workflow against a local Harn-native host module.\n"
+ "\n"
+ "## Run\n"
+ "\n"
+ "```bash\n"
+ "harn playground --task \"Explain this repository\"\n"
+ "```\n"
+ "\n"
+ "## Watch mode\n"
+ "\n"
+ "```bash\n"
+ "harn playground --watch --task \"Tighten the workflow prompt\"\n"
+ "```\n"
+ "\n"
+ "Edit `host.harn` or `pipeline.harn` and the playground will re-run automatically.\n"
return [
["harn.toml", __basic_manifest(project_name)],
["host.harn", host_harn],
["pipeline.harn", pipeline_harn],
["README.md", readme],
]
}
fn __package_files(project_name: string, harn_range: string) -> list {
let lib_main = "/// Return a greeting for `name`.\n"
+ "pub fn greet(name: string) -> string {\n"
+ " return \"Hello, \" + name + \"!\"\n"
+ "}\n"
let main_harn = "import \"lib/main\"\n"
+ "\n"
+ "pipeline default(task) {\n"
+ " log(greet(\"world\"))\n"
+ "}\n"
let test_harn = "import \"../lib/main\"\n"
+ "\n"
+ "pipeline test_greet(task) {\n"
+ " assert_eq(greet(\"Harn\"), \"Hello, Harn!\")\n"
+ "}\n"
let workflow = "name: Harn package\n"
+ "\n"
+ "on:\n"
+ " pull_request:\n"
+ " push:\n"
+ " branches: [main]\n"
+ "\n"
+ "jobs:\n"
+ " package:\n"
+ " runs-on: ubuntu-latest\n"
+ " steps:\n"
+ " - uses: actions/checkout@v4\n"
+ " - uses: taiki-e/install-action@cargo-binstall\n"
+ " - run: cargo binstall harn-cli --no-confirm\n"
+ " - run: harn install --locked --offline || harn install\n"
+ " - run: harn test tests/\n"
+ " - run: harn package check\n"
+ " - run: harn package docs --check\n"
+ " - run: harn package pack --dry-run\n"
let readme = "# " + project_name + "\n"
+ "\n"
+ "Reusable Harn package.\n"
+ "\n"
+ "## Quickstart\n"
+ "\n"
+ "```bash\n"
+ "harn add ../"
+ project_name
+ "\n"
+ "harn test tests/\n"
+ "harn package check\n"
+ "harn package docs\n"
+ "harn package pack\n"
+ "```\n"
+ "\n"
+ "Consumers import stable modules through the `[exports]` entries in `harn.toml`.\n"
let docs = "# API Reference: " + project_name + "\n"
+ "\n"
+ "Generated by `harn package docs`.\n"
+ "\n"
+ "Version: `0.1.0`\n"
+ "\n"
+ "## Export `lib`\n"
+ "\n"
+ "`lib/main.harn`\n"
+ "\n"
+ "### fn `greet`\n"
+ "\n"
+ "Return a greeting for `name`.\n"
+ "\n"
+ "```harn\n"
+ "pub fn greet(name: string) -> string\n"
+ "```\n"
return [
["harn.toml", __package_manifest(project_name, harn_range)],
["lib/main.harn", lib_main],
["main.harn", main_harn],
["tests/test_main.harn", test_harn],
[".github/workflows/harn-package.yml", workflow],
["README.md", readme],
["LICENSE", "MIT OR Apache-2.0\n"],
["docs/api.md", docs],
]
}
fn __connector_files(project_name: string, harn_range: string) -> list {
let echo_harn = "/// Connector provider id.\n"
+ "pub fn provider_id() {\n"
+ " return \"echo\"\n"
+ "}\n"
+ "\n"
+ "/// Trigger kinds emitted by this connector.\n"
+ "pub fn kinds() {\n"
+ " return [\"webhook\"]\n"
+ "}\n"
+ "\n"
+ "/// JSON payload schema for normalized inbound events.\n"
+ "pub fn payload_schema() {\n"
+ " return {\n"
+ " harn_schema_name: \"EchoEventPayload\",\n"
+ " json_schema: {\n"
+ " type: \"object\",\n"
+ " additionalProperties: true,\n"
+ " },\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "/// Convert one inbound request into Harn trigger events.\n"
+ "pub fn normalize_inbound(raw) {\n"
+ " let body = raw.body_json ?? json_parse(raw.body_text)\n"
+ " return {\n"
+ " type: \"event\",\n"
+ " event: {\n"
+ " kind: \"webhook\",\n"
+ " dedupe_key: \"echo:\" + (body.message ?? \"message\"),\n"
+ " payload: body,\n"
+ " },\n"
+ " }\n"
+ "}\n"
let main_harn = "import \"connectors/echo\"\n"
+ "\n"
+ "pipeline default(task) {\n"
+ " log(provider_id())\n"
+ "}\n"
let test_harn = "import \"../connectors/echo\"\n"
+ "\n"
+ "pipeline test_provider_id(task) {\n"
+ " assert_eq(provider_id(), \"echo\")\n"
+ " assert_eq(kinds(), [\"webhook\"])\n"
+ "}\n"
let workflow = "name: Harn connector package\n"
+ "\n"
+ "on:\n"
+ " pull_request:\n"
+ " push:\n"
+ " branches: [main]\n"
+ "\n"
+ "jobs:\n"
+ " package:\n"
+ " runs-on: ubuntu-latest\n"
+ " steps:\n"
+ " - uses: actions/checkout@v4\n"
+ " - uses: taiki-e/install-action@cargo-binstall\n"
+ " - run: cargo binstall harn-cli --no-confirm\n"
+ " - run: harn install --locked --offline || harn install\n"
+ " - run: harn connector test .\n"
+ " - run: harn package check\n"
+ " - run: harn package docs --check\n"
+ " - run: harn package pack --dry-run\n"
let readme = "# " + project_name + "\n"
+ "\n"
+ "Pure-Harn connector package.\n"
+ "\n"
+ "## Quickstart\n"
+ "\n"
+ "```bash\n"
+ "harn connector test .\n"
+ "harn package check\n"
+ "harn package docs\n"
+ "harn package pack\n"
+ "```\n"
+ "\n"
+ "Consumers import the connector through the stable `[exports]` entry in `harn.toml`.\n"
let docs = "# API Reference: " + project_name + "\n"
+ "\n"
+ "Generated by `harn package docs`.\n"
+ "\n"
+ "Version: `0.1.0`\n"
+ "\n"
+ "## Export `connector`\n"
+ "\n"
+ "`connectors/echo.harn`\n"
+ "\n"
+ "### fn `provider_id`\n"
+ "\n"
+ "Connector provider id.\n"
+ "\n"
+ "```harn\n"
+ "pub fn provider_id()\n"
+ "```\n"
+ "\n"
+ "### fn `kinds`\n"
+ "\n"
+ "Trigger kinds emitted by this connector.\n"
+ "\n"
+ "```harn\n"
+ "pub fn kinds()\n"
+ "```\n"
+ "\n"
+ "### fn `payload_schema`\n"
+ "\n"
+ "JSON payload schema for normalized inbound events.\n"
+ "\n"
+ "```harn\n"
+ "pub fn payload_schema()\n"
+ "```\n"
+ "\n"
+ "### fn `normalize_inbound`\n"
+ "\n"
+ "Convert one inbound request into Harn trigger events.\n"
+ "\n"
+ "```harn\n"
+ "pub fn normalize_inbound(raw)\n"
+ "```\n"
return [
["harn.toml", __connector_manifest(project_name, harn_range)],
["connectors/echo.harn", echo_harn],
["main.harn", main_harn],
["tests/test_connector.harn", test_harn],
[".github/workflows/harn-package.yml", workflow],
["README.md", readme],
["LICENSE", "MIT OR Apache-2.0\n"],
["docs/api.md", docs],
]
}
fn __template_files(template: string, project_name: string, harn_range: string) -> list {
if template == "basic" {
return __basic_files(project_name, harn_range)
}
if template == "agent" {
return __agent_files(project_name, harn_range)
}
if template == "chat" {
return __chat_files(project_name, harn_range)
}
if template == "mcp-server" {
return __mcp_files(project_name, harn_range)
}
if template == "eval" {
return __eval_files(project_name, harn_range)
}
if template == "pipeline-lab" {
return __pipeline_lab_files(project_name, harn_range)
}
if template == "package" {
return __package_files(project_name, harn_range)
}
if template == "connector" {
return __connector_files(project_name, harn_range)
}
throw "unknown template: " + template
}
fn __write_if_new(harness: Harness, dir: string, rel: string, content: string) {
let path = path_join(dir, rel)
let parent = dirname(path)
if parent != "" && !harness.fs.exists(parent) {
try {
harness.fs.mkdir(parent)
} catch (e) {
harness.stdio.eprintln("Failed to create " + parent + ": " + to_string(e))
return
}
}
if harness.fs.exists(path) {
harness.stdio.println(" skip " + path + " (already exists)")
return
}
try {
harness.fs.write_text(path, content)
} catch (e) {
harness.stdio.eprintln("Failed to write " + path + ": " + to_string(e))
return
}
harness.stdio.println(" create " + path)
}
fn __print_next_steps(harness: Harness, name: string, template: string) {
harness.stdio.println("")
if name != "" {
harness.stdio.println(" cd " + name)
}
if template == "chat" {
harness.stdio.println(" harn run main.harn # run the program")
} else if template == "mcp-server" {
harness.stdio.println(" harn serve mcp main.harn # expose the starter MCP server")
} else if template == "pipeline-lab" {
harness.stdio.println(" harn playground --task \"Explain this repo\" # run the lab")
harness.stdio
.println(" harn playground --watch --task \"Refine the prompt\" # live iteration")
} else {
// basic | agent | eval | package | connector
harness.stdio.println(" harn run main.harn # run the program")
harness.stdio.println(" harn test tests/ # run the tests")
}
harness.stdio.println(" harn fmt main.harn # format code")
harness.stdio.println(" harn lint main.harn # lint code")
if template == "package" || template == "connector" {
harness.stdio.println(" harn package check # validate publish readiness")
harness.stdio.println(" harn package docs # generate API docs")
harness.stdio.println(" harn package pack # build an inspectable artifact")
}
harness.stdio.println(" harn doctor # verify the local environment")
}
fn main(harness: Harness) {
let name = harness.env.get_or("HARN_INIT_NAME", "")
let project_name = harness.env.get_or("HARN_INIT_PROJECT_NAME", "my-project")
let dir = harness.env.get_or("HARN_INIT_DIR", "")
let template = harness.env.get_or("HARN_INIT_TEMPLATE", "basic")
let harn_range = harness.env.get_or("HARN_INIT_HARN_RANGE", "")
if dir == "" || harn_range == "" {
harness.stdio
.eprintln("init: HARN_INIT_DIR and HARN_INIT_HARN_RANGE must be set")
exit(2)
}
if name != "" {
harness.stdio.println("Creating project '" + name + "'...")
} else {
harness.stdio.println("Initializing harn project in current directory...")
}
let files = try {
__template_files(template, project_name, harn_range)
} catch (e) {
harness.stdio.eprintln(to_string(e))
exit(2)
}
for entry in files {
__write_if_new(harness, dir, entry[0], entry[1])
}
__print_next_steps(harness, name, template)
}