From 7ea1deaae5968ef74da4d5fd52763279c93a5602 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Tue, 14 Jul 2026 03:23:52 +1000 Subject: [PATCH] G-030 achieved: make.tcl dogfoods punk::args - tabled usage, declared subcommands, -confirm prompt policy All 15 make.tcl subcommands are punk::args-declared ((script)::punkboot + (script)::punkboot::, built from single-source summary/help/opt dicts with shared option fragments and explicit @form -synopsis). Bare make.tcl / -help, 'help ?subcommand?' and ' -help' render tabled usage; invalid flags/subcommands raise punk::args usage errors (exit 1) with unambiguous prefix resolution; 'shell' is a declared passthrough. Prompt policy: new -confirm 0|1 (default 1) on every confirmation point (bootsupport minor-staleness gate, vfscommonupdate REPLACE, kit-type mismatch). Default prompts only on an interactive terminal and aborts fast with guidance on non-interactive stdin (::punkboot::lib::stdin_is_interactive; Tcl 8.6 lacks the -inputmode probe and is assumed interactive). -confirm 0 proceeds (staleness, REPLACE) or skips the mismatched kit. The piped-y agent workflow is retired; the old vfscommonupdate decline half-abort (printed done, exit 0) now exits 1. Degrade rule: punk::args/punk::ansi/textblock boot requires guarded; definition load caught with fallback to a self-contained scan (-k/-dirty-abort/-confirm supported) + plain punkboot_gethelp (availability NOTE factored into punkboot_availability_note, shared by both paths); rendering degrades independently of parsing (errorstyle minimal / plain help when the ANSI stack is unhealthy); PUNKBOOT_PLAIN=1 forces degraded mode. punk::args joins the bootstrap-tracked _runtime_deps staleness set (parsing contract only - the rendering stack degrades instead; contract docs updated in src/bootsupport/AGENTS.md + src/modules/AGENTS.md, workflow docs in src/AGENTS.md + src/tests/shell/AGENTS.md). Verified: usage/help/error paths, vfscommonupdate fail-fast and -confirm 0 runs with closed stdin, staleness flag route live (args 0.5.0->0.12.0 tripped the gate), degraded-mode help/check/info, full 'project -k -confirm 0' kit build. Dogfooding finding recorded in the goal file: punk::args 0.12.0 reports generic overflow where 0.5.0 reported choiceviolation for optional-choice mismatches (worked around with required leaders; candidate error-selection improvement). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- CHANGELOG.md | 4 + GOALS-archive.md | 4 + GOALS.md | 4 - goals/G-030-maketcl-punkargs.md | 77 --- goals/G-032-launcher-punkargs.md | 2 +- goals/archive/G-030-maketcl-punkargs.md | 189 ++++++++ punkproject.toml | 2 +- src/AGENTS.md | 5 +- src/bootsupport/AGENTS.md | 12 +- src/make.tcl | 594 +++++++++++++++++++----- src/modules/AGENTS.md | 2 +- src/tests/shell/AGENTS.md | 2 +- 12 files changed, 676 insertions(+), 221 deletions(-) delete mode 100644 goals/G-030-maketcl-punkargs.md create mode 100644 goals/archive/G-030-maketcl-punkargs.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 26668bfc..ea519600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ 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.12.24] - 2026-07-14 + +- G-030 (achieved): make.tcl dogfoods punk::args. All 15 subcommands are punk::args-declared ((script)::punkboot definitions with single-source summaries, shared option fragments and explicit @form -synopsis lines): bare `make.tcl`/`-help` render tabled usage with grouped subcommand summaries, `make.tcl help ?subcommand?` / ` -help` show per-subcommand definitions, invalid flags and unknown subcommands raise punk::args usage errors (exit 1) with unambiguous-prefix resolution. New `-confirm 0|1` prompt policy on every confirmation point (bootsupport minor-staleness gate, vfscommonupdate REPLACE, kit-type mismatch): default prompts only on an interactive terminal and aborts fast with guidance on non-interactive stdin (the piped-`y` agent workflow is retired - use `-confirm 0`; the old vfscommonupdate decline half-abort now exits 1). punk::args joined the bootstrap-tracked staleness set (parsing contract only - the punk::ansi/textblock rendering stack degrades instead: minimal errorstyle/plain help when unhealthy, and full scan-based fallback dispatch when punk::args itself is unavailable; PUNKBOOT_PLAIN=1 forces the degraded mode). Bootsupport snapshot refreshed (args 0.5.0->0.12.0 plus punk/lib/ns/repl/tclcore moduledoc) and layout make.tcl/bootsupport copies followed via the punkcheck channel. Docs: src/AGENTS.md, src/bootsupport/AGENTS.md, src/modules/AGENTS.md, src/tests/shell/AGENTS.md. Dogfooding finding recorded in the goal file: punk::args 0.12.0 reports a generic overflow error where 0.5.0 reported a pointed choiceviolation for optional-choice mismatches (worked around with required leaders; candidate punk::args error-selection improvement). + ## [0.12.22] - 2026-07-13 - G-074 (achieved): punk::args 0.12.0 adds punk::args::formcheck - on-demand multiform ambiguity analysis. It reports the form pairs of a definition that some argument list could cleanly match simultaneously, confirming every candidate with a real parse of a synthetic witness arglist against both forms - so fully discriminated form pairs can never false-alarm, and each reported witness is a genuine multipleformmatches input. Findings classify as type-weakness (a literal/choice discriminator aligned with a permissive non-validating type such as expr/any/string - the 'lseq 1 count 5' class) vs structural (the forms genuinely share an argument shape - the 'after cancel id|script' class). The new @form -overlapallowed key sanctions a known/documented overlap for formcheck reporting only (parse behaviour untouched; unknown form names rejected at definition resolve); tclcore moduledoc 0.3.4 adopts it for the after cancel pair, leaving ::after with zero unsanctioned findings while ::lseq's expr-typed-end findings stay visible as actionable. New testsuite args/formcheck.test. diff --git a/GOALS-archive.md b/GOALS-archive.md index 5553bcd4..33352531 100644 --- a/GOALS-archive.md +++ b/GOALS-archive.md @@ -85,6 +85,10 @@ Acceptance: LICENSE.txt exists at the repo root containing the standard BSD-2-Cl Scope: src/modules/punk/args-999999.0a1.0.tm (get_dict value allocation, private::get_dict_can_assign_value, parse_status), src/tests/modules/punk/args/testsuites/args/ (new allocation characterization suite), src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (::lseq as the proving consumer) Acceptance: a new allocation characterization suite drives the lseq range matrix under explicit -form range - '0 10', '0 10 2', '0 10 by 2', '0 to 10 2', '0 .. 10 by 2', '1 5 by 0' parse per the lseq.n grammar (the three currently-failing cases fixed) and '0 10 2 4' still fails - plus reduced fixtures isolating the shape (optional choice value between required values + trailing optional-member clause) independent of the moduledoc; the ::if noise-word cases (mid-clause ?literal(then)?, clause-leading ?literal(else)?) keep passing - no regression to optional clause members generally; a genuinely invalid arglist's error names the failing element (the '..|to' misblame case pinned fixed); punk::args::parse_status accepts -form (single form name/index at minimum, consistent with parse) with its status structure reporting the form used; full punk::args and punk::ns suites pass with no expectations weakened; before/after results for the probe matrix recorded in this file. +### G-030 [achieved 2026-07-14] make.tcl dogfoods punk::args: tabled usage, declared subcommands, prompt-free flags → detail: goals/archive/G-030-maketcl-punkargs.md +Scope: src/make.tcl (dispatch, help, prompts), src/bootsupport/AGENTS.md + src/modules/AGENTS.md (bootstrap-tracked staleness contract), src/modules/punk/args-999999.0a1.0.tm (only as consumed) +Acceptance: `tclsh src/make.tcl` and `-help` render punk::args tabled usage listing every subcommand with a summary, and `make.tcl help ` (or ` -help`) shows that subcommand's definition; invalid arguments produce a punk::args usage error rather than ad-hoc messages; every y/n prompt has a documented flag equivalent (proven at least for vfscommonupdate and the project-build confirmations: a run with the flag completes non-interactively with stdin closed) and a non-interactive stdin without the flag fails fast with usage rather than hanging or half-aborting; punk::args is added to the bootstrap-tracked buildversion set with the doc contract updated (src/bootsupport/AGENTS.md, src/modules/AGENTS.md); with bootsupport punk::args unavailable or unloadable, make.tcl still boots and `check`, `bootsupport` and `modules` remain usable with plain-text fallback help (the guarded-require degrade rule); layout make.tcl copies follow via the established sync/G-027 channels (noted, not hand-synced). + ### G-074 [achieved 2026-07-13] punk::args multiform ambiguity analysis: on-demand form-overlap detection with sanctioned-overlap annotation → detail: goals/archive/G-074-punkargs-multiform-ambiguity-lint.md Scope: src/modules/punk/args-999999.0a1.0.tm (analysis command, @form sanction key as decided in the work), src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (::after/::lseq as proving consumers, sanction adoption), src/tests/modules/punk/args/testsuites/args/ (new suite) Acceptance: the analysis command reports the two known real cases from the G-041 closeout - ::lseq range/start_count overlap via the expr-typed end slot (unsanctioned finding: type-weakness class) and ::after cancelid/cancelscript (documented-overlap class) - and reports nothing for multiform definitions whose forms are fully discriminated (the parse withid/withdef pair, the forms.test afterish fixture); classifications distinguish at minimum type-weakness overlap (a discriminator aligned with a permissive type) from structural overlap (no discriminating slot exists); the sanction annotation silences (or downgrades to acknowledged) a listed form pair without affecting parse behaviour, is rejected at definition resolve when it names unknown forms, and is adopted for the after cancel pair in the tclcore moduledoc; the analysis is conservative in the documented direction (may miss deep ambiguities, must not false-alarm on discriminated forms - the miss/report boundary is documented with the slot model); running it performs no parse of user-supplied words and adds no work to define/resolve for definitions that never call it; a new testsuite covers the finding classes, the sanction, the unknown-form rejection and the no-finding cases; full punk::args suite passes. diff --git a/GOALS.md b/GOALS.md index c54c01a9..7ac579e5 100644 --- a/GOALS.md +++ b/GOALS.md @@ -166,10 +166,6 @@ Detail: goals/G-028-file-locker-identification.md Scope: src/make.tcl (test-module packaging step), src/tests/ (source of truth), src/modules/test/ (generated #modpod targets), src/modules/punk/mix/ (modpod tooling as needed) Detail: goals/G-029-testmodules-from-srctests.md -### G-030 [proposed] make.tcl dogfoods punk::args: tabled usage, declared subcommands, prompt-free flags -Scope: src/make.tcl (dispatch, help, prompts), src/bootsupport/AGENTS.md + src/modules/AGENTS.md (bootstrap-tracked staleness contract), src/modules/punk/args-999999.0a1.0.tm (only as consumed) -Detail: goals/G-030-maketcl-punkargs.md - ### G-031 [proposed] Componentized kit boot: thin project-owned main + shared layout-owned boot core Scope: src/vfs/_config/ (punk_main.tcl, project_main.tcl restructure), src/vfs/_vfscommon.vfs (boot core delivery), src/project_layouts/ (thin-main skeleton, via established sync channels) Detail: goals/G-031-componentized-kit-boot.md diff --git a/goals/G-030-maketcl-punkargs.md b/goals/G-030-maketcl-punkargs.md deleted file mode 100644 index 93bd9890..00000000 --- a/goals/G-030-maketcl-punkargs.md +++ /dev/null @@ -1,77 +0,0 @@ -# G-030 make.tcl dogfoods punk::args: tabled usage, declared subcommands, prompt-free flags - -Status: proposed -Scope: src/make.tcl (dispatch, help, prompts), src/bootsupport/AGENTS.md + src/modules/AGENTS.md (bootstrap-tracked staleness contract), src/modules/punk/args-999999.0a1.0.tm (only as consumed) -Goal: make.tcl - the first surface a developer sees - parses its subcommands and options via punk::args and showcases the tabled usage output for help and argument errors, every interactive y/n prompt gains a declared flag equivalent so agents can drive make.tcl with arguments instead of piped input, punk::args joins the bootstrap-tracked staleness set, and the boot phase plus the environment-repair commands keep working with degraded plain help when the bootsupport punk::args (or the table-rendering stack) is stale or unavailable. -Acceptance: `tclsh src/make.tcl` and `-help` render punk::args tabled usage listing every subcommand with a summary, and `make.tcl help ` (or ` -help`) shows that subcommand's definition; invalid arguments produce a punk::args usage error rather than ad-hoc messages; every y/n prompt has a documented flag equivalent (proven at least for vfscommonupdate and the project-build confirmations: a run with the flag completes non-interactively with stdin closed) and a non-interactive stdin without the flag fails fast with usage rather than hanging or half-aborting; punk::args is added to the bootstrap-tracked buildversion set with the doc contract updated (src/bootsupport/AGENTS.md, src/modules/AGENTS.md); with bootsupport punk::args unavailable or unloadable, make.tcl still boots and `check`, `bootsupport` and `modules` remain usable with plain-text fallback help (the guarded-require degrade rule); layout make.tcl copies follow via the established sync/G-027 channels (noted, not hand-synced). - -## Context - -make.tcl is the first surface a developer meets in a punkshell-derived project, -but its command handling predates the ecosystem's own tooling: a hand-built -help text, a bare `known_commands` list, ad-hoc argument handling per -subcommand, and interactive y/n prompts (`vfscommonupdate`'s REPLACE -confirmation, the project-build confirmations, bootsupport staleness prompts). -Eating our own dogfood - punk::args definitions per subcommand with the tabled -usage rendering - both showcases the ecosystem where it is most visible and -makes the parsing declarative. - -The prompts are the practical payoff: agent-driven builds currently pipe `y` -into stdin (fragile, undiscoverable - observed 2026-07-07 while rebuilding -tomlish.exe). With punk::args parsing, prompt-free operation is just another -declared option per subcommand, and non-interactive stdin without the flag can -fail fast with usage instead of hanging on a read or half-aborting. - -Precedents already in-tree: src/tests/runtests.tcl parses via punk::args -((script)::runtests definition), and the tomlish cmdline app presents tabled -usage as its first surface. - -## Approach - -- One PUNKARGS definition per subcommand (@cmd -summary/-help + opts), plus a - top-level definition enumerating subcommands - replacing punkboot_gethelp - and the hand-maintained help strings. `make.tcl`, `make.tcl -help`, and - per-subcommand help all render through punk::args::usage. -- Prompt policy: interactive stdin -> prompt as today (default); flag supplied - (e.g. -confirm 0 / -y, naming decision recorded here) -> proceed without - prompting; non-interactive stdin without the flag -> usage error, fast. - The bootsupport staleness prompt keeps its abort/prompt/proceed - classification but gains the same flag route. -- **Degradation is a hard requirement** (the 2026-07-06/07 incidents are the - cautionary tale: a stale bundled fileutil disabled the very make.tcl step - needed to fix it). The boot phase stays self-contained; punk::args is - guarded-lazily required post-boot (the punkboot::utils pattern documented in - src/bootsupport/AGENTS.md); when unavailable, dispatch and the repair - commands (check, bootsupport, modules) keep working with plain-text fallback - help. Note the tabled rendering also pulls punk::ansi/textblock/punk::char - - exactly the modules whose same-version staleness broke shellfilter this week - - so rendering must degrade independently of parsing (punk::args plain - output when the ANSI stack is unhealthy). -- Staleness tracking: punk::args joins the bootstrap-tracked buildversion set - (currently punkcheck, punk::repo, punk::mix, punk::tdl) with the same - bump-at-least-minor-on-call-site-API-change discipline; whether the - rendering stack is also tracked or left to degrade is an implementation - decision to record here (initial lean: track punk::args only - it is the - parsing contract; rendering degrades). -- Layout copies of make.tcl follow through the existing punkcheck-tracked - sync (custom/_project) and the G-012/G-027 channels for the rest - noted in - completion reports, never hand-synced. - -## Alternatives considered - -- Ad-hoc -y flags bolted onto the current hand parsing - rejected: solves the - agent problem but leaves the first-surface help un-showcased and the parsing - divergent from the ecosystem's own conventions. -- Requiring punk::args at boot (no fallback) - rejected: make.tcl must be able - to repair the very bootsupport snapshot it loads punk::args from. - -## Notes - -- Related: G-015 (agents driving punk tooling non-interactively), G-024 - (mapvfs toml errors deserve the same declared-argument quality), G-025 (the - version-report subcommand should be born punk::args-defined), G-027 (pull - updates deliver the improved make.tcl to derived projects). -- Observation parked here from the same session: runtests/make.tcl-adjacent - tooling that returns result dicts should document their key shape (see the - runx -tcl exitcode note in G-015's detail). -- Archived-goal references in this file: G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md). diff --git a/goals/G-032-launcher-punkargs.md b/goals/G-032-launcher-punkargs.md index c8ef98e4..7864892f 100644 --- a/goals/G-032-launcher-punkargs.md +++ b/goals/G-032-launcher-punkargs.md @@ -62,4 +62,4 @@ in `-help` by registration alone. natural first parsed subcommand; exit-code semantics), G-025 (version-report subcommand born punk::args-defined), G-013 (the debugrepl activation review mentions proper-command conversions that would slot into the same pattern). -- Archived-goal references in this file: G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md). +- Archived-goal references in this file: G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md); G-030 achieved 2026-07-14 (goals/archive/G-030-maketcl-punkargs.md) - the make.tcl counterpart shipped: follow its shipped decisions (`-confirm 0|1` prompt policy, explicit `@form -synopsis`, track-parsing-degrade-rendering split, required-choice leaders for pointed choiceviolation errors). diff --git a/goals/archive/G-030-maketcl-punkargs.md b/goals/archive/G-030-maketcl-punkargs.md new file mode 100644 index 00000000..d1c50a80 --- /dev/null +++ b/goals/archive/G-030-maketcl-punkargs.md @@ -0,0 +1,189 @@ +# G-030 make.tcl dogfoods punk::args: tabled usage, declared subcommands, prompt-free flags + +Status: achieved 2026-07-14 +Scope: src/make.tcl (dispatch, help, prompts), src/bootsupport/AGENTS.md + src/modules/AGENTS.md (bootstrap-tracked staleness contract), src/modules/punk/args-999999.0a1.0.tm (only as consumed) +Goal: make.tcl - the first surface a developer sees - parses its subcommands and options via punk::args and showcases the tabled usage output for help and argument errors, every interactive y/n prompt gains a declared flag equivalent so agents can drive make.tcl with arguments instead of piped input, punk::args joins the bootstrap-tracked staleness set, and the boot phase plus the environment-repair commands keep working with degraded plain help when the bootsupport punk::args (or the table-rendering stack) is stale or unavailable. +Acceptance: `tclsh src/make.tcl` and `-help` render punk::args tabled usage listing every subcommand with a summary, and `make.tcl help ` (or ` -help`) shows that subcommand's definition; invalid arguments produce a punk::args usage error rather than ad-hoc messages; every y/n prompt has a documented flag equivalent (proven at least for vfscommonupdate and the project-build confirmations: a run with the flag completes non-interactively with stdin closed) and a non-interactive stdin without the flag fails fast with usage rather than hanging or half-aborting; punk::args is added to the bootstrap-tracked buildversion set with the doc contract updated (src/bootsupport/AGENTS.md, src/modules/AGENTS.md); with bootsupport punk::args unavailable or unloadable, make.tcl still boots and `check`, `bootsupport` and `modules` remain usable with plain-text fallback help (the guarded-require degrade rule); layout make.tcl copies follow via the established sync/G-027 channels (noted, not hand-synced). + +## Context + +make.tcl is the first surface a developer meets in a punkshell-derived project, +but its command handling predates the ecosystem's own tooling: a hand-built +help text, a bare `known_commands` list, ad-hoc argument handling per +subcommand, and interactive y/n prompts (`vfscommonupdate`'s REPLACE +confirmation, the project-build confirmations, bootsupport staleness prompts). +Eating our own dogfood - punk::args definitions per subcommand with the tabled +usage rendering - both showcases the ecosystem where it is most visible and +makes the parsing declarative. + +The prompts are the practical payoff: agent-driven builds currently pipe `y` +into stdin (fragile, undiscoverable - observed 2026-07-07 while rebuilding +tomlish.exe). With punk::args parsing, prompt-free operation is just another +declared option per subcommand, and non-interactive stdin without the flag can +fail fast with usage instead of hanging on a read or half-aborting. + +Precedents already in-tree: src/tests/runtests.tcl parses via punk::args +((script)::runtests definition), and the tomlish cmdline app presents tabled +usage as its first surface. + +## Approach + +- One PUNKARGS definition per subcommand (@cmd -summary/-help + opts), plus a + top-level definition enumerating subcommands - replacing punkboot_gethelp + and the hand-maintained help strings. `make.tcl`, `make.tcl -help`, and + per-subcommand help all render through punk::args::usage. +- Prompt policy: interactive stdin -> prompt as today (default); flag supplied + (e.g. -confirm 0 / -y, naming decision recorded here) -> proceed without + prompting; non-interactive stdin without the flag -> usage error, fast. + The bootsupport staleness prompt keeps its abort/prompt/proceed + classification but gains the same flag route. +- **Degradation is a hard requirement** (the 2026-07-06/07 incidents are the + cautionary tale: a stale bundled fileutil disabled the very make.tcl step + needed to fix it). The boot phase stays self-contained; punk::args is + guarded-lazily required post-boot (the punkboot::utils pattern documented in + src/bootsupport/AGENTS.md); when unavailable, dispatch and the repair + commands (check, bootsupport, modules) keep working with plain-text fallback + help. Note the tabled rendering also pulls punk::ansi/textblock/punk::char - + exactly the modules whose same-version staleness broke shellfilter this week + - so rendering must degrade independently of parsing (punk::args plain + output when the ANSI stack is unhealthy). +- Staleness tracking: punk::args joins the bootstrap-tracked buildversion set + (currently punkcheck, punk::repo, punk::mix, punk::tdl) with the same + bump-at-least-minor-on-call-site-API-change discipline; whether the + rendering stack is also tracked or left to degrade is an implementation + decision to record here (initial lean: track punk::args only - it is the + parsing contract; rendering degrades). +- Layout copies of make.tcl follow through the existing punkcheck-tracked + sync (custom/_project) and the G-012/G-027 channels for the rest - noted in + completion reports, never hand-synced. + +## Alternatives considered + +- Ad-hoc -y flags bolted onto the current hand parsing - rejected: solves the + agent problem but leaves the first-surface help un-showcased and the parsing + divergent from the ecosystem's own conventions. +- Requiring punk::args at boot (no fallback) - rejected: make.tcl must be able + to repair the very bootsupport snapshot it loads punk::args from. + +## Notes + +- Related: G-015 (agents driving punk tooling non-interactively), G-024 + (mapvfs toml errors deserve the same declared-argument quality), G-025 (the + version-report subcommand should be born punk::args-defined), G-027 (pull + updates deliver the improved make.tcl to derived projects). +- Observation parked here from the same session: runtests/make.tcl-adjacent + tooling that returns result dicts should document their key shape (see the + runx -tcl exitcode note in G-015's detail). +- Archived-goal references in this file: G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md). + +## Progress + +2026-07-14: implemented whole and verified; punkproject 0.12.24. + +### What shipped (src/make.tcl) + +- Declarative dispatch: punk::args definitions `(script)::punkboot` (top level: + subcommand leader with -choicegroups/-choicelabels subtables) and + `(script)::punkboot::` for all 15 subcommands, built in + `::punkboot::argdoc` from single-source dicts (SUMMARIES/HELPTEXTS/SUBOPTS/ + OPT_SYNOPSES) plus shared option fragments (OPT_CONFIRM/OPT_DIRTYABORT/ + OPT_FORCEKILL) composed via multi-part `punk::args::define`. Explicit + `@form -synopsis` per definition so usage shows the real invocation + (`make.tcl modules ?-dirty-abort? ?-confirm 0|1?`) rather than the internal id. +- `make.tcl` / `-help` / `help ?subcommand?` / ` -help` all render + punk::args tabled usage (the missing/broken bootsupport-package NOTE was + factored into `punkboot_availability_note` and is appended to both the tabled + and the plain-fallback help). Invalid flags and unknown subcommands raise + punk::args usage errors (exit 1); unambiguous subcommand prefixes resolve + (`make.tcl vfsc...`). +- `shell` is a declared passthrough: its definition documents that trailing args + go to the repl unparsed. +- Prompt policy - **naming decision: `-confirm 0|1` (boolean, default 1)**, + declared on every subcommand that can hit a confirmation point: + - `-confirm 1` (default): prompt when stdin is an interactive terminal; + when stdin is NOT interactive, abort fast at the confirmation point with + guidance instead of reading stdin (no more piped `y`, no half-aborts - + the old vfscommonupdate decline path printed "done" and exited 0; it now + exits 1 with "-aborted-"). + - `-confirm 0`: never prompt; documented per-site resolutions: staleness + minor-bump gate -> proceed, vfscommonupdate REPLACE -> proceed, kit + source/target type mismatch -> skip that kit (only an interactive 'y' + can force building a mismatched kit). + All three `gets stdin` confirmation sites reworked; interactivity probe is + `::punkboot::lib::stdin_is_interactive` (8.7+/9 `-inputmode` on terminal + channels only; **Tcl 8.6 caveat**: no probe exists, stdin is assumed + interactive there - piped 8.6 runs should pass -confirm explicitly; + documented in the option help and bootsupport AGENTS.md). +- Staleness tracking: punk::args joined `_runtime_deps` + (`punk/args-buildversion.txt`). **Decision recorded: track punk::args only** - + it is the parsing contract; the tabled-rendering stack (punk::ansi, textblock) + stays untracked and degrades instead. +- Degrade rule implemented at three levels: (1) boot requires for + punk::args/punk::ansi/textblock are guarded (stderr note, no abort); + (2) definition build is caught - any failure falls back to a self-contained + scan (rewritten from the old hand parser; handles -k/-dirty-abort/-confirm + and help) plus plain-text punkboot_gethelp; (3) rendering degrades + independently of parsing (errorstyle minimal when the ANSI stack is + unhealthy; usage render failure falls back to plain help). + `PUNKBOOT_PLAIN=1` forces the degraded mode (troubleshooting/test hook). +- Flag plumbing: `-k` (project/vfs/bin), `-dirty-abort` (the nine + build/promotion commands) and `-confirm` now flow from parsed opts into + `::punkboot::opt_forcekill/opt_dirty_abort/opt_confirm`; the old + `lsearch $::argv` sites read those variables instead. + +### Verification (all under tclsh 9.0.2, from repo root) + +- Bare/`-help`/`help `/` -help`: tabled usage with grouped + subcommand/summary subtables; `help` with a bad subject and an unknown + subcommand both raise choiceviolation usage errors (exit 1); + `modules -bogus` raises invalidoption (exit 1). +- `vfscommonupdate fast abort exit 1 with -confirm guidance, + no changes; `vfscommonupdate -confirm 0 completed exit 0, + idempotent (no git churn). +- Staleness flag route proven live: adding punk::args to _runtime_deps + immediately tripped the minor gate (bootsupport 0.5.0 vs source 0.12.0): + `info ` want an explicit `@form -synopsis` (adopted + here; possible future punk::args nicety: fall back to @cmd -name for + synopsis rendering). + +### Deferred / out of scope + +- The kit-type-mismatch confirmation cannot be triggered without a mismatched + runtime/target configuration - its -confirm handling is code-reviewed, not + runtime-proven (the prompt sites share the same policy helper). +- punk::args error-selection improvement above left to punk::args goals + (G-072/G-073 territory) rather than patched mid-goal. +- Old `echo y | make.tcl vfscommonupdate` agent workflow is retired; docs + updated (src/AGENTS.md, src/tests/shell/AGENTS.md, src/bootsupport/AGENTS.md, + src/modules/AGENTS.md). diff --git a/punkproject.toml b/punkproject.toml index 23b8ac24..d7b52db7 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,4 +1,4 @@ [project] name = "punkshell" -version = "0.12.23" +version = "0.12.24" license = "BSD-2-Clause" diff --git a/src/AGENTS.md b/src/AGENTS.md index a85a45dd..4b380226 100644 --- a/src/AGENTS.md +++ b/src/AGENTS.md @@ -66,7 +66,8 @@ Recovery after a wrong path guess: - Use `tclsh src/make.tcl vendorupdate` to refresh vendormodules from config. It warns (non-fatal) for each source project whose fossil/git checkout is dirty - vendored artifacts built from a dirty tree have no committed provenance; commit in the source project to clear the warning (enforcement policy tracked by goal G-026). - All build/promotion commands (`project`, `packages`, `modules`, `libs`, `vfs`, `vfslibs`, `bin`, `bootsupport`, `vfscommonupdate`) warn similarly when this project's own `src/` has uncommitted fossil/git changes (dirt outside `src/` is ignored). Warn-only by default; pass `-dirty-abort` to make the check aborting. For evaluating uncommitted source without a build, prefer ` src` / ` src shell`. The check is `punkboot::utils::vcs_dirty_warnings` (optional scope argument) loaded guardedly from bootsupport - if the snapshot is stale/missing the check degrades to a skip notice (but `-dirty-abort` then aborts rather than silently losing the requested strictness). - Provenance warnings (dirty-src gate + vendorupdate source-project check) print with a plain column-0 `PROVENANCE-WARNING:` token (grep for it in captured build output) and are recapped at the end of the run via make.tcl's wrapped `::exit`. Interactive terminal runs get a 3-second ctrl-c grace countdown before a dirty build proceeds; piped/agent runs skip it. `tclsh src/make.tcl check` reports the current src provenance status and what the build commands would do. -- Use `tclsh src/make.tcl vfscommonupdate` to rebuild `_vfscommon.vfs`. +- Use `tclsh src/make.tcl vfscommonupdate` to rebuild `_vfscommon.vfs`. The REPLACE confirmation prompts on an interactive terminal; unattended/agent runs must pass `-confirm 0` (with the default `-confirm 1` and a piped/closed stdin, make.tcl aborts fast with guidance instead of reading stdin - do not pipe `y`). +- make.tcl subcommands and flags are punk::args-declared (G-030): `tclsh src/make.tcl help ?subcommand?` or ` -help` shows tabled usage; invalid arguments produce punk::args usage errors. The dispatch degrades to plain scan/help when the bootsupport punk::args (or its rendering stack) is stale or unavailable; `PUNKBOOT_PLAIN=1` forces the degraded mode for troubleshooting. - Uncommitted `make.tcl`-generated outputs may be batched into one commit, regardless of how many `make.tcl` invocations produced them. This covers punkcheck-managed build outputs that are VCS-tracked: `src/bootsupport/`, `_vfscommon.vfs/modules` + `/lib`, and declared per-kit `*.vfs/lib_tcl/` subfolders. (Root `modules/`, `lib/`, `modules_tcl/`, `lib_tcl/` are gitignored and never committed.) Each module's old→new version rename is atomic; a regeneration reflects one build-output refresh, not independent hand-edits. This is a carve-out from generic "split aggressively" commit guidance for punkcheck-managed build outputs only — it does not cover user-curated VFS content (`_config/`, per-kit `*.vfs/` outside declared `lib_tcl` subfolders, `_aside/`, `mkzipfix.vfs`, `_vfscommon.vfs/doc`), which commits separately per its own concerns. - Use `punk make.tcl project` or `punk902z make.tcl project` inside Punk shell when building binaries through Punk. - Binary images are platform-specific; build on each target platform rather than expecting a cross-platform flag. @@ -81,7 +82,7 @@ Recovery after a wrong path guess: - Review VS Code Tcl lint diagnostics before submitting new agent-produced Tcl code, but do not use lint tooling to reformat existing code. - When touching VFS payloads, describe regeneration steps in durable docs if the workflow changes. - When a tool summary reports cleanup issues such as `git diff --check` whitespace errors, verify against exact command output and exit code before running secondary scans or reporting the issue. -- `make.tcl` performs version-aware bootsupport staleness detection: major bumps abort, minor bumps prompt (y/N), patch bumps warn-and-proceed. See `src/bootsupport/AGENTS.md` "Bootsupport Staleness Handling" for the full contract and the version-bump discipline agents must follow. +- `make.tcl` performs version-aware bootsupport staleness detection: major bumps abort, minor bumps prompt (y/N; `-confirm 0` proceeds without prompting, non-interactive stdin without it aborts fast), patch bumps warn-and-proceed. See `src/bootsupport/AGENTS.md` "Bootsupport Staleness Handling" for the full contract and the version-bump discipline agents must follow. - Project-level version bumps are governed by the root `AGENTS.md` "Project Versioning" section. Any `src/` change that ships user-visible shell behaviour requires a `punkproject.toml` version bump and a `CHANGELOG.md` entry as part of the DOX closeout pass. Run `tclsh src/make.tcl projectversion` to verify. ## Verification diff --git a/src/bootsupport/AGENTS.md b/src/bootsupport/AGENTS.md index a22953c6..f5298b46 100644 --- a/src/bootsupport/AGENTS.md +++ b/src/bootsupport/AGENTS.md @@ -21,17 +21,19 @@ Modules and libraries required during the build/bootstrap/make process before th ## Bootsupport Staleness Handling -`src/make.tcl` compares each tracked bootsupport module's highest `.tm` version against the corresponding `src/modules/<...>-buildversion.txt` for these runtime-critical packages: `punkcheck`, `punk::repo`, `punk::mix`, `punk::tdl`. When the source version is higher than the bootsupport version, `make.tcl` classifies the bump level from the version delta and reacts as follows (except for the `check` command, which only reports staleness at the end of its output): +`src/make.tcl` compares each tracked bootsupport module's highest `.tm` version against the corresponding `src/modules/<...>-buildversion.txt` for these runtime-critical packages: `punkcheck`, `punk::repo`, `punk::mix`, `punk::tdl`, `punk::args`. When the source version is higher than the bootsupport version, `make.tcl` classifies the bump level from the version delta and reacts as follows (except for the `check` command, which only reports staleness at the end of its output): - **Major bump** (e.g 1.x -> 2.x): abort unconditionally. Breaking change means the old bootsupport snapshot will not work. -- **Minor bump** (e.g 0.1 -> 0.2): prompt the user (y/N, default No) whether to proceed. Backward-compat aliases *should* keep old bootsupport functional, but the user must opt in. +- **Minor bump** (e.g 0.1 -> 0.2): prompt the user (y/N, default No) whether to proceed. Backward-compat aliases *should* keep old bootsupport functional, but the user must opt in. With `-confirm 0` proceed without prompting; with the default `-confirm 1` and a non-interactive stdin, abort fast with guidance instead of reading stdin (G-030 prompt policy). - **Patch bump** (e.g 0.1.1 -> 0.1.2): warn and proceed. No prompt. -The prompt is self-contained Tcl (modeled on `punk::lib::askuser` via `::punkboot::lib::bootsupport_prompt_yesno`) because it runs in the early boot phase before punk packages are guaranteed loaded. The classifier is `::punkboot::lib::bootsupport_bump_level`. +The prompt is self-contained Tcl (modeled on `punk::lib::askuser` via `::punkboot::lib::bootsupport_prompt_yesno`) because it runs in the early boot phase before punk packages are guaranteed loaded. The classifier is `::punkboot::lib::bootsupport_bump_level`; stdin interactivity is probed by `::punkboot::lib::stdin_is_interactive` (Tcl 8.6 lacks the `-inputmode` probe and is assumed interactive - piped 8.6 runs should pass `-confirm` explicitly). + +`punk::args` is tracked because make.tcl dogfoods it for subcommand dispatch and tabled help (G-030). Deliberately, only punk::args itself joined the tracked set - it is the parsing contract; its tabled-rendering stack (`punk::ansi`, `textblock` and their deps) is untracked and left to degrade (make.tcl falls back to minimal errorstyle / plain-text help when the rendering stack is unhealthy, and to fully self-contained scan-based dispatch when punk::args itself is unavailable - the guarded-require degrade rule). `PUNKBOOT_PLAIN=1` forces the degraded dispatch/help for troubleshooting. ### Version-Bump Discipline (agent-relevant) -Because the staleness classifier keys off the version delta, under-bumping a module (e.g recording a patch bump when the call-site API actually changed) will cause `make.tcl` to mis-classify the bump and either wrongly proceed without prompting or wrongly abort. This discipline applies specifically to the four files the classifier reads — `punkcheck-buildversion.txt`, `punk/repo-buildversion.txt`, `punk/mix-buildversion.txt` (top-level `punk::mix` only, not its submodules), and `punk/tdl-buildversion.txt`. Follow the rules in `src/modules/AGENTS.md` "Versioning And Releases" exactly: +Because the staleness classifier keys off the version delta, under-bumping a module (e.g recording a patch bump when the call-site API actually changed) will cause `make.tcl` to mis-classify the bump and either wrongly proceed without prompting or wrongly abort. This discipline applies specifically to the five files the classifier reads — `punkcheck-buildversion.txt`, `punk/repo-buildversion.txt`, `punk/mix-buildversion.txt` (top-level `punk::mix` only, not its submodules), `punk/tdl-buildversion.txt`, and `punk/args-buildversion.txt`. Follow the rules in `src/modules/AGENTS.md` "Versioning And Releases" exactly: - Call-site API change (new flags, renamed flags, changed call shapes) -> at least a **minor** bump, even if the module's own interface is unchanged. - Backward-compatible API additions (new procs, new flags with defaults) -> **minor**. @@ -42,7 +44,7 @@ For modules outside this tracked set (including `punk::mix::util`, `punk::mix::c If the set of runtime-critical packages in `make.tcl`'s `_runtime_deps` list ever grows, update this list (and the matching one in `src/modules/AGENTS.md`) so the two stay in sync. -After changing any build-critical module (`punkcheck`, `punk::repo`, `punk::mix`, `punk::tdl`), rebuild bootsupport with `cd src && tclsh make.tcl modules && tclsh make.tcl bootsupport` so the snapshot matches the source version and staleness does not trip. +After changing any build-critical module (`punkcheck`, `punk::repo`, `punk::mix`, `punk::tdl`, `punk::args`), rebuild bootsupport with `cd src && tclsh make.tcl modules && tclsh make.tcl bootsupport` so the snapshot matches the source version and staleness does not trip (append `-confirm 0` for unattended runs). ## Work Guidance diff --git a/src/make.tcl b/src/make.tcl index 1a7dc687..b46d54cf 100644 --- a/src/make.tcl +++ b/src/make.tcl @@ -20,7 +20,6 @@ namespace eval ::punkboot { variable scriptfolder [file normalize [file dirname [info script]]] variable foldername [file tail $scriptfolder] variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list] - variable non_help_flags [list -k -dirty-abort] variable help_flags [list -help --help /? -h] variable known_commands [list project modules libs packages vfs vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion] } @@ -311,6 +310,22 @@ proc ::punkboot::lib::bootsupport_bump_level {old_ver new_ver} { return "patch" } +# stdin interactivity probe for the confirmation-prompt policy (G-030). +# Tcl 8.7+/9: -inputmode is supported only on terminal channels, so a successful +# query means stdin is a console. Under Tcl 8.6 there is no -inputmode anywhere and +# no reliable pure-Tcl tty test in the boot phase - we return 1 (assume interactive, +# the pre-G-030 behaviour of reading stdin) so a real 8.6 console still gets its +# prompt. Piped/non-interactive runs under 8.6 should pass -confirm explicitly. +proc ::punkboot::lib::stdin_is_interactive {} { + if {![catch {chan configure stdin -inputmode}]} { + return 1 + } + if {[package vsatisfies [package provide Tcl] 8.7-]} { + return 0 + } + return 1 +} + # Self-contained y/N prompt. Returns 1 for y/yes (case-insensitive), 0 otherwise. # Used by the staleness abort path to ask the user whether to proceed past a # minor-version bump. Default is No (Enter = abort) so accidental Enter is safe. @@ -530,6 +545,7 @@ if {$bootsupport_paths_exist || $sourcesupport_paths_exist} { } punk::repo punk/repo-buildversion.txt punk/repo-*.tm {*}{ } punk::mix punk/mix-buildversion.txt punk/mix-*.tm {*}{ } punk::tdl punk/tdl-buildversion.txt punk/tdl-*.tm {*}{ + } punk::args punk/args-buildversion.txt punk/args-*.tm {*}{ }] set _stale_modules [list] foreach {pkg buildversion_rel bootsupport_glob} $_runtime_deps { @@ -565,9 +581,16 @@ if {$bootsupport_paths_exist || $sourcesupport_paths_exist} { package require punk::mix package require punkcheck package require punk::lib - package require punk::args - package require punk::ansi - package require textblock + #G-030 degrade rule: punk::args (declarative dispatch/help) and its tabled-rendering stack + #(punk::ansi, textblock) are guarded - a stale/missing snapshot of these must never brick + #the make.tcl commands used to repair it (check, bootsupport, modules). Dispatch and help + #fall back to the self-contained scan / plain-text help further below when absent. + foreach _optpkg {punk::args punk::ansi textblock} { + if {[catch {package require $_optpkg} _opterr]} { + puts stderr "make.tcl: boot package $_optpkg unavailable from bootsupport ($_opterr) - continuing degraded (plain help/argument handling)" + } + } + unset -nocomplain _optpkg _opterr set package_paths_modified 1 @@ -1364,7 +1387,13 @@ proc ::punkboot::punkboot_gethelp {args} { append h " - run the punk shell using bootsupport libraries." \n append h " $scriptname projectversion" \n append h " - advisory check: verify CHANGELOG.md matches punkproject.toml and warn if src/ has changes since the last project-version bump." \n \n + append h " $scriptname help ?subcommand?" \n + append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname -help)" \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 + append h " Use -confirm 0 for unattended runs: the bootsupport minor-staleness gate and the vfscommonupdate REPLACE" \n + append h " confirmation proceed without prompting; kits with a source/target kit-type mismatch are skipped." \n append h " -dirty-abort" \n append h " - abort build/promotion commands (project packages modules libs vfs vfslibs bin bootsupport vfscommonupdate) when src/ has" \n append h " uncommitted VCS changes. Default is warn-only: artifacts built from dirty src have no committed provenance." \n @@ -1372,6 +1401,20 @@ proc ::punkboot::punkboot_gethelp {args} { append h " Use '$scriptname check' to see the current provenance status. To evaluate uncommitted source without building," \n append h " use ' src' or ' src shell'." \n \n append h "" \n + append h [punkboot_availability_note] + return $h +} +#Missing/broken bootsupport-package NOTE shown with help output. +#Factored out of punkboot_gethelp (G-030) so both the punk::args tabled help path and the +#plain-text fallback help append the same information. Returns "" when there is nothing to report. +proc ::punkboot::punkboot_availability_note {} { + variable pkg_availability + if {![info exists pkg_availability]} { + return "" + } + global A + if {![array size A]} {punkboot::define_global_ansi} + set h "" if {[llength [dict get $pkg_availability missing]] || [llength [dict get $pkg_availability broken]]} { set has_recommended 0 set has_nonoptional 0 @@ -1389,10 +1432,10 @@ proc ::punkboot::punkboot_gethelp {args} { if {$has_recommended || $has_nonoptional} { append h "* $A(HIGHLIGHT)** NOTE ** ***$A(RST)" \n append h " punk boot has detected that the following packages could not be loaded from the bootsystem path:" \n - set missing_out [get_display_missing_packages $pkg_availability] + set missing_out [get_display_missing_packages $pkg_availability] append h $missing_out - set broken_out [get_display_broken_packages $pkg_availability] + set broken_out [get_display_broken_packages $pkg_availability] append h $broken_out append h "* $A(HIGHLIGHT)** *** *** ***$A(RST)" \n @@ -1402,7 +1445,7 @@ proc ::punkboot::punkboot_gethelp {args} { append h " Call 'make.tcl check' and examine the last table (which includes bootsupport + executable-provided packages)" \n append h " See if there are any items marked missing or broken that aren't marked as '(known optional)'" \n append h " If all are marked (known optional) then it should work." \n - append h " A package marked (known optional) and (RECOMMENDED) may make the build/install processes run a lot faster. (e.g tcllibc)" \n + append h " A package marked (known optional) and (RECOMMENDED) may make the build/install processes run a lot faster. (e.g tcllibc)" \n append h "* $A(HIGHLIGHT)** *** *** ***$A(RST)" \n\n #append h "Successfully Loaded packages:" \n #append h " " [join $::punkboot::pkg_loaded "\n "] \n @@ -1417,124 +1460,385 @@ proc ::punkboot::punkboot_gethelp {args} { ############################################################################################################## ############################################################################################################## set scriptargs $::argv -namespace eval ::punkboot::app { - namespace ensemble create - proc help {args} { - puts "test help" - } -} -namespace eval ::punkboot::app::argdoc { - proc punkboot_subcommands {} { - dict set groups "package" {packages modules libs} - dict set groups "informational" {check info help} - return [punk::args::ensemble_subcommands_definition -groupdict $groups -columns 4 ::punkboot::app] - } - #punk::args::define { - # @id -id punkboot::app - # @cmd -name punkboot::app\ - # -summary\ - # "Project builder"\ - # -help\ - # "" - # @form -form help - # @leaders - # subcommand -type "literal(help)" - # @opts - # @values - # what -type string -choices {modules libs shell} - - # @form -form modules - # subcommand -type "literal(modules)" - - # @form -form libs - # subcommand -type "literal(libs)" - - # @form -form shell - # subcommand -type "literal(shell)" - # arg -type any -optional 1 -multiple 1 - #} - punk::args::define { - @dynamic - @id -id ::punkboot::app - @cmd -name ::punkboot::app\ - -summary\ - "Project builder"\ - -help\ - "" - @leaders - ${[punkboot::app::argdoc::punkboot_subcommands]} - } -} -namespace eval ::punkboot::app { - proc test {args} { - puts "test" +# ---------------------------------------------------------------------------------------------- +# G-030: make.tcl dogfoods punk::args. +# Subcommands and their options are declared as punk::args definitions ((script)::punkboot and +# (script)::punkboot::) and parsed with punk::args::parse - 'make.tcl', +# 'make.tcl help ?subcommand?' and 'make.tcl -help' render tabled usage, and invalid +# arguments produce punk::args usage errors. +# Degrade rule (hard requirement - see goals/archive/G-030-maketcl-punkargs.md): punk::args is +# guarded. When it (or a definition feature it needs) is unavailable from bootsupport, dispatch +# falls back to the self-contained scan below and help falls back to plain-text +# ::punkboot::punkboot_gethelp, so the environment-repair commands (check, bootsupport, modules) +# keep working. The tabled rendering additionally depends on the punk::ansi/textblock stack - +# rendering degrades independently of parsing (minimal errorstyle / plain fallback help) when +# that stack is unhealthy. Only punk::args itself joins the bootstrap-tracked staleness set +# (_runtime_deps above): it is the parsing contract; the rendering stack is left to degrade. +# ---------------------------------------------------------------------------------------------- +set ::punkboot::punkargs_ok 0 +#PUNKBOOT_PLAIN=1 forces the plain fallback dispatch/help - a troubleshooting/test hook for the +#degrade contract (e.g when a half-broken punk::args snapshot loads but misbehaves). +if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBOOT_PLAIN)]} { + puts stderr "make.tcl: PUNKBOOT_PLAIN set - using plain argument handling and help" +} elseif {![catch {package require punk::args}]} { + if {![catch { + namespace eval ::punkboot::argdoc { + #single source for the subcommand one-line summaries: each subcommand definition's + #@cmd -summary and the top-level subcommand -choicelabels are both built from this. + variable SUMMARIES { + project "Full project build - packages plus kit/zipkit executables from src/vfs and src/runtime" + packages "Build .tm modules and pkgIndex.tcl libraries from src into (no kit executables)" + modules "Build .tm modules from src/modules, src/vendormodules etc into /modules etc" + libs "Build pkgIndex.tcl libraries from src/lib, src/vendorlib etc into /lib etc" + vfs "Build kit/zipkit executables from src/vfs and src/runtime into /bin" + vfslibs "Propagate declared vendored platform-library packages into kit vfs lib_tcl trees" + bin "Install executables from src/bin into /bin, then build kits as for vfs" + vendorupdate "Update src/vendormodules based on src/vendormodules/include_modules.config" + bootsupport "Update src/bootsupport modules (and project-layout copies) from built project modules" + vfscommonupdate "Replace src/vfs/_vfscommon.vfs modules and libs with the project's built modules and libs" + info "Show the name and base folder of the project to be built" + check "Show module/library paths and any potentially problematic packages for running this script" + projectversion "Advisory check: CHANGELOG.md vs punkproject.toml and src/ changes since last version bump" + shell "Run the punk shell using bootsupport libraries" + help "Show usage for make.tcl or one of its subcommands" + } + variable HELPTEXTS { + project + "Run the full project build - includes src/vfs/* checks and builds. + Builds/copies .tm modules and pkgIndex.tcl based libraries from src to + /modules, /lib etc, propagates declared vendored + platform-libraries into kit vfs trees (as for vfslibs), then scans + src/runtime and src/vfs folders to build kit/zipkit executables and + installs them to /bin." + packages + "Build (or copy if build not required) both .tm and pkgIndex.tcl based + packages from src to their corresponding locations under . + This does not scan src/runtime and src/vfs folders to build kit/zipkit + executables." + modules + "Build (or copy if build not required) .tm modules from src/modules, + src/vendormodules etc to their corresponding locations under . + This does not scan src/runtime and src/vfs folders to build kit/zipkit + executables." + libs + "Build (or copy if build not required) pkgIndex.tcl based libraries from + src/lib, src/vendorlib etc to their corresponding locations under + . + This does not scan src/runtime and src/vfs folders to build kit/zipkit + executables." + vfs + "Scan src/vfs and src/runtime folders and build kit/zipkit executables + into /bin. + Does not first rebuild modules/libs - use 'make.tcl project' for the + full pipeline." + vfslibs + "Propagate declared vendored platform-library packages into kit vfs + lib_tcl trees. + Declarations (per-package per-kit, with superseded-version removal) + live in src/runtime/vendorlib_vfs.toml. + Also runs automatically as part of 'make.tcl project'." + bin + "Install executables from src/bin to /bin, then check vfs + folders and build kit/zipkit executables as for the vfs subcommand." + vendorupdate + "Update the src/vendormodules based on src/vendormodules/include_modules.config. + Update the src/vendorlib based on src/vendorlib/config.toml (todo)." + bootsupport + "Update the src/bootsupport modules as well as the project-layout + src/bootsupport modules if those folders exist. + Bootsupport modules are pulled from locations specified in + include_modules.config files within each src/bootsupport subdirectory. + This should usually be from modules that have been built and tested in + /modules, /lib etc. + Bootsupport modules are available to make.tcl." + vfscommonupdate + "Update the src/vfs/_vfscommon.vfs from compiled src/modules and src/lib etc. + Before calling this (followed by 'make.tcl project') - you can test using + '(.exe) dev' - this will load modules from your /modules, + /lib paths instead of from the kit/zipkit. + Replacing the _vfscommon.vfs contents requires confirmation - see -confirm." + info + "Show the name and base folder of the project to be built." + check + "Show module/library paths and any potentially problematic packages for + running this script. + Also reports bootsupport staleness and the src provenance status (what + the build/promotion commands would do)." + projectversion + "Advisory check: verify CHANGELOG.md matches punkproject.toml and warn + if src/ has changes since the last project-version bump." + } + #shared option fragments composed into the per-subcommand definitions below + variable OPT_CONFIRM { + -confirm -type boolean -default 1 -help\ + "Interactive y/n confirmation policy. + -confirm 1 (default): confirmation points prompt when stdin is an + interactive terminal. When stdin is NOT interactive (piped/closed), + make.tcl aborts fast at the confirmation point with guidance instead + of reading stdin. + -confirm 0: never prompt - each confirmation point takes its documented + non-interactive resolution: + bootsupport minor-version staleness gate -> proceed + vfscommonupdate REPLACE confirmation -> proceed + kit source/target type mismatch -> skip building that kit + Note: Tcl 8.6 lacks the terminal probe (-inputmode) so stdin is assumed + interactive there - piped runs under 8.6 should always pass -confirm + explicitly." + } + variable OPT_DIRTYABORT { + -dirty-abort -type none -default 0 -help\ + "Abort when src/ has uncommitted VCS changes. + Default is warn-only: artifacts built from dirty src have no committed + provenance. Warnings carry a plain PROVENANCE-WARNING: prefix (greppable + in redirected output) and are recapped at the end of the run. + Use 'make.tcl check' to see the current provenance status. To evaluate + uncommitted source without building, use ' src' or + ' src shell'." + } + variable OPT_FORCEKILL { + -k -type none -default 0 -help\ + "Terminate running processes matching the executable being built + (if applicable) so the build can install over it." + } + #which shared option fragments each subcommand declares + #(shell and help have bespoke definitions below: shell passes trailing args + # through to the repl untouched, help takes a subject value) + variable SUBOPTS { + project {OPT_FORCEKILL OPT_DIRTYABORT OPT_CONFIRM} + packages {OPT_DIRTYABORT OPT_CONFIRM} + modules {OPT_DIRTYABORT OPT_CONFIRM} + libs {OPT_DIRTYABORT OPT_CONFIRM} + vfs {OPT_FORCEKILL OPT_DIRTYABORT OPT_CONFIRM} + vfslibs {OPT_DIRTYABORT OPT_CONFIRM} + bin {OPT_FORCEKILL OPT_DIRTYABORT OPT_CONFIRM} + vendorupdate {OPT_CONFIRM} + bootsupport {OPT_DIRTYABORT OPT_CONFIRM} + vfscommonupdate {OPT_DIRTYABORT OPT_CONFIRM} + info {OPT_CONFIRM} + check {} + projectversion {} + } + #synopsis fragments matching the shared option fragments (explicit @form -synopsis + #so usage shows the real invocation 'make.tcl ...' rather than the + #internal definition id) + variable OPT_SYNOPSES { + OPT_FORCEKILL "?-k?" + OPT_DIRTYABORT "?-dirty-abort?" + OPT_CONFIRM "?-confirm 0|1?" + } + foreach {sub optvars} $SUBOPTS { + set synparts [list "make.tcl $sub"] + foreach ov $optvars { + lappend synparts [dict get $OPT_SYNOPSES $ov] + } + set defparts [list] + lappend defparts "@id -id (script)::punkboot::$sub" + lappend defparts "@cmd -name [list "make.tcl $sub"] -summary [list [dict get $SUMMARIES $sub]] -help [list [dict get $HELPTEXTS $sub]]" + lappend defparts "@form -synopsis [list [join $synparts { }]]" + lappend defparts "@opts" + foreach ov $optvars { + lappend defparts [set $ov] + } + lappend defparts "@values -min 0 -max 0" + punk::args::define {*}$defparts + } + punk::args::define\ + "@id -id (script)::punkboot::shell"\ + "@cmd -name [list "make.tcl shell"] -summary [list [dict get $SUMMARIES shell]] -help [list\ + "Run the punk shell (repl) using bootsupport libraries. + All arguments after the shell subcommand are passed through to the + repl untouched (they are not parsed or validated by make.tcl)."]"\ + {@form -synopsis "make.tcl shell ?arg ...?"}\ + {@values -min 0 -max -1 + arg -type any -optional 1 -multiple 1 -help\ + "Arguments passed through to the punk repl."} + punk::args::define\ + "@id -id (script)::punkboot::help"\ + "@cmd -name [list "make.tcl help"] -summary [list [dict get $SUMMARIES help]] -help [list\ + "Show tabled usage for make.tcl as a whole, or for a single subcommand. + Equivalent to 'make.tcl -help'."]"\ + {@form -synopsis "make.tcl help ?subcommand?"}\ + "@values -min 1 -max 1"\ + "subject -type string -optional 0 -choices [list [dict keys $SUMMARIES]] -help {Subcommand to show usage for.}" + #top-level definition: the subcommand table rendered by 'make.tcl' / 'make.tcl -help' + variable SUBGROUPS { + "build & promotion" {project packages modules libs vfs vfslibs bin} + "source maintenance" {vendorupdate bootsupport vfscommonupdate} + "informational" {info check projectversion help} + "interactive" {shell} + } + punk::args::define\ + "@id -id (script)::punkboot"\ + "@cmd -name make.tcl -summary {punkshell project build tool (punk boot)} -help [list\ + "punk boot: make any tclkits and modules in /src folders and place + them and associated data files/scripts in the parent folder of src - e.g in + 'bin' and 'modules' folders at the same level as 'src'. + + General usage: make.tcl ?flags? + 'make.tcl help ' or 'make.tcl -help' shows a + subcommand's own usage. Interactive y/n confirmations can be driven + non-interactively with the -confirm flag declared on the relevant + subcommands."]"\ + {@form -synopsis "make.tcl ?subcommand? ?flags?"}\ + "@leaders -min 1 -max 1"\ + "subcommand -type string -optional 0 -choicecolumns 1 -choicegroups [list $SUBGROUPS] -choicelabels [list $SUMMARIES] -help\ + {Use 'make.tcl help ' or 'make.tcl -help' for details of a subcommand.}" + unset -nocomplain sub optvars defparts ov + } + } _defserr]} { + set ::punkboot::punkargs_ok 1 + } else { + puts stderr "make.tcl: punk::args subcommand definitions failed to load ($_defserr) - falling back to plain argument handling" } } - -#set argd [punk::args::parse $scriptargs -form 0 withid ::punkboot::app] -###lassign [dict values $argd] leaders opts values received -# -#puts stdout [punk::args::usage -scheme nocolour ::punkboot::app] -#exit 1 - +#error/usage rendering style: tabled (enhanced) when the rendering stack is healthy, +#minimal plain text otherwise - rendering degrades independently of parsing. +set ::punkboot::errstyle minimal +if {$::punkboot::punkargs_ok && [package provide punk::ansi] ne "" && [package provide textblock] ne ""} { + set ::punkboot::errstyle enhanced +} set do_help 0 -if {![llength $scriptargs]} { - set do_help 1 -} else { - foreach h $::punkboot::help_flags { - if {[lsearch $scriptargs $h] >= 0} { +set help_subject "" +set help_exitcode 0 +#defaults for the option-derived variables (fallback scan and passthrough subcommands rely on these) +set ::punkboot::opt_forcekill 0 +set ::punkboot::opt_dirty_abort 0 +set ::punkboot::opt_confirm 1 + +if {$::punkboot::punkargs_ok} { + set first [lindex $scriptargs 0] + if {![llength $scriptargs] || $first in $::punkboot::help_flags} { + set do_help 1 + } else { + #validate/resolve the subcommand word via the top-level definition + #(allows unambiguous prefixes; unknown subcommands get a punk::args usage error) + if {[catch {punk::args::parse [list $first] -errorstyle $::punkboot::errstyle withid (script)::punkboot} argd]} { + puts stderr $argd + exit 1 + } + set subcommand [dict get $argd leaders subcommand] + set subargs [lrange $scriptargs 1 end] + set wants_help 0 + foreach h $::punkboot::help_flags { + if {$h in $subargs} {set wants_help 1 ; break} + } + if {$subcommand eq "help"} { set do_help 1 - break + if {[llength $subargs]} { + if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::help} argd]} { + puts stderr $argd + exit 1 + } + set help_subject [dict get $argd values subject] + } + } elseif {$wants_help} { + set do_help 1 + set help_subject $subcommand + } elseif {$subcommand eq "shell"} { + #declared passthrough: everything after 'shell' goes to the repl unparsed + set ::punkboot::command shell + } else { + if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} { + puts stderr $argd + exit 1 + } + set ::punkboot::command $subcommand + set _opts [dict get $argd opts] + foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm} { + if {[dict exists $_opts $_optname]} { + set ::punkboot::$_var [dict get $_opts $_optname] + } + } + unset -nocomplain _opts _optname _var } } -} - - -set commands_found [list] -foreach a $scriptargs { - if {![string match -* $a]} { - lappend commands_found $a - } else { - if {$a ni $::punkboot::non_help_flags} { +} else { + #self-contained fallback scan (degraded mode: punk::args or a needed definition feature + #unavailable). Keeps check/bootsupport/modules and the -k/-dirty-abort/-confirm flags working. + set commands_found [list] + set argsleft $scriptargs + while {[llength $argsleft]} { + set a [lindex $argsleft 0] + set argsleft [lrange $argsleft 1 end] + if {[string match -* $a] || $a eq "/?"} { + switch -- $a { + -k {set ::punkboot::opt_forcekill 1} + -dirty-abort {set ::punkboot::opt_dirty_abort 1} + -confirm { + set v [lindex $argsleft 0] + set argsleft [lrange $argsleft 1 end] + if {![string is boolean -strict $v]} { + puts stderr "make.tcl: -confirm requires a boolean value (got '$v')" + exit 1 + } + set ::punkboot::opt_confirm [expr {bool($v)}] + } + default { + if {$a in $::punkboot::help_flags} { + set do_help 1 + } else { + puts stderr "Unknown flag: $a\n" + set do_help 1 + set help_exitcode 1 + } + } + } + } else { + lappend commands_found $a + } + } + if {![llength $scriptargs] || [lindex $commands_found 0] eq "help"} { + set do_help 1 + } elseif {!$do_help} { + if {[llength $commands_found] != 1} { set do_help 1 + set help_exitcode 1 + } elseif {[lindex $commands_found 0] ni $::punkboot::known_commands} { + puts stderr "Unknown command: [lindex $commands_found 0]\n\n" + set do_help 1 + set help_exitcode 1 } } -} -if {[llength $commands_found] != 1 } { - set do_help 1 -} elseif {[lindex $commands_found 0] ni $::punkboot::known_commands} { - puts stderr "Unknown command: [lindex $commands_found 0]\n\n" - set do_help 1 + if {!$do_help} { + set ::punkboot::command [lindex $commands_found 0] + } } - if {$do_help} { puts stdout "Checking package availability..." - set ::punkboot::pkg_availability [::punkboot::check_package_availability -quiet 1 $::punkboot::bootsupport_requirements] + set ::punkboot::pkg_availability [::punkboot::check_package_availability -quiet 1 $::punkboot::bootsupport_requirements] foreach pkg_request [dict get $::punkboot::pkg_availability loaded] { - #puts stderr "---> $pkg_request" lassign $pkg_request pkgname vrequest - set vloaded [dict get $::punkboot::pkg_availability info $pkg_request version] ;#version that was selected to load in response to vrequest during test - #catch {package require $pkgname {*}$vrequest} ;#todo package require $pkgname {*}$vrequest ;#todo - #package require $pkgname $vloaded-$vloaded } - puts stdout [::punkboot::punkboot_gethelp] - exit 0 + set help_shown 0 + if {$::punkboot::punkargs_ok} { + #tabled usage via punk::args - degrade to the plain fallback help if the rendering + #stack (punk::ansi/textblock etc) can't produce it + set usage_id (script)::punkboot + if {$help_subject ne ""} { + set usage_id (script)::punkboot::$help_subject + } + if {![catch {punk::args::usage $usage_id} usage_out]} { + puts stdout $usage_out + set availability_note [::punkboot::punkboot_availability_note] + if {$availability_note ne ""} { + puts stdout $availability_note + } + set help_shown 1 + } else { + puts stderr "make.tcl: punk::args tabled usage unavailable ($usage_out) - falling back to plain help" + } + } + if {!$help_shown} { + puts stdout [::punkboot::punkboot_gethelp] + } + exit $help_exitcode } - - -set ::punkboot::command [lindex $commands_found 0] - - -if {[lsearch $::argv -k] >= 0} { - set forcekill 1 -} else { - set forcekill 0 -} +set forcekill $::punkboot::opt_forcekill #puts stdout "::argv $::argv" # ---------------------------------------- @@ -1574,11 +1878,20 @@ if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ne "chec exit 1 } if {$_have_minor} { - if {![::punkboot::lib::bootsupport_prompt_yesno "Minor-version staleness — backward-compat aliases should keep old bootsupport functional."]} { + #G-030 prompt policy: -confirm 0 proceeds without prompting; with the default -confirm 1 + #a non-interactive stdin aborts fast with guidance instead of reading stdin. + if {!$::punkboot::opt_confirm} { + puts stderr "-proceeding with stale bootsupport (-confirm 0 supplied)-" + } elseif {![::punkboot::lib::stdin_is_interactive]} { + puts stderr "-aborted- (minor-version bootsupport staleness and stdin is not interactive)" + puts stderr " Update bootsupport (recommended - see above), or rerun with -confirm 0 to proceed with stale bootsupport." + exit 1 + } elseif {![::punkboot::lib::bootsupport_prompt_yesno "Minor-version staleness — backward-compat aliases should keep old bootsupport functional."]} { puts stderr "-aborted- by user" exit 1 + } else { + puts stderr "-proceeding with stale bootsupport at user's request-" } - puts stderr "-proceeding with stale bootsupport at user's request-" } # patch-only staleness: warn and proceed (warning already printed above) } @@ -1669,7 +1982,7 @@ if {![llength [info commands ::punkboot::exit_original]]} { } if {$::punkboot::command in {project packages modules libs vfs vfslibs bin bootsupport vfscommonupdate}} { - set dirty_abort [expr {[lsearch $::argv -dirty-abort] >= 0}] + set dirty_abort $::punkboot::opt_dirty_abort lassign [::punkboot::get_src_provenance_warnings $projectroot "make.tcl $::punkboot::command"] have_scoped_dirty_check dirty_warnings if {$have_scoped_dirty_check} { if {[llength $dirty_warnings]} { @@ -2054,29 +2367,41 @@ if {$::punkboot::command eq "vfscommonupdate"} { puts "script: [info script]" puts stdout "Updating vfs/_vfscommon.vfs" - puts stdout "REPLACE src/vfs/_vfscommon.vfs/* with project's modules and libs?? y|n" - if {[gets stdin] eq "y"} { - puts proceeding... - - proc vfscommonupdate {projectroot} { - file delete -force $projectroot/src/vfs/_vfscommon.vfs/modules - file copy $projectroot/modules $projectroot/src/vfs/_vfscommon.vfs/ - #temp? (avoid zipfs mkimg windows dotfile bug) - file delete $projectroot/src/vfs/_vfscommon.vfs/modules/.punkcheck - - file delete -force $projectroot/src/vfs/_vfscommon.vfs/lib - file copy $projectroot/lib $projectroot/src/vfs/_vfscommon.vfs/ - #temp? - file delete $projectroot/src/vfs/_vfscommon.vfs/lib/.punkcheck - + #G-030 prompt policy: -confirm 0 proceeds without prompting; with the default -confirm 1 + #a non-interactive stdin aborts fast with guidance instead of reading stdin. + set _proceed 0 + if {!$::punkboot::opt_confirm} { + puts stdout "REPLACE src/vfs/_vfscommon.vfs/* with project's modules and libs (-confirm 0 supplied - proceeding without prompting)" + set _proceed 1 + } elseif {![::punkboot::lib::stdin_is_interactive]} { + puts stderr "-aborted- (vfscommonupdate REPLACE confirmation required but stdin is not interactive)" + puts stderr " Rerun with -confirm 0 to proceed without prompting (see 'make.tcl vfscommonupdate -help')." + exit 1 + } else { + puts stdout "REPLACE src/vfs/_vfscommon.vfs/* with project's modules and libs?? y|n" + if {[string tolower [string trim [gets stdin]]] eq "y"} { + set _proceed 1 } - vfscommonupdate $projectroot - - } else { - puts aborting... } + if {!$_proceed} { + puts stderr "-aborted- by user (vfscommonupdate: no changes made)" + exit 1 + } + puts proceeding... + + proc vfscommonupdate {projectroot} { + file delete -force $projectroot/src/vfs/_vfscommon.vfs/modules + file copy $projectroot/modules $projectroot/src/vfs/_vfscommon.vfs/ + #temp? (avoid zipfs mkimg windows dotfile bug) + file delete $projectroot/src/vfs/_vfscommon.vfs/modules/.punkcheck + file delete -force $projectroot/src/vfs/_vfscommon.vfs/lib + file copy $projectroot/lib $projectroot/src/vfs/_vfscommon.vfs/ + #temp? + file delete $projectroot/src/vfs/_vfscommon.vfs/lib/.punkcheck + } + vfscommonupdate $projectroot puts stdout "\nvfscommonupdate done " flush stderr @@ -3860,13 +4185,24 @@ foreach vfstail $vfs_tails { puts stderr "WARNING: mismatch between kit type of source runtime [punk::ansi::a brightyellow]$extract_kit_type[punk::ansi::a] and target kit type [punk::ansi::a brightyellow]$target_kit_type[punk::ansi::a]" puts stderr "The resulting kit is unlikely to initialise" puts stderr "--------------------------------------------" - puts stdout "Continue to try to build $targetkit from $rtname anyway? y|n" - if {[string tolower [gets stdin]] eq "y"} { - puts proceeding... + #G-030 prompt policy: only an interactive 'y' can force building a mismatched + #kit - non-interactive runs (and -confirm 0) skip this kit and continue. + set _build_anyway 0 + if {!$::punkboot::opt_confirm} { + puts stderr "skipping kit $targetkit (source/target kit type mismatch; -confirm 0 policy is to skip)" + } elseif {![::punkboot::lib::stdin_is_interactive]} { + puts stderr "skipping kit $targetkit (source/target kit type mismatch and stdin is not interactive)" } else { + puts stdout "Continue to try to build $targetkit from $rtname anyway? y|n" + if {[string tolower [string trim [gets stdin]]] eq "y"} { + set _build_anyway 1 + } + } + if {!$_build_anyway} { #skip to next kit continue } + puts proceeding... } if {[file exists $sourcefolder/vfs/_vfscommon.vfs]} { diff --git a/src/modules/AGENTS.md b/src/modules/AGENTS.md index e7a3e2e4..3e3f574f 100644 --- a/src/modules/AGENTS.md +++ b/src/modules/AGENTS.md @@ -319,7 +319,7 @@ return #0.1.2 - fixed path_relative delegation edge case on Windows ``` This keeps the changelog discoverable alongside the version number without requiring a separate CHANGES file. -- **Bootstrap-tracked files only** — `punkcheck-buildversion.txt`, `punk/repo-buildversion.txt`, `punk/mix-buildversion.txt` (the top-level `punk::mix` file only; `punk::mix::util`, `punk::mix::cli`, and `punk/mix/commandset/*` version independently and are not covered by this check), and `punk/tdl-buildversion.txt`: bump at least **minor** whenever a call site inside that file is updated to use a new API, even if the file's own interface is unchanged. `src/make.tcl` reads only these four files to classify bootsupport staleness (major=abort, minor=prompt, patch=silent-proceed); under-bumping one of them to patch when the call-site change is more significant causes `make.tcl` to mis-classify and either wrongly proceed without prompting or wrongly abort. See `src/bootsupport/AGENTS.md` "Bootsupport Staleness Handling" for the full contract. +- **Bootstrap-tracked files only** — `punkcheck-buildversion.txt`, `punk/repo-buildversion.txt`, `punk/mix-buildversion.txt` (the top-level `punk::mix` file only; `punk::mix::util`, `punk::mix::cli`, and `punk/mix/commandset/*` version independently and are not covered by this check), `punk/tdl-buildversion.txt`, and `punk/args-buildversion.txt` (added by G-030: make.tcl dogfoods punk::args for dispatch/help; only the parsing contract is tracked — the punk::ansi/textblock rendering stack degrades instead): bump at least **minor** whenever a call site inside that file is updated to use a new API, even if the file's own interface is unchanged. `src/make.tcl` reads only these five files to classify bootsupport staleness (major=abort, minor=prompt, patch=silent-proceed); under-bumping one of them to patch when the call-site change is more significant causes `make.tcl` to mis-classify and either wrongly proceed without prompting or wrongly abort. See `src/bootsupport/AGENTS.md` "Bootsupport Staleness Handling" for the full contract. - **All other modules** (including `punk::mix` submodules): call-site updates follow ordinary judgement from the Patch/Minor/Major rules above — a behavior-preserving call-site change is a patch (or no bump if genuinely a no-op); reserve minor for changes that add capability to the module's *own* API. `src/make.tcl` does not read these versions, so there is no automated consequence, but keep the changelog accurate since it is the only record of the module's real semantic version. - **Manually versioned modules** (currently only `punk::libunknown`): the real `major.minor.patch` version is the filename suffix and the `package provide` block value; there is no `-buildversion.txt` and the build does not stamp a version. The Patch/Minor/Major bump rules above apply identically — an agent changing such a module bumps by (1) renaming the file (`git mv`) to the new version, (2) updating the `# Application ` Meta line, the doctools `manpage_begin` version and the provide-block `set version`, and (3) appending a changelog comment line to the version-history block in the module header (it substitutes for the buildversion.txt changelog). Before the first bump of such a module, verify nothing requires it by exact version or hardcoded filename (for punk::libunknown: punk_main.tcl and punk::repl glob `libunknown-*.tm` and pick the highest by vcompare, bootsupport's include_modules.config lists it by name only, and all requires are unversioned - verified 2026-07-11). New modules should use the magic version mechanism instead. - Modules with the magic version number must not appear in output paths such as `/modules`. diff --git a/src/tests/shell/AGENTS.md b/src/tests/shell/AGENTS.md index 5f4674f4..dd2cf14a 100644 --- a/src/tests/shell/AGENTS.md +++ b/src/tests/shell/AGENTS.md @@ -18,7 +18,7 @@ Tests for shell-level behavior, command-line execution, and stdin/stdout interac - Tests that spawn the built executable must be hang-proof: use the event-loop `punk_run` pattern (pipe stdin, half-close for EOF, timeout then force-kill) rather than plain `exec`, because known failure modes leave the child waiting on a reopened console. - `testsuites/punkexe/shellexit.test` guards piped-stdin termination behaviour of the built executable (no `invalid thread handle` on shutdown races, no console-reopen hang on eof/error paths, exitcode propagation); do not weaken these tests - a red result means a regression in punk::repl shutdown or app-punkshell eof handling. - `testsuites/punkexe/scriptexec.test` covers the `script` subcommand (app-punkscript, G-015): piped execution + honest exit codes, result echo, file-form argv, the `lib:` scriptlib-resolution mechanism, and the tclsh-matching Tk main-loop behaviour. The `lib:` and Tk cases resolve committed fixtures under `scriptlib/_punktest/` (test-owned; a `lib:`-resolvable fixture cannot live in a tcltest temp dir since resolution only searches scriptlib locations relative to the exe). Tk cases are gated by the `punktk` constraint, auto-detected by probing whether the kit can load Tk. -- punkexe tests run against the built binary: after changing punk::repl or app-punkshell source, rebuild via `make.tcl packages`, `make.tcl vfscommonupdate` (requires interactive `y`), then `make.tcl project` before trusting results; `make.tcl project` alone does not refresh `_vfscommon.vfs`. +- punkexe tests run against the built binary: after changing punk::repl or app-punkshell source, rebuild via `make.tcl packages`, `make.tcl vfscommonupdate -confirm 0` (unattended runs must pass the flag - the REPLACE confirmation aborts fast on non-interactive stdin instead of reading a piped `y`), then `make.tcl project` before trusting results; `make.tcl project` alone does not refresh `_vfscommon.vfs`. - `testsuites/binscripts/runtimebash_wsl.test` (G-059) exercises the runtime.cmd unix payload (`src/scriptapps/bin/runtime.bash`) through WSL: active/use/run resolution, env override, stale-active guidance, single-candidate fallback, and `list -remote` local-vs-server comparison (offline via a crafted cached sha1sums.txt + `PUNKBIN_URL` pointed at an unreachable address). Gated by the `wsllinux` capability constraint from `src/tests/testsupport/wslprobe.tcl`; all execution happens in a WSL-native staging dir, and a final test asserts the Windows checkout's git status is unchanged by the run. - `testsuites/punkexe/staticruntime.test` (G-058) targets a kit built on a runtime with statically-linked packages: resolved from `env(PUNK_STATICKIT_TEST_EXE)`, else `/bin/punk91.exe`, gated by the capability-probed `statickitavailable` constraint (a probe run must show a captured `::punkboot::static_packages` baseline including Thread - not mere file existence). It asserts repl boot without the codethread Thread failure, Thread resolution in the code interp / fabricated interps / snapshot-seeded threads, and twapi resolution per the static-vs-bundled policy. The verification runtime (tclsfe-x64.exe) is pinned in the punkbin artifact repo so the constraint is satisfiable off the original dev machine. Kit script-exec paths must be passed with forward slashes. - GOAL tests (constraint `punkgoals`, enabled by env `PUNK_TEST_GOALS=1`) cover the piped-stdin-then-interactive-shell drop-in (`shellpipe_eof_then_interactive_shell`, `shellpipe_script_and_eof_then_interactive_shell`); they are excluded from normal runs because they require an openable console in the test environment and briefly attach a live shell to it - they pass in console-attached environments against a current build.