Browse Source

tclsh subcommand: stock arg forms (leading dash, -encoding) + lib: refusal (0.19.0)

- a leading '-' argument is no longer treated as a script name: all args stay in
  ::argv and the subcommand proceeds to the repl (tty) or stdin evaluation
  (piped), matching stock tclsh
- '-encoding name fileName' sources the script with the named encoding;
  incomplete -encoding forms fall through to the argv path as stock does
- lib: scriptlib names are refused with a pointer to the 'script' subcommand
  (exit 1): the tclsh subcommand keeps plain-tclsh semantics, no punk modules
- also carries the piperepl dispatch work-in-progress this session's review
  validated: TCLSH_PIPEREPL gate default enabled-unless-0 (G-103 patched-runtime
  policy) and the no-arg branch (tty -> tclsh repl via dorepl; piped -> read
  stdin + eval with tcl_interactive/dorepl 0)
- punkproject 0.19.0 + changelog entry

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
1dd9940695
  1. 12
      CHANGELOG.md
  2. 2
      punkproject.toml
  3. 63
      src/vfs/_config/punk_main.tcl

12
CHANGELOG.md

@ -5,6 +5,18 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.19.0] - 2026-07-23
- `bin/punk-runtime.cmd`: sha1 hashing (fetch verification, `list -remote` comparison) no longer depends on `Get-FileHash` - a script-defined function in Windows PowerShell 5.1 that vanishes on machines with a damaged PSModulePath while compiled cmdlets keep working (observed in the field: "Get-FileHash ... not recognized" under PS 5, making `list -remote` report spurious UPDATE AVAILABLE and fetch verification fail closed). Hashing now uses .NET directly (`Get-PunkFileSha1`), working on any PowerShell edition/state, with a one-time informational note when the damaged condition is detected. The bash payload's multi-tool sha1 probing was already robust and is unchanged.
- `tclsh` subcommand: stock tclsh argument forms - a leading `-` argument no longer errors as a
script name: all arguments stay in `::argv` and the subcommand proceeds to the repl/stdin
evaluation, matching stock `tclsh - args...`; `-encoding name fileName` is recognised and the
script is sourced with the named encoding (incomplete `-encoding` forms fall through to argv,
as stock). `lib:` scriptlib names are refused with a pointer to the `script` subcommand
(exit 1) - the tclsh subcommand keeps plain tclsh semantics and loads no punk modules.
Pinned by `src/tests/shell/testsuites/punkexe/tclshcmd.test` (new suite, also covering the
piperepl launch-state contract on patched kits).
## [0.18.9] - 2026-07-22
- punk::mod 0.1.2: punk::apps `latest` app-version selection fixed (version-selection audit) - a plain lexical sort picked the LOWEST version as latest (and misorders 1.10 vs 1.9); now `package vcompare`-sorted highest, empty unversioned-main entries excluded. Audit outcome: all other punk-owned `[package versions]` consumers already sort with vcompare; naive sorts remain only in vendored third-party code (tcllib doctools, pattern-1.2.8.tm) - flagged, not edited, per the vendor no-edit policy.

2
punkproject.toml

@ -1,4 +1,4 @@
[project]
name = "punkshell"
version = "0.18.9"
version = "0.19.0"
license = "BSD-2-Clause"

63
src/vfs/_config/punk_main.tcl

