fix(wt): resolve type checker warnings

Amolith created

- Add GlobalConfig type annotation in config.lua with typed fields
- Type remotes values as string? to allow nil lookups
- Replace local aliases with direct module exports in main.lua
- Suppress duplicate-set-field for test API re-exports
- Suppress unnecessary-if for union type discrimination
- Use explicit if-narrowing for global_config.remotes

Assisted-by: Claude Opus 4.5 via Amp

Change summary

dist/wt              | 247 +++++++++++++++++++++------------------------
src/main.lua         | 104 +++++-------------
src/wt/cmd/clone.lua |  97 ++++++++++-------
src/wt/cmd/new.lua   |  38 ++++--
src/wt/config.lua    |   8 +
5 files changed, 230 insertions(+), 264 deletions(-)

Detailed changes

dist/wt 🔗

@@ -417,6 +417,12 @@ _EMBEDDED_MODULES["wt.config"] = [[-- SPDX-FileCopyrightText: Amolith <amolith@s
 --
 -- SPDX-License-Identifier: GPL-3.0-or-later
 
+---@class wt.GlobalConfig
+---@field remotes? table<string, string?>
+---@field default_remotes? string[]|"prompt"
+---@field branch_path_style? string
+---@field flat_separator? string
+
 ---@class wt.config
 local M = {}
 
@@ -461,7 +467,7 @@ function M.extract_project_name(url)
 end
 
 ---Load global config from ~/.config/wt/config.lua
----@return table
+---@return wt.GlobalConfig
 function M.load_global_config()
 	local home = os.getenv("HOME")
 	if not home then
@@ -959,6 +965,7 @@ function M.cmd_clone(args)
 	elseif global_config.default_remotes then
 		if type(global_config.default_remotes) == "table" then
 			selected_remotes = global_config.default_remotes --[[@as string[] ]]
+		---@diagnostic disable-next-line: unnecessary-if
 		elseif global_config.default_remotes == "prompt" then
 			if global_config.remotes then
 				local keys = {}
@@ -1025,32 +1032,39 @@ function M.cmd_clone(args)
 			end
 
 			-- Add additional remotes and push to them
+			local remotes = global_config.remotes
 			for j = 2, #selected_remotes do
 				local remote_name = selected_remotes[j]
-				local template = global_config.remotes and global_config.remotes[remote_name]
-				if template then
-					local remote_url = config.resolve_url_template(template, project_name)
-					output, code =
-						shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url)
-					if code ~= 0 then
-						io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
-					else
-						shell.run_cmd(
-							"GIT_DIR="
-								.. git_dir
-								.. " git config remote."
-								.. remote_name
-								.. ".fetch '+refs/heads/*:refs/remotes/"
-								.. remote_name
-								.. "/*'"
+				if remotes then
+					local template = remotes[remote_name]
+					if template then
+						local remote_url = config.resolve_url_template(template, project_name)
+						output, code = shell.run_cmd(
+							"GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url
 						)
-						-- Push to additional remotes
-						output, code =
-							shell.run_cmd("GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch)
 						if code ~= 0 then
-							io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+							io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+						else
+							shell.run_cmd(
+								"GIT_DIR="
+									.. git_dir
+									.. " git config remote."
+									.. remote_name
+									.. ".fetch '+refs/heads/*:refs/remotes/"
+									.. remote_name
+									.. "/*'"
+							)
+							-- Push to additional remotes
+							output, code = shell.run_cmd(
+								"GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch
+							)
+							if code ~= 0 then
+								io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+							end
+							table.insert(configured_remotes, remote_name)
 						end
-						table.insert(configured_remotes, remote_name)
+					else
+						io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
 					end
 				else
 					io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
@@ -1077,31 +1091,36 @@ function M.cmd_clone(args)
 		end
 
 		-- Add user's remotes and push to each
+		local remotes = global_config.remotes
 		for _, remote_name in ipairs(selected_remotes) do
-			local template = global_config.remotes and global_config.remotes[remote_name]
-			if template then
-				local remote_url = config.resolve_url_template(template, project_name)
-				output, code =
-					shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url)
-				if code ~= 0 then
-					io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
-				else
-					shell.run_cmd(
-						"GIT_DIR="
-							.. git_dir
-							.. " git config remote."
-							.. remote_name
-							.. ".fetch '+refs/heads/*:refs/remotes/"
-							.. remote_name
-							.. "/*'"
-					)
-					-- Push to this remote
+			if remotes then
+				local template = remotes[remote_name]
+				if template then
+					local remote_url = config.resolve_url_template(template, project_name)
 					output, code =
-						shell.run_cmd("GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch)
+						shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url)
 					if code ~= 0 then
-						io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+						io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+					else
+						shell.run_cmd(
+							"GIT_DIR="
+								.. git_dir
+								.. " git config remote."
+								.. remote_name
+								.. ".fetch '+refs/heads/*:refs/remotes/"
+								.. remote_name
+								.. "/*'"
+						)
+						-- Push to this remote
+						output, code =
+							shell.run_cmd("GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch)
+						if code ~= 0 then
+							io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+						end
+						table.insert(configured_remotes, remote_name)
 					end
-					table.insert(configured_remotes, remote_name)
+				else
+					io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
 				end
 			else
 				io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
@@ -1205,6 +1224,7 @@ function M.cmd_new(args)
 	elseif global_config.default_remotes then
 		if type(global_config.default_remotes) == "table" then
 			selected_remotes = global_config.default_remotes --[[@as string[] ]]
+		---@diagnostic disable-next-line: unnecessary-if
 		elseif global_config.default_remotes == "prompt" then
 			-- Prompt with gum choose
 			if global_config.remotes then
@@ -1267,24 +1287,29 @@ function M.cmd_new(args)
 
 	-- Add remotes
 	local git_dir = bare_path
+	local remotes = global_config.remotes
 	for _, remote_name in ipairs(selected_remotes) do
-		local template = global_config.remotes and global_config.remotes[remote_name]
-		if template then
-			local url = config.resolve_url_template(template, project_name)
-			output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. url)
-			if code ~= 0 then
-				io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+		if remotes then
+			local template = remotes[remote_name]
+			if template then
+				local url = config.resolve_url_template(template, project_name)
+				output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. url)
+				if code ~= 0 then
+					io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+				else
+					-- Configure fetch refspec for the remote
+					shell.run_cmd(
+						"GIT_DIR="
+							.. git_dir
+							.. " git config remote."
+							.. remote_name
+							.. ".fetch '+refs/heads/*:refs/remotes/"
+							.. remote_name
+							.. "/*'"
+					)
+				end
 			else
-				-- Configure fetch refspec for the remote
-				shell.run_cmd(
-					"GIT_DIR="
-						.. git_dir
-						.. " git config remote."
-						.. remote_name
-						.. ".fetch '+refs/heads/*:refs/remotes/"
-						.. remote_name
-						.. "/*'"
-				)
+				io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
 			end
 		else
 			io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
@@ -1964,62 +1989,19 @@ if _VERSION < "Lua 5.2" then
 end
 
 local exit = require("wt.exit")
-local EXIT_SUCCESS = exit.EXIT_SUCCESS
-
 local shell = require("wt.shell")
-local run_cmd = shell.run_cmd
-local run_cmd_silent = shell.run_cmd_silent
-local die = shell.die
-
 local path_mod = require("wt.path")
-local branch_to_path = path_mod.branch_to_path
-local split_path = path_mod.split_path
-local relative_path = path_mod.relative_path
-local path_inside = path_mod.path_inside
-local escape_pattern = path_mod.escape_pattern
-
 local git_mod = require("wt.git")
-local find_project_root = git_mod.find_project_root
-local detect_source_worktree = git_mod.detect_source_worktree
-local parse_branch_remotes = git_mod.parse_branch_remotes
-local parse_worktree_list = git_mod.parse_worktree_list
-
 local config_mod = require("wt.config")
-local resolve_url_template = config_mod.resolve_url_template
-local extract_project_name = config_mod.extract_project_name
-local load_global_config = config_mod.load_global_config
-local load_project_config = config_mod.load_project_config
-
 local hooks_mod = require("wt.hooks")
-local load_hook_permissions = hooks_mod.load_hook_permissions
-local save_hook_permissions = hooks_mod.save_hook_permissions
-local summarize_hooks = hooks_mod.summarize_hooks
-local run_hooks = hooks_mod.run_hooks
-
 local help_mod = require("wt.help")
-local print_usage = help_mod.print_usage
-local show_command_help = help_mod.show_command_help
-
 local fetch_mod = require("wt.cmd.fetch")
-local cmd_fetch = fetch_mod.cmd_fetch
-
 local list_mod = require("wt.cmd.list")
-local cmd_list = list_mod.cmd_list
-
 local remove_mod = require("wt.cmd.remove")
-local cmd_remove = remove_mod.cmd_remove
-
 local add_mod = require("wt.cmd.add")
-local cmd_add = add_mod.cmd_add
-
 local new_mod = require("wt.cmd.new")
-local cmd_new = new_mod.cmd_new
-
 local clone_mod = require("wt.cmd.clone")
-local cmd_clone = clone_mod.cmd_clone
-
 local init_mod = require("wt.cmd.init")
-local cmd_init = init_mod.cmd_init
 
 -- Main entry point
 
@@ -2027,8 +2009,8 @@ local function main()
 	local command = arg[1]
 
 	if not command or command == "help" or command == "--help" or command == "-h" then
-		print_usage()
-		os.exit(EXIT_SUCCESS)
+		help_mod.print_usage()
+		os.exit(exit.EXIT_SUCCESS)
 	end
 
 	---@cast command string
@@ -2041,57 +2023,58 @@ local function main()
 
 	-- Check for --help on any command
 	if subargs[1] == "--help" or subargs[1] == "-h" then
-		show_command_help(command)
+		help_mod.show_command_help(command)
 	end
 
 	if command == "c" then
-		cmd_clone(subargs)
+		clone_mod.cmd_clone(subargs)
 	elseif command == "n" then
-		cmd_new(subargs)
+		new_mod.cmd_new(subargs)
 	elseif command == "a" then
-		cmd_add(subargs)
+		add_mod.cmd_add(subargs)
 	elseif command == "r" then
-		cmd_remove(subargs)
+		remove_mod.cmd_remove(subargs)
 	elseif command == "l" then
-		cmd_list()
+		list_mod.cmd_list()
 	elseif command == "f" then
-		cmd_fetch()
+		fetch_mod.cmd_fetch()
 	elseif command == "init" then
-		cmd_init(subargs)
+		init_mod.cmd_init(subargs)
 	else
-		die("unknown command: " .. command)
+		shell.die("unknown command: " .. command)
 	end
 end
 
 -- Export for testing when required as module
 if pcall(debug.getlocal, 4, 1) then
+	---@diagnostic disable: duplicate-set-field
 	return {
 		-- URL/project parsing
-		extract_project_name = extract_project_name,
-		resolve_url_template = resolve_url_template,
+		extract_project_name = config_mod.extract_project_name,
+		resolve_url_template = config_mod.resolve_url_template,
 		-- Path manipulation
-		branch_to_path = branch_to_path,
-		split_path = split_path,
-		relative_path = relative_path,
-		path_inside = path_inside,
+		branch_to_path = path_mod.branch_to_path,
+		split_path = path_mod.split_path,
+		relative_path = path_mod.relative_path,
+		path_inside = path_mod.path_inside,
 		-- Config loading
-		load_global_config = load_global_config,
-		load_project_config = load_project_config,
+		load_global_config = config_mod.load_global_config,
+		load_project_config = config_mod.load_project_config,
 		-- Git output parsing (testable without git)
-		parse_branch_remotes = parse_branch_remotes,
-		parse_worktree_list = parse_worktree_list,
-		escape_pattern = escape_pattern,
+		parse_branch_remotes = git_mod.parse_branch_remotes,
+		parse_worktree_list = git_mod.parse_worktree_list,
+		escape_pattern = path_mod.escape_pattern,
 		-- Hook helpers (re-exported from wt.hooks)
-		summarize_hooks = summarize_hooks,
-		load_hook_permissions = load_hook_permissions,
-		save_hook_permissions = save_hook_permissions,
-		run_hooks = run_hooks,
+		summarize_hooks = hooks_mod.summarize_hooks,
+		load_hook_permissions = hooks_mod.load_hook_permissions,
+		save_hook_permissions = hooks_mod.save_hook_permissions,
+		run_hooks = hooks_mod.run_hooks,
 		-- Project root detection (re-exported from wt.git)
-		find_project_root = find_project_root,
-		detect_source_worktree = detect_source_worktree,
+		find_project_root = git_mod.find_project_root,
+		detect_source_worktree = git_mod.detect_source_worktree,
 		-- Command execution (for integration tests)
-		run_cmd = run_cmd,
-		run_cmd_silent = run_cmd_silent,
+		run_cmd = shell.run_cmd,
+		run_cmd_silent = shell.run_cmd_silent,
 		-- Exit codes (re-exported from wt.exit)
 		EXIT_SUCCESS = exit.EXIT_SUCCESS,
 		EXIT_USER_ERROR = exit.EXIT_USER_ERROR,

src/main.lua 🔗

@@ -10,62 +10,19 @@ if _VERSION < "Lua 5.2" then
 end
 
 local exit = require("wt.exit")
-local EXIT_SUCCESS = exit.EXIT_SUCCESS
-
 local shell = require("wt.shell")
-local run_cmd = shell.run_cmd
-local run_cmd_silent = shell.run_cmd_silent
-local die = shell.die
-
 local path_mod = require("wt.path")
-local branch_to_path = path_mod.branch_to_path
-local split_path = path_mod.split_path
-local relative_path = path_mod.relative_path
-local path_inside = path_mod.path_inside
-local escape_pattern = path_mod.escape_pattern
-
 local git_mod = require("wt.git")
-local find_project_root = git_mod.find_project_root
-local detect_source_worktree = git_mod.detect_source_worktree
-local parse_branch_remotes = git_mod.parse_branch_remotes
-local parse_worktree_list = git_mod.parse_worktree_list
-
 local config_mod = require("wt.config")
-local resolve_url_template = config_mod.resolve_url_template
-local extract_project_name = config_mod.extract_project_name
-local load_global_config = config_mod.load_global_config
-local load_project_config = config_mod.load_project_config
-
 local hooks_mod = require("wt.hooks")
-local load_hook_permissions = hooks_mod.load_hook_permissions
-local save_hook_permissions = hooks_mod.save_hook_permissions
-local summarize_hooks = hooks_mod.summarize_hooks
-local run_hooks = hooks_mod.run_hooks
-
 local help_mod = require("wt.help")
-local print_usage = help_mod.print_usage
-local show_command_help = help_mod.show_command_help
-
 local fetch_mod = require("wt.cmd.fetch")
-local cmd_fetch = fetch_mod.cmd_fetch
-
 local list_mod = require("wt.cmd.list")
-local cmd_list = list_mod.cmd_list
-
 local remove_mod = require("wt.cmd.remove")
-local cmd_remove = remove_mod.cmd_remove
-
 local add_mod = require("wt.cmd.add")
-local cmd_add = add_mod.cmd_add
-
 local new_mod = require("wt.cmd.new")
-local cmd_new = new_mod.cmd_new
-
 local clone_mod = require("wt.cmd.clone")
-local cmd_clone = clone_mod.cmd_clone
-
 local init_mod = require("wt.cmd.init")
-local cmd_init = init_mod.cmd_init
 
 -- Main entry point
 
@@ -73,8 +30,8 @@ local function main()
 	local command = arg[1]
 
 	if not command or command == "help" or command == "--help" or command == "-h" then
-		print_usage()
-		os.exit(EXIT_SUCCESS)
+		help_mod.print_usage()
+		os.exit(exit.EXIT_SUCCESS)
 	end
 
 	---@cast command string
@@ -87,57 +44,58 @@ local function main()
 
 	-- Check for --help on any command
 	if subargs[1] == "--help" or subargs[1] == "-h" then
-		show_command_help(command)
+		help_mod.show_command_help(command)
 	end
 
 	if command == "c" then
-		cmd_clone(subargs)
+		clone_mod.cmd_clone(subargs)
 	elseif command == "n" then
-		cmd_new(subargs)
+		new_mod.cmd_new(subargs)
 	elseif command == "a" then
-		cmd_add(subargs)
+		add_mod.cmd_add(subargs)
 	elseif command == "r" then
-		cmd_remove(subargs)
+		remove_mod.cmd_remove(subargs)
 	elseif command == "l" then
-		cmd_list()
+		list_mod.cmd_list()
 	elseif command == "f" then
-		cmd_fetch()
+		fetch_mod.cmd_fetch()
 	elseif command == "init" then
-		cmd_init(subargs)
+		init_mod.cmd_init(subargs)
 	else
-		die("unknown command: " .. command)
+		shell.die("unknown command: " .. command)
 	end
 end
 
 -- Export for testing when required as module
 if pcall(debug.getlocal, 4, 1) then
+	---@diagnostic disable: duplicate-set-field
 	return {
 		-- URL/project parsing
-		extract_project_name = extract_project_name,
-		resolve_url_template = resolve_url_template,
+		extract_project_name = config_mod.extract_project_name,
+		resolve_url_template = config_mod.resolve_url_template,
 		-- Path manipulation
-		branch_to_path = branch_to_path,
-		split_path = split_path,
-		relative_path = relative_path,
-		path_inside = path_inside,
+		branch_to_path = path_mod.branch_to_path,
+		split_path = path_mod.split_path,
+		relative_path = path_mod.relative_path,
+		path_inside = path_mod.path_inside,
 		-- Config loading
-		load_global_config = load_global_config,
-		load_project_config = load_project_config,
+		load_global_config = config_mod.load_global_config,
+		load_project_config = config_mod.load_project_config,
 		-- Git output parsing (testable without git)
-		parse_branch_remotes = parse_branch_remotes,
-		parse_worktree_list = parse_worktree_list,
-		escape_pattern = escape_pattern,
+		parse_branch_remotes = git_mod.parse_branch_remotes,
+		parse_worktree_list = git_mod.parse_worktree_list,
+		escape_pattern = path_mod.escape_pattern,
 		-- Hook helpers (re-exported from wt.hooks)
-		summarize_hooks = summarize_hooks,
-		load_hook_permissions = load_hook_permissions,
-		save_hook_permissions = save_hook_permissions,
-		run_hooks = run_hooks,
+		summarize_hooks = hooks_mod.summarize_hooks,
+		load_hook_permissions = hooks_mod.load_hook_permissions,
+		save_hook_permissions = hooks_mod.save_hook_permissions,
+		run_hooks = hooks_mod.run_hooks,
 		-- Project root detection (re-exported from wt.git)
-		find_project_root = find_project_root,
-		detect_source_worktree = detect_source_worktree,
+		find_project_root = git_mod.find_project_root,
+		detect_source_worktree = git_mod.detect_source_worktree,
 		-- Command execution (for integration tests)
-		run_cmd = run_cmd,
-		run_cmd_silent = run_cmd_silent,
+		run_cmd = shell.run_cmd,
+		run_cmd_silent = shell.run_cmd_silent,
 		-- Exit codes (re-exported from wt.exit)
 		EXIT_SUCCESS = exit.EXIT_SUCCESS,
 		EXIT_USER_ERROR = exit.EXIT_USER_ERROR,

src/wt/cmd/clone.lua 🔗

@@ -96,6 +96,7 @@ function M.cmd_clone(args)
 	elseif global_config.default_remotes then
 		if type(global_config.default_remotes) == "table" then
 			selected_remotes = global_config.default_remotes --[[@as string[] ]]
+		---@diagnostic disable-next-line: unnecessary-if
 		elseif global_config.default_remotes == "prompt" then
 			if global_config.remotes then
 				local keys = {}
@@ -162,32 +163,39 @@ function M.cmd_clone(args)
 			end
 
 			-- Add additional remotes and push to them
+			local remotes = global_config.remotes
 			for j = 2, #selected_remotes do
 				local remote_name = selected_remotes[j]
-				local template = global_config.remotes and global_config.remotes[remote_name]
-				if template then
-					local remote_url = config.resolve_url_template(template, project_name)
-					output, code =
-						shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url)
-					if code ~= 0 then
-						io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
-					else
-						shell.run_cmd(
-							"GIT_DIR="
-								.. git_dir
-								.. " git config remote."
-								.. remote_name
-								.. ".fetch '+refs/heads/*:refs/remotes/"
-								.. remote_name
-								.. "/*'"
+				if remotes then
+					local template = remotes[remote_name]
+					if template then
+						local remote_url = config.resolve_url_template(template, project_name)
+						output, code = shell.run_cmd(
+							"GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url
 						)
-						-- Push to additional remotes
-						output, code =
-							shell.run_cmd("GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch)
 						if code ~= 0 then
-							io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+							io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+						else
+							shell.run_cmd(
+								"GIT_DIR="
+									.. git_dir
+									.. " git config remote."
+									.. remote_name
+									.. ".fetch '+refs/heads/*:refs/remotes/"
+									.. remote_name
+									.. "/*'"
+							)
+							-- Push to additional remotes
+							output, code = shell.run_cmd(
+								"GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch
+							)
+							if code ~= 0 then
+								io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+							end
+							table.insert(configured_remotes, remote_name)
 						end
-						table.insert(configured_remotes, remote_name)
+					else
+						io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
 					end
 				else
 					io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
@@ -214,31 +222,36 @@ function M.cmd_clone(args)
 		end
 
 		-- Add user's remotes and push to each
+		local remotes = global_config.remotes
 		for _, remote_name in ipairs(selected_remotes) do
-			local template = global_config.remotes and global_config.remotes[remote_name]
-			if template then
-				local remote_url = config.resolve_url_template(template, project_name)
-				output, code =
-					shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url)
-				if code ~= 0 then
-					io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
-				else
-					shell.run_cmd(
-						"GIT_DIR="
-							.. git_dir
-							.. " git config remote."
-							.. remote_name
-							.. ".fetch '+refs/heads/*:refs/remotes/"
-							.. remote_name
-							.. "/*'"
-					)
-					-- Push to this remote
+			if remotes then
+				local template = remotes[remote_name]
+				if template then
+					local remote_url = config.resolve_url_template(template, project_name)
 					output, code =
-						shell.run_cmd("GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch)
+						shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. remote_url)
 					if code ~= 0 then
-						io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+						io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+					else
+						shell.run_cmd(
+							"GIT_DIR="
+								.. git_dir
+								.. " git config remote."
+								.. remote_name
+								.. ".fetch '+refs/heads/*:refs/remotes/"
+								.. remote_name
+								.. "/*'"
+						)
+						-- Push to this remote
+						output, code =
+							shell.run_cmd("GIT_DIR=" .. git_dir .. " git push " .. remote_name .. " " .. default_branch)
+						if code ~= 0 then
+							io.stderr:write("warning: failed to push to " .. remote_name .. ": " .. output .. "\n")
+						end
+						table.insert(configured_remotes, remote_name)
 					end
-					table.insert(configured_remotes, remote_name)
+				else
+					io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
 				end
 			else
 				io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")

src/wt/cmd/new.lua 🔗

@@ -67,6 +67,7 @@ function M.cmd_new(args)
 	elseif global_config.default_remotes then
 		if type(global_config.default_remotes) == "table" then
 			selected_remotes = global_config.default_remotes --[[@as string[] ]]
+		---@diagnostic disable-next-line: unnecessary-if
 		elseif global_config.default_remotes == "prompt" then
 			-- Prompt with gum choose
 			if global_config.remotes then
@@ -129,24 +130,29 @@ function M.cmd_new(args)
 
 	-- Add remotes
 	local git_dir = bare_path
+	local remotes = global_config.remotes
 	for _, remote_name in ipairs(selected_remotes) do
-		local template = global_config.remotes and global_config.remotes[remote_name]
-		if template then
-			local url = config.resolve_url_template(template, project_name)
-			output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. url)
-			if code ~= 0 then
-				io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+		if remotes then
+			local template = remotes[remote_name]
+			if template then
+				local url = config.resolve_url_template(template, project_name)
+				output, code = shell.run_cmd("GIT_DIR=" .. git_dir .. " git remote add " .. remote_name .. " " .. url)
+				if code ~= 0 then
+					io.stderr:write("warning: failed to add remote '" .. remote_name .. "': " .. output .. "\n")
+				else
+					-- Configure fetch refspec for the remote
+					shell.run_cmd(
+						"GIT_DIR="
+							.. git_dir
+							.. " git config remote."
+							.. remote_name
+							.. ".fetch '+refs/heads/*:refs/remotes/"
+							.. remote_name
+							.. "/*'"
+					)
+				end
 			else
-				-- Configure fetch refspec for the remote
-				shell.run_cmd(
-					"GIT_DIR="
-						.. git_dir
-						.. " git config remote."
-						.. remote_name
-						.. ".fetch '+refs/heads/*:refs/remotes/"
-						.. remote_name
-						.. "/*'"
-				)
+				io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")
 			end
 		else
 			io.stderr:write("warning: remote '" .. remote_name .. "' not found in config\n")

src/wt/config.lua 🔗

@@ -2,6 +2,12 @@
 --
 -- SPDX-License-Identifier: GPL-3.0-or-later
 
+---@class wt.GlobalConfig
+---@field remotes? table<string, string?>
+---@field default_remotes? string[]|"prompt"
+---@field branch_path_style? string
+---@field flat_separator? string
+
 ---@class wt.config
 local M = {}
 
@@ -46,7 +52,7 @@ function M.extract_project_name(url)
 end
 
 ---Load global config from ~/.config/wt/config.lua
----@return table
+---@return wt.GlobalConfig
 function M.load_global_config()
 	local home = os.getenv("HOME")
 	if not home then