From b3666c655a4f39d4aa0431a55bf83571f445af06 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Sat, 1 Aug 2026 23:18:20 +1000 Subject: [PATCH] Build outputs: thin-layout make.tcl sync (help command-line refinement) Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com --- .../vendor/punk/project-0.1/src/make.tcl | 116 ++++++++++-------- .../vendor/punk/basic/src/make.tcl | 116 ++++++++++-------- .../vendor/punk/project-0.1/src/make.tcl | 116 ++++++++++-------- 3 files changed, 189 insertions(+), 159 deletions(-) diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl index 49d50aec..4fce9524 100644 --- a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl +++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl @@ -2618,10 +2618,10 @@ proc ::punkboot::punkboot_gethelp {args} { append h " test suites, or build (test-gated) and install to /bin; options precede the tool names" \n append h " - zig is OPTIONAL: packages/bake never require this step; without a suitable toolchain the state is" \n append h " reported and build/test exit nonzero with fetch guidance (bin/punk-getzig.cmd)" \n \n - append h " $scriptname help ?subcommand? ?action?" \n + append h " $scriptname help ?subcommand? ?arg ...?" \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname -help);" \n - append h " with an action word or 0-based form index, that action's single-form usage when the tabled help" \n - append h " is available" \n \n + append h " extra words are the subcommand's own command line - a leading action word narrows the multi-form" \n + append h " subcommands (tool, buildsuite) to that action's usage when the tabled help is available" \n \n append h " Flags:" \n append h " -confirm 0|1" \n append h " - interactive y/n confirmation policy (default 1: prompt when stdin is a terminal, abort fast when it is not)." \n @@ -3239,11 +3239,14 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO help " Show tabled usage for make.tcl as a whole, or for a single subcommand. - Equivalent to 'make.tcl -help'. For the multi-form - subcommands (tool, buildsuite) an action word - or the 0-based form - index the synopsis hints display - narrows to that action's - single-form usage: 'make.tcl help tool build', 'make.tcl help tool 2' - and 'make.tcl tool build -help' all render the build form." + After the subject, accepts that subcommand's own command line and + shows the usage most specific to it: for the multi-form subcommands + (tool, buildsuite) the leading action word narrows to that action's + single-form usage - 'make.tcl help tool build -test 0 punkzip' shows + the tool build form, as does appending -help to the command line + itself ('make.tcl tool build -test 0 punkzip -help'). Words after + the action are tolerated and ignored; an option-first line shows + the whole subcommand's usage." buildsuite " Surface for the defined buildsuites under src/buildsuites (zig-built @@ -3678,13 +3681,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO -summary "${[dict get $SUMMARIES help]}" -& -help -& {${[dict get $HELPTEXTS help]}} - @values -min 1 -max 2 + @values -min 1 -max -1 subject -type string -optional 0 -& -choices {${[dict keys $SUMMARIES]}} -& -help "Subcommand to show usage for." - action -type string -optional 1 -help -& - "Action word (or 0-based form index) of a multi-form subcommand - (tool, buildsuite) - shows that action's single-form usage." + arg -type any -optional 1 -multiple 1 -help -& + "The subject's own arguments, as they would be typed. For a + multi-form subcommand (tool, buildsuite) a leading action word + narrows to that action's single-form usage; everything after + it is tolerated and ignored." } #top-level definition: the subcommand table rendered by 'make.tcl' / 'make.tcl -help' variable SUBGROUPS { @@ -3705,11 +3710,13 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO 'bin' and 'modules' folders at the same level as 'src'. General usage: make.tcl ?flags? - 'make.tcl help ?action?' or 'make.tcl ?action? -help' - shows a subcommand's own usage (a single action's usage for the - multi-form tool/buildsuite subcommands). Interactive y/n - confirmations can be driven non-interactively with the -confirm - flag declared on the relevant subcommands.} + 'make.tcl help ?arg ...?' or 'make.tcl + ?arg ...? -help' shows a subcommand's own usage - the words are the + subcommand's own command line, and for the multi-form + tool/buildsuite subcommands a leading action word narrows to that + action's usage. Interactive y/n confirmations can be driven + non-interactively with the -confirm flag declared on the relevant + subcommands.} punk::args::define { @id -id "(script)::punkboot" @cmd -name "make.tcl" -& @@ -3754,7 +3761,7 @@ if {$::punkboot::punkargs_ok && [package provide punk::ansi] ne "" && [package p set do_help 0 set help_subject "" -set help_action "" +set help_words [list] set help_exitcode 0 #defaults for the option-derived variables (fallback scan and passthrough subcommands rely on these) set ::punkboot::opt_forcekill 0 @@ -3785,30 +3792,29 @@ if {$::punkboot::punkargs_ok} { if {$subcommand eq "help"} { set do_help 1 if {[llength $subargs]} { - if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { + #validate/resolve ONLY the subject word through the help definition + #(choices table + unambiguous prefixes). The tail is the subject's + #own command line as the user would type it - deliberately NOT + #parsed here: it may be any mix of that subcommand's actions, + #options and values, including incomplete or wrong ones, which is + #precisely when help is wanted (G-143 refinement 2026-08-01). + if {[catch {punk::args::parse [lrange $subargs 0 0] -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { puts stderr $argd exit 1 } set help_subject [dict get $argd values subject] - if {[dict exists $argd values action]} { - #G-143: 'make.tcl help ' renders the action's - #single-form usage (resolved against the subject's forms below) - set help_action [dict get $argd values action] - } + set help_words [lrange $subargs 1 end] } } elseif {$wants_help} { set do_help 1 set help_subject $subcommand - #G-143: ' -help' routes to the action's single-form - #usage when the subcommand is declared multi-form (tool, buildsuite) - - #the action candidate is the first non-flag word. Single-form subcommands - #keep the historic whole-subcommand render (trailing words ignored). - set firstword "" + #' ?arg ...? -help' - the same contract as + #'make.tcl help ?arg ...?': the remaining words are the + #subcommand's command line, with the help flag itself removed + #(wherever it appeared). + set help_words [list] foreach w $subargs { - if {![string match -* $w]} {set firstword $w ; break} - } - if {$firstword ne "" && [llength [punk::args::forms (script)::punkboot::$subcommand]] > 1} { - set help_action $firstword + if {$w ni $::punkboot::help_flags} {lappend help_words $w} } } elseif {$subcommand eq "shell"} { #declared passthrough: everything after 'shell' goes to the repl unparsed @@ -3955,29 +3961,33 @@ if {$do_help} { set usage_id (script)::punkboot::$help_subject } set usage_args [list] - if {$help_action ne ""} { - #G-143: per-action single-form usage. An unknown action word is a pointed - #punk::args usage error (exit 1) - never a plain-help fallback. Form - #names resolve by unambiguous prefix, matching the dispatch convention; - #a 0-based form INDEX is also accepted - the notation punk::args itself - #advertises (the ' i -form N ...' synopsis hints and its -form error - #messages both speak indexes). + if {[llength $help_words]} { + #G-143 (refined 2026-08-01): help_words is the subject's own command line + #('make.tcl help tool build -test 0 punkzip'). For a multi-form subject + #the LEADING word selects that action's single-form usage by unambiguous + #prefix - the same literal-leader word punk::args form auto-selection + #keys on at dispatch. Words after it are the user's in-progress + #arguments: tolerated and ignored, never validated here. A flag-shaped + #leading word selects nothing (an option-first line cannot identify a + #form without option-schema knowledge) and the whole subcommand's usage + #renders. A non-flag leading word matching no action of a multi-form + #subject is a pointed punk::args usage error (exit 1) - the same + #reaction dispatch has to that command line - never a plain-help + #fallback. Single-form subjects ignore the words entirely. set form_names [punk::args::forms $usage_id] - set fmatch [tcl::prefix::match -error "" $form_names $help_action] - if {$fmatch eq "" && [string is integer -strict $help_action] - && $help_action >= 0 && $help_action < [llength $form_names]} { - set fmatch [lindex $form_names $help_action] - } - if {$fmatch eq ""} { - if {[catch {punk::args::usage -form $help_action $usage_id} usage_err]} { - puts stderr $usage_err - } else { - puts stderr "make.tcl: no action '$help_action' for '$help_subject' (actions: $form_names)" + set w0 [lindex $help_words 0] + if {[llength $form_names] > 1 && ![string match -* $w0]} { + set fmatch [tcl::prefix::match -error "" $form_names $w0] + if {$fmatch eq ""} { + if {[catch {punk::args::usage -form $w0 $usage_id} usage_err]} { + puts stderr $usage_err + } else { + puts stderr "make.tcl: no action '$w0' for '$help_subject' (actions: $form_names)" + } + exit 1 } - exit 1 + lappend usage_args -form $fmatch } - set help_action $fmatch - lappend usage_args -form $help_action } if {![catch {punk::args::usage {*}$usage_args $usage_id} usage_out]} { puts stdout $usage_out diff --git a/src/project_layouts/vendor/punk/basic/src/make.tcl b/src/project_layouts/vendor/punk/basic/src/make.tcl index 49d50aec..4fce9524 100644 --- a/src/project_layouts/vendor/punk/basic/src/make.tcl +++ b/src/project_layouts/vendor/punk/basic/src/make.tcl @@ -2618,10 +2618,10 @@ proc ::punkboot::punkboot_gethelp {args} { append h " test suites, or build (test-gated) and install to /bin; options precede the tool names" \n append h " - zig is OPTIONAL: packages/bake never require this step; without a suitable toolchain the state is" \n append h " reported and build/test exit nonzero with fetch guidance (bin/punk-getzig.cmd)" \n \n - append h " $scriptname help ?subcommand? ?action?" \n + append h " $scriptname help ?subcommand? ?arg ...?" \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname -help);" \n - append h " with an action word or 0-based form index, that action's single-form usage when the tabled help" \n - append h " is available" \n \n + append h " extra words are the subcommand's own command line - a leading action word narrows the multi-form" \n + append h " subcommands (tool, buildsuite) to that action's usage when the tabled help is available" \n \n append h " Flags:" \n append h " -confirm 0|1" \n append h " - interactive y/n confirmation policy (default 1: prompt when stdin is a terminal, abort fast when it is not)." \n @@ -3239,11 +3239,14 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO help " Show tabled usage for make.tcl as a whole, or for a single subcommand. - Equivalent to 'make.tcl -help'. For the multi-form - subcommands (tool, buildsuite) an action word - or the 0-based form - index the synopsis hints display - narrows to that action's - single-form usage: 'make.tcl help tool build', 'make.tcl help tool 2' - and 'make.tcl tool build -help' all render the build form." + After the subject, accepts that subcommand's own command line and + shows the usage most specific to it: for the multi-form subcommands + (tool, buildsuite) the leading action word narrows to that action's + single-form usage - 'make.tcl help tool build -test 0 punkzip' shows + the tool build form, as does appending -help to the command line + itself ('make.tcl tool build -test 0 punkzip -help'). Words after + the action are tolerated and ignored; an option-first line shows + the whole subcommand's usage." buildsuite " Surface for the defined buildsuites under src/buildsuites (zig-built @@ -3678,13 +3681,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO -summary "${[dict get $SUMMARIES help]}" -& -help -& {${[dict get $HELPTEXTS help]}} - @values -min 1 -max 2 + @values -min 1 -max -1 subject -type string -optional 0 -& -choices {${[dict keys $SUMMARIES]}} -& -help "Subcommand to show usage for." - action -type string -optional 1 -help -& - "Action word (or 0-based form index) of a multi-form subcommand - (tool, buildsuite) - shows that action's single-form usage." + arg -type any -optional 1 -multiple 1 -help -& + "The subject's own arguments, as they would be typed. For a + multi-form subcommand (tool, buildsuite) a leading action word + narrows to that action's single-form usage; everything after + it is tolerated and ignored." } #top-level definition: the subcommand table rendered by 'make.tcl' / 'make.tcl -help' variable SUBGROUPS { @@ -3705,11 +3710,13 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO 'bin' and 'modules' folders at the same level as 'src'. General usage: make.tcl ?flags? - 'make.tcl help ?action?' or 'make.tcl ?action? -help' - shows a subcommand's own usage (a single action's usage for the - multi-form tool/buildsuite subcommands). Interactive y/n - confirmations can be driven non-interactively with the -confirm - flag declared on the relevant subcommands.} + 'make.tcl help ?arg ...?' or 'make.tcl + ?arg ...? -help' shows a subcommand's own usage - the words are the + subcommand's own command line, and for the multi-form + tool/buildsuite subcommands a leading action word narrows to that + action's usage. Interactive y/n confirmations can be driven + non-interactively with the -confirm flag declared on the relevant + subcommands.} punk::args::define { @id -id "(script)::punkboot" @cmd -name "make.tcl" -& @@ -3754,7 +3761,7 @@ if {$::punkboot::punkargs_ok && [package provide punk::ansi] ne "" && [package p set do_help 0 set help_subject "" -set help_action "" +set help_words [list] set help_exitcode 0 #defaults for the option-derived variables (fallback scan and passthrough subcommands rely on these) set ::punkboot::opt_forcekill 0 @@ -3785,30 +3792,29 @@ if {$::punkboot::punkargs_ok} { if {$subcommand eq "help"} { set do_help 1 if {[llength $subargs]} { - if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { + #validate/resolve ONLY the subject word through the help definition + #(choices table + unambiguous prefixes). The tail is the subject's + #own command line as the user would type it - deliberately NOT + #parsed here: it may be any mix of that subcommand's actions, + #options and values, including incomplete or wrong ones, which is + #precisely when help is wanted (G-143 refinement 2026-08-01). + if {[catch {punk::args::parse [lrange $subargs 0 0] -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { puts stderr $argd exit 1 } set help_subject [dict get $argd values subject] - if {[dict exists $argd values action]} { - #G-143: 'make.tcl help ' renders the action's - #single-form usage (resolved against the subject's forms below) - set help_action [dict get $argd values action] - } + set help_words [lrange $subargs 1 end] } } elseif {$wants_help} { set do_help 1 set help_subject $subcommand - #G-143: ' -help' routes to the action's single-form - #usage when the subcommand is declared multi-form (tool, buildsuite) - - #the action candidate is the first non-flag word. Single-form subcommands - #keep the historic whole-subcommand render (trailing words ignored). - set firstword "" + #' ?arg ...? -help' - the same contract as + #'make.tcl help ?arg ...?': the remaining words are the + #subcommand's command line, with the help flag itself removed + #(wherever it appeared). + set help_words [list] foreach w $subargs { - if {![string match -* $w]} {set firstword $w ; break} - } - if {$firstword ne "" && [llength [punk::args::forms (script)::punkboot::$subcommand]] > 1} { - set help_action $firstword + if {$w ni $::punkboot::help_flags} {lappend help_words $w} } } elseif {$subcommand eq "shell"} { #declared passthrough: everything after 'shell' goes to the repl unparsed @@ -3955,29 +3961,33 @@ if {$do_help} { set usage_id (script)::punkboot::$help_subject } set usage_args [list] - if {$help_action ne ""} { - #G-143: per-action single-form usage. An unknown action word is a pointed - #punk::args usage error (exit 1) - never a plain-help fallback. Form - #names resolve by unambiguous prefix, matching the dispatch convention; - #a 0-based form INDEX is also accepted - the notation punk::args itself - #advertises (the ' i -form N ...' synopsis hints and its -form error - #messages both speak indexes). + if {[llength $help_words]} { + #G-143 (refined 2026-08-01): help_words is the subject's own command line + #('make.tcl help tool build -test 0 punkzip'). For a multi-form subject + #the LEADING word selects that action's single-form usage by unambiguous + #prefix - the same literal-leader word punk::args form auto-selection + #keys on at dispatch. Words after it are the user's in-progress + #arguments: tolerated and ignored, never validated here. A flag-shaped + #leading word selects nothing (an option-first line cannot identify a + #form without option-schema knowledge) and the whole subcommand's usage + #renders. A non-flag leading word matching no action of a multi-form + #subject is a pointed punk::args usage error (exit 1) - the same + #reaction dispatch has to that command line - never a plain-help + #fallback. Single-form subjects ignore the words entirely. set form_names [punk::args::forms $usage_id] - set fmatch [tcl::prefix::match -error "" $form_names $help_action] - if {$fmatch eq "" && [string is integer -strict $help_action] - && $help_action >= 0 && $help_action < [llength $form_names]} { - set fmatch [lindex $form_names $help_action] - } - if {$fmatch eq ""} { - if {[catch {punk::args::usage -form $help_action $usage_id} usage_err]} { - puts stderr $usage_err - } else { - puts stderr "make.tcl: no action '$help_action' for '$help_subject' (actions: $form_names)" + set w0 [lindex $help_words 0] + if {[llength $form_names] > 1 && ![string match -* $w0]} { + set fmatch [tcl::prefix::match -error "" $form_names $w0] + if {$fmatch eq ""} { + if {[catch {punk::args::usage -form $w0 $usage_id} usage_err]} { + puts stderr $usage_err + } else { + puts stderr "make.tcl: no action '$w0' for '$help_subject' (actions: $form_names)" + } + exit 1 } - exit 1 + lappend usage_args -form $fmatch } - set help_action $fmatch - lappend usage_args -form $help_action } if {![catch {punk::args::usage {*}$usage_args $usage_id} usage_out]} { puts stdout $usage_out diff --git a/src/project_layouts/vendor/punk/project-0.1/src/make.tcl b/src/project_layouts/vendor/punk/project-0.1/src/make.tcl index 49d50aec..4fce9524 100644 --- a/src/project_layouts/vendor/punk/project-0.1/src/make.tcl +++ b/src/project_layouts/vendor/punk/project-0.1/src/make.tcl @@ -2618,10 +2618,10 @@ proc ::punkboot::punkboot_gethelp {args} { append h " test suites, or build (test-gated) and install to /bin; options precede the tool names" \n append h " - zig is OPTIONAL: packages/bake never require this step; without a suitable toolchain the state is" \n append h " reported and build/test exit nonzero with fetch guidance (bin/punk-getzig.cmd)" \n \n - append h " $scriptname help ?subcommand? ?action?" \n + append h " $scriptname help ?subcommand? ?arg ...?" \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname -help);" \n - append h " with an action word or 0-based form index, that action's single-form usage when the tabled help" \n - append h " is available" \n \n + append h " extra words are the subcommand's own command line - a leading action word narrows the multi-form" \n + append h " subcommands (tool, buildsuite) to that action's usage when the tabled help is available" \n \n append h " Flags:" \n append h " -confirm 0|1" \n append h " - interactive y/n confirmation policy (default 1: prompt when stdin is a terminal, abort fast when it is not)." \n @@ -3239,11 +3239,14 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO help " Show tabled usage for make.tcl as a whole, or for a single subcommand. - Equivalent to 'make.tcl -help'. For the multi-form - subcommands (tool, buildsuite) an action word - or the 0-based form - index the synopsis hints display - narrows to that action's - single-form usage: 'make.tcl help tool build', 'make.tcl help tool 2' - and 'make.tcl tool build -help' all render the build form." + After the subject, accepts that subcommand's own command line and + shows the usage most specific to it: for the multi-form subcommands + (tool, buildsuite) the leading action word narrows to that action's + single-form usage - 'make.tcl help tool build -test 0 punkzip' shows + the tool build form, as does appending -help to the command line + itself ('make.tcl tool build -test 0 punkzip -help'). Words after + the action are tolerated and ignored; an option-first line shows + the whole subcommand's usage." buildsuite " Surface for the defined buildsuites under src/buildsuites (zig-built @@ -3678,13 +3681,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO -summary "${[dict get $SUMMARIES help]}" -& -help -& {${[dict get $HELPTEXTS help]}} - @values -min 1 -max 2 + @values -min 1 -max -1 subject -type string -optional 0 -& -choices {${[dict keys $SUMMARIES]}} -& -help "Subcommand to show usage for." - action -type string -optional 1 -help -& - "Action word (or 0-based form index) of a multi-form subcommand - (tool, buildsuite) - shows that action's single-form usage." + arg -type any -optional 1 -multiple 1 -help -& + "The subject's own arguments, as they would be typed. For a + multi-form subcommand (tool, buildsuite) a leading action word + narrows to that action's single-form usage; everything after + it is tolerated and ignored." } #top-level definition: the subcommand table rendered by 'make.tcl' / 'make.tcl -help' variable SUBGROUPS { @@ -3705,11 +3710,13 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO 'bin' and 'modules' folders at the same level as 'src'. General usage: make.tcl ?flags? - 'make.tcl help ?action?' or 'make.tcl ?action? -help' - shows a subcommand's own usage (a single action's usage for the - multi-form tool/buildsuite subcommands). Interactive y/n - confirmations can be driven non-interactively with the -confirm - flag declared on the relevant subcommands.} + 'make.tcl help ?arg ...?' or 'make.tcl + ?arg ...? -help' shows a subcommand's own usage - the words are the + subcommand's own command line, and for the multi-form + tool/buildsuite subcommands a leading action word narrows to that + action's usage. Interactive y/n confirmations can be driven + non-interactively with the -confirm flag declared on the relevant + subcommands.} punk::args::define { @id -id "(script)::punkboot" @cmd -name "make.tcl" -& @@ -3754,7 +3761,7 @@ if {$::punkboot::punkargs_ok && [package provide punk::ansi] ne "" && [package p set do_help 0 set help_subject "" -set help_action "" +set help_words [list] set help_exitcode 0 #defaults for the option-derived variables (fallback scan and passthrough subcommands rely on these) set ::punkboot::opt_forcekill 0 @@ -3785,30 +3792,29 @@ if {$::punkboot::punkargs_ok} { if {$subcommand eq "help"} { set do_help 1 if {[llength $subargs]} { - if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { + #validate/resolve ONLY the subject word through the help definition + #(choices table + unambiguous prefixes). The tail is the subject's + #own command line as the user would type it - deliberately NOT + #parsed here: it may be any mix of that subcommand's actions, + #options and values, including incomplete or wrong ones, which is + #precisely when help is wanted (G-143 refinement 2026-08-01). + if {[catch {punk::args::parse [lrange $subargs 0 0] -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { puts stderr $argd exit 1 } set help_subject [dict get $argd values subject] - if {[dict exists $argd values action]} { - #G-143: 'make.tcl help ' renders the action's - #single-form usage (resolved against the subject's forms below) - set help_action [dict get $argd values action] - } + set help_words [lrange $subargs 1 end] } } elseif {$wants_help} { set do_help 1 set help_subject $subcommand - #G-143: ' -help' routes to the action's single-form - #usage when the subcommand is declared multi-form (tool, buildsuite) - - #the action candidate is the first non-flag word. Single-form subcommands - #keep the historic whole-subcommand render (trailing words ignored). - set firstword "" + #' ?arg ...? -help' - the same contract as + #'make.tcl help ?arg ...?': the remaining words are the + #subcommand's command line, with the help flag itself removed + #(wherever it appeared). + set help_words [list] foreach w $subargs { - if {![string match -* $w]} {set firstword $w ; break} - } - if {$firstword ne "" && [llength [punk::args::forms (script)::punkboot::$subcommand]] > 1} { - set help_action $firstword + if {$w ni $::punkboot::help_flags} {lappend help_words $w} } } elseif {$subcommand eq "shell"} { #declared passthrough: everything after 'shell' goes to the repl unparsed @@ -3955,29 +3961,33 @@ if {$do_help} { set usage_id (script)::punkboot::$help_subject } set usage_args [list] - if {$help_action ne ""} { - #G-143: per-action single-form usage. An unknown action word is a pointed - #punk::args usage error (exit 1) - never a plain-help fallback. Form - #names resolve by unambiguous prefix, matching the dispatch convention; - #a 0-based form INDEX is also accepted - the notation punk::args itself - #advertises (the ' i -form N ...' synopsis hints and its -form error - #messages both speak indexes). + if {[llength $help_words]} { + #G-143 (refined 2026-08-01): help_words is the subject's own command line + #('make.tcl help tool build -test 0 punkzip'). For a multi-form subject + #the LEADING word selects that action's single-form usage by unambiguous + #prefix - the same literal-leader word punk::args form auto-selection + #keys on at dispatch. Words after it are the user's in-progress + #arguments: tolerated and ignored, never validated here. A flag-shaped + #leading word selects nothing (an option-first line cannot identify a + #form without option-schema knowledge) and the whole subcommand's usage + #renders. A non-flag leading word matching no action of a multi-form + #subject is a pointed punk::args usage error (exit 1) - the same + #reaction dispatch has to that command line - never a plain-help + #fallback. Single-form subjects ignore the words entirely. set form_names [punk::args::forms $usage_id] - set fmatch [tcl::prefix::match -error "" $form_names $help_action] - if {$fmatch eq "" && [string is integer -strict $help_action] - && $help_action >= 0 && $help_action < [llength $form_names]} { - set fmatch [lindex $form_names $help_action] - } - if {$fmatch eq ""} { - if {[catch {punk::args::usage -form $help_action $usage_id} usage_err]} { - puts stderr $usage_err - } else { - puts stderr "make.tcl: no action '$help_action' for '$help_subject' (actions: $form_names)" + set w0 [lindex $help_words 0] + if {[llength $form_names] > 1 && ![string match -* $w0]} { + set fmatch [tcl::prefix::match -error "" $form_names $w0] + if {$fmatch eq ""} { + if {[catch {punk::args::usage -form $w0 $usage_id} usage_err]} { + puts stderr $usage_err + } else { + puts stderr "make.tcl: no action '$w0' for '$help_subject' (actions: $form_names)" + } + exit 1 } - exit 1 + lappend usage_args -form $fmatch } - set help_action $fmatch - lappend usage_args -form $help_action } if {![catch {punk::args::usage {*}$usage_args $usage_id} usage_out]} { puts stdout $usage_out