From 1beefefc69beee214430eb5bd2528a4f5692d2a8 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 1 Jun 2026 08:21:00 -0600 Subject: Rename system extension layer to base for clarity Replace all references to the "system" layer with "base" to better reflect its role as the foundational extension/tool layer in panto's hierarchy. The layer hierarchy now consistently uses: project > user > base. Includes: - Update agent README and build.zig documentation - Refactor tool registry and config module to support layered lookups - Add TestHarness abstraction for cleaner test setup - Improve JSON serialization with wire-encoded tool names - Add glob pattern matching for tool/extension discovery --- src/luarocks_runtime.zig | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'src/luarocks_runtime.zig') diff --git a/src/luarocks_runtime.zig b/src/luarocks_runtime.zig index 0114b64..e652096 100644 --- a/src/luarocks_runtime.zig +++ b/src/luarocks_runtime.zig @@ -137,6 +137,7 @@ pub fn bootstrap( try panto_home.ensureDirsExist(layout, io); try stageLuaHeaders(allocator, io, layout); try stageAgentTree(allocator, io, layout); + try stageDefaultConfig(allocator, io, layout); const lua_wrapper_path = try writeLuaWrapper(allocator, io, layout, panto_executable_path); defer allocator.free(lua_wrapper_path); try writeLuarocksConfig(allocator, io, layout, lua_wrapper_path); @@ -236,6 +237,71 @@ fn stageAgentTree( } } +/// The default base `config.toml`, materialized at `$PANTO_HOME/config.toml` +/// on first run if absent. It declares OpenAI and Anthropic providers whose +/// API keys come from the conventional env vars — so a provider simply +/// doesn't appear unless its key is exported. Edit or override at the user +/// (`~/.config/panto/config.toml`) or project (`./.panto/config.toml`) layer. +const default_base_config = + \\# panto base config (auto-generated on first run). + \\# + \\# This is the lowest-precedence layer. Override anything here from + \\# ~/.config/panto/config.toml (user) + \\# ./.panto/config.toml (project) + \\# Tables merge across layers; scalars and arrays from a higher layer + \\# replace the lower one wholesale. + \\# + \\# A provider whose API key (or its api_key_env_var) is missing at + \\# runtime is silently dropped — so these defaults disappear unless + \\# you've exported the corresponding key. + \\ + \\[providers.openai] + \\style = "openai_chat" + \\base_url = "https://api.openai.com/v1" + \\api_key_env_var = "OPENAI_API_KEY" + \\ + \\[providers.anthropic] + \\style = "anthropic_messages" + \\base_url = "https://api.anthropic.com" + \\api_key_env_var = "ANTHROPIC_API_KEY" + \\ + \\# Pick the default model with `:`. The alias is + \\# resolved against models.toml; an unknown alias is used verbatim as + \\# the wire model name. + \\# + \\# [defaults] + \\# model = "anthropic:claude-sonnet-4-20250514" + \\ + \\# Tool/extension availability (glob patterns). Empty allow = allow all. + \\# [tools] + \\# allow = ["std.*"] + \\# deny = [] + \\ +; + +/// Materialize the default base config at `$PANTO_HOME/config.toml`, +/// but only if no file exists there yet. We never overwrite — the base +/// config is user-editable, and a stale-but-edited file must win over the +/// shipped default. +fn stageDefaultConfig( + allocator: Allocator, + io: Io, + layout: panto_home.Layout, +) !void { + _ = allocator; + var home = try Io.Dir.cwd().openDir(io, layout.home, .{}); + defer home.close(io); + + home.access(io, "config.toml", .{}) catch |err| switch (err) { + error.FileNotFound => { + try home.writeFile(io, .{ .sub_path = "config.toml", .data = default_base_config }); + return; + }, + else => return err, + }; + // Exists already — leave it untouched. +} + /// Write `contents` into `dir/name` only if the existing file differs. /// Creates the file if absent. fn writeIfDifferent( -- cgit v1.3