@ -1216,17 +1216,17 @@ apply { args {
#we would like to drop through to standard tclsh repl without launching another process
#tclMain.c doesn't allow it unless patched.
if {![info exists ::env(TCLSH_PIPEREPL)]} {
set is_tclsh_piperepl_env_true 0
set is_tclsh_piperepl_env_true 1
} else {
if {[string is boolean -strict $::env(TCLSH_PIPEREPL)]} {
set is_tclsh_piperepl_env_true $::env(TCLSH_PIPEREPL)
} else {
set is_tclsh_piperepl_env_true 0
set is_tclsh_piperepl_env_true 1
}
}
if {!$is_tclsh_piperepl_env_true} {
puts stderr "tcl_interactive: $::tcl_interactive"
puts stderr "stdin: [chan configure stdin]"
#puts stderr "stdin: [chan configure stdin]"
puts stderr "Environment variable TCLSH_PIPEREPL is not set or is false or is not a boolean"
} else {
#according to env TCLSH_PIPEREPL and our commandline argument - tclsh repl is desired
@ -1235,16 +1235,61 @@ apply { args {
puts stderr "error: the runtime doesn't appear to have been compiled with the piperepl patch"
}
}
set ::tcl_interactive 1
set ::tclsh(dorepl) 1
if {[llength $subcommand_arglist]} {
set normscript [file normalize [lindex $subcommand_arglist 0]]
#stock tclsh argument forms (tclMain.c): the only recognised leading option is
#'-encoding name fileName' (and only when fileName does not begin with '-');
#any other leading '-' argument means NO script file - all arguments stay in
#::argv (already set above) and tclsh proceeds to the repl (tty) or stdin
#evaluation (piped).
set tclsh_have_script 0
set tclsh_encoding ""
if {[llength $subcommand_arglist] >= 3 && [lindex $subcommand_arglist 0] eq "-encoding" && ![string match -* [lindex $subcommand_arglist 2]]} {
set tclsh_encoding [lindex $subcommand_arglist 1]
set tclsh_script [lindex $subcommand_arglist 2]
set tclsh_scriptargs [lrange $subcommand_arglist 3 end]
set tclsh_have_script 1
} elseif {[llength $subcommand_arglist] && ![string match -* [lindex $subcommand_arglist 0]]} {
set tclsh_script [lindex $subcommand_arglist 0]
set tclsh_scriptargs [lrange $subcommand_arglist 1 end]
set tclsh_have_script 1
}
if {$tclsh_have_script} {
if {[string match -nocase lib:* $tclsh_script]} {
#scriptlib resolution is a punk facility - the tclsh subcommand keeps plain
#tclsh semantics (no punk modules loaded), so point at the 'script' subcommand
#instead of failing on a literal 'lib:...' path (illegal on windows filesystems
#anyway; reachable via ./lib:... or an absolute path on other platforms).
set exebase [file rootname [file tail [info nameofexecutable]]]
puts stderr "punk tclsh: 'lib:' scriptlib resolution is not supported by the tclsh subcommand (plain tclsh semantics)"
puts stderr " use: $exebase script $tclsh_script ?args...?"
exit 1
}
set normscript [file normalize $tclsh_script]
info script $normscript
set ::argv0 $normscript
set ::argv [lrange $subcommand_arglist 1 end]
set ::argv $tclsh_scriptargs
set ::argc [llength $::argv]
#we are in an apply context here - so we need to uplevel to get the source to work as expected
uplevel 1 [list source [lindex $subcommand_arglist 0]]
if {$tclsh_encoding ne ""} {
uplevel 1 [list source -encoding $tclsh_encoding $tclsh_script]
} else {
uplevel 1 [list source $tclsh_script]
}
#default tclsh behaviour is to run the script and exit
#the script can set ::tclsh(dorepl) 1 to force the tclsh repl after the script has run
} else {
if {[info exists ::tclsh(istty)] && $::tclsh(istty)} {
#tclsh piperepl patch applied - stdin is a tty - we can run the tclsh repl
set ::tclsh(dorepl) 1
set ::tcl_interactive 1
} else {
#stdin is not a tty - we are being run with input piped in - we will evaluate stdin as a script and exit
set ::tclsh(dorepl) 0
set ::tcl_interactive 0
#script on stdin could set ::tclsh(dorepl) 1 to force the tclsh repl after the script has run
set data [read stdin]
uplevel 1 [list eval $data]
}
}
}
shellspy {

Loading…
Cancel
Save