Compare commits

...

4 Commits

Author SHA1 Message Date
Julian Noble 14fc37daba vfscommonupdate: promote pending module bumps into _vfscommon.vfs (punkexe 0.1.1 packagemode doc reaches kits) 2 days ago
Julian Noble 59bdb1ec49 G-033 achieved: flip, archive, reference sweep (proj: visitor mode live) 2 days ago
Julian Noble 768dab399f G-033: proj: package-mode scope prefix - visitor binary resolves dev/src against the cwd's project 2 days ago
Julian Noble b692979c6a G-135 + G-136: per-asset assetorigin sidecars replace the directory record 2 days ago
  1. 4
      ARCHITECTURE.md
  2. 15
      CHANGELOG.md
  3. 4
      GOALS-archive.md
  4. 6
      GOALS.md
  5. 8
      bin/AGENTS.md
  6. 10
      goals/G-016-projects-work-git-discovery.md
  7. 3
      goals/G-018-zig-plain-tclsh-kits.md
  8. 5
      goals/G-031-componentized-kit-boot.md
  9. 10
      goals/G-032-launcher-punkargs.md
  10. 3
      goals/G-035-mixed-tm-pkgindex-provision.md
  11. 3
      goals/G-043-subshell-definition-plugins.md
  12. 8
      goals/G-047-declared-primary-vcs.md
  13. 2
      goals/G-057-kit-icon-embedding.md
  14. 9
      goals/G-089-scriptlib-kits-and-modes.md
  15. 95
      goals/G-135-asset-provenance-records.md
  16. 18
      goals/G-136-generated-project-icon-seeding.md
  17. 53
      goals/archive/G-033-proj-mode-cwd-project.md
  18. 2
      punkproject.toml
  19. 38
      src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm
  20. 2
      src/modules/punk/args/moduledoc/punkexe-buildversion.txt
  21. 2
      src/vfs/AGENTS.md
  22. 235
      src/vfs/_config/punk_main.tcl
  23. 340
      src/vfs/_vfscommon.vfs/modules/argparsingtest-1.3.0.tm
  24. 4
      src/vfs/_vfscommon.vfs/modules/oolib-0.1.4.tm
  25. 44
      src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/punkexe-0.1.1.tm
  26. BIN
      src/vfs/_vfscommon.vfs/modules/punk/mix/templates-0.2.0.tm
  27. 175
      src/vfs/_vfscommon.vfs/modules/punk/zip-0.3.0.tm
  28. 31
      src/vfs/_vfscommon.vfs/modules/punkcheck-0.6.1.tm

4
ARCHITECTURE.md

@ -42,7 +42,7 @@ app package from src/lib/ (app-punkshell, app-punkscript, app-repl, app-shellsp
## Boot and launch chain
- **Kit anatomy.** Each `src/vfs/*.vfs` folder is a runtime payload; `src/runtime/mapvfs.config` maps payload folders to platform runtimes under `bin/runtime/<platform>/`; `src/vfs/_vfscommon.vfs/` is a generated merge of common libraries (never hand-edited); `src/vfs/_config/` holds the entry scripts. Sources: `src/vfs/AGENTS.md`, `src/runtime/AGENTS.md`.
- **Entry point.** `src/vfs/_config/punk_main.tcl`. An optional first argument is a dash-delimited package mode composed of tokens from `dev`, `os`, `src`, `internal` (`internal` is always appended when absent). The next argument is the subcommand: `shell`, `script`, `punk`, `tclsh`, `shellspy`. Any other first argument is treated as a script invocation; no arguments at all means interactive shell. Subcommands map to app packages under `src/lib/` (`app-punkshell`, `app-punkscript`, `app-repl`, `app-shellspy`).
- **Entry point.** `src/vfs/_config/punk_main.tcl`. An optional first argument is a dash-delimited package mode composed of tokens from `dev`, `os`, `src`, `internal` (`internal` is always appended when absent), optionally scoped with the `proj:` prefix (G-033: `dev`/`src` resolve against the project containing the cwd - walk-up to the nearest git/fossil repo root with a punkshell-style src tree - instead of the executable's own project; discovery is always reported, never a silent rebind). The next argument is the subcommand: `shell`, `script`, `punk`, `tclsh`, `shellspy`. Any other first argument is treated as a script invocation; no arguments at all means interactive shell. Subcommands map to app packages under `src/lib/` (`app-punkshell`, `app-punkscript`, `app-repl`, `app-shellspy`).
- **Package modes pick module provenance.** `internal` uses module snapshots baked into the kit at build time; `dev` loads build outputs from repo-root `modules/` and `lib/`; `src` loads the unbuilt working tree (`src/modules`, `src/lib`, `src/bootsupport`, `src/vendormodules`) with `package prefer latest` so magic-version dev modules (`999999.0a1.0`) beat stamped snapshots. `src` mode is the standard way to verify working-tree changes without a rebuild. Source: `bin/AGENTS.md` "Launch package modes".
- **Payload mount derivation (G-129, achieved).** The boot keys zipfs presence on `tcl::zipfs::mount` and derives where the executable's attached archive actually mounted from the mount table itself (the entry whose archive file is the executable; fallback: the mount containing the boot script) instead of assuming `tcl::zipfs::root` + `//zipfs:/app`. Modern runtimes still answer `//zipfs:/app`; the androwish/undroidwish 8.6 backport has no `root` command, mounts at the executable's own path, and boots the same payload through its `app/main.tcl` in-archive hook (`src/vfs/punk8win.vfs` carries fauxlinks for both conventions). A mounted archive the boot cannot attribute is reported on stderr rather than silently yielding no internal paths. The derivation procs stay defined post-boot (`::punkboot::zipfs_kit_mountbase`). Sources: `src/vfs/AGENTS.md`, `bin/AGENTS.md` "Kit-wrappable runtime requirements", `src/tests/shell/testsuites/punkexe/kitmountpoint.test`.
- **Static package capture (G-058, achieved).** Boot probe-loads the runtime's statically linked packages in a throwaway interp and records what each provides; every interp the shell fabricates (boot, codethread, shellthread workers) seeds `package ifneeded <name> <ver> {load {} <prefix>}` from that record, and `punk::packagepreference` resolves static-vs-bundled version-aware. Sources: `src/vfs/AGENTS.md`, `goals/archive/G-058-static-runtime-packages.md`.
@ -106,7 +106,7 @@ Mechanics here are documented as pointers only - detailed prose would be obsolet
- Input mode and completion: G-013 (raw-mode default), G-044 (punk::args-driven completion).
- Stored configuration and help: G-014 (punk::config toml), G-042 (subshell help topics), G-043 (subshell definition plugins).
- Console err channel: G-011.
- Launch surface: G-023 (version-named binaries), G-033 (`proj:` package mode), G-077 (`-e` one-liners), G-089 (scriptlib in kits).
- Launch surface: G-023 (version-named binaries), G-077 (`-e` one-liners), G-089 (scriptlib in kits).
- 8.6 buildsuite family: G-101 (kit container) - the core runtime (G-099) and the Tk/tklib/tcllib dependency set (G-100) are achieved 2026-07-26.
## Doc map - which lane holds what

15
CHANGELOG.md

@ -5,6 +5,21 @@ 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.29.0] - 2026-07-28
- `proj:` package-mode scope prefix (G-033): an installed or standalone punk shell
binary can visit the punk project containing the current directory -
`<punkexe> proj:internal-src shell` (canonical, kit copies win same-version ties)
or `proj:src` (project copies win). The boot walks up from the cwd to the nearest
git/fossil repo root with a punkshell-style src tree and feeds it to the existing
src/dev path machinery (src/modules + bootsupport + vendormodules + src/lib,
`package prefer latest`, #modpod registration), reporting the detected root and
effective precedence on stderr - warn-and-proceed (dev/src unbound) when no
project is found, never an exe-relative fallback rebind. Exe-relative plain
`src`/`dev` launches are unchanged. The packagemode contract (blocks, ordering,
proj: examples) is now live punk::args documentation in
punk::args::moduledoc::punkexe 0.1.1 (rendering wiring remains G-032).
## [0.28.4] - 2026-07-27
- punk::zip 0.3.0 (G-126): optional punkzip extraction accelerator. New

4
GOALS-archive.md

@ -32,6 +32,10 @@ Acceptance: from a running punk session's code interp, without `repl eval`: `con
Scope: src/vfs/_config/punk_main.tcl; src/lib/app-punkshell/punkshell.tcl (script path or a leaner dedicated app package)
Acceptance: piping commands to `<punkexe> script` runs them and terminates at stdin EOF with no trailing `exit` required, exit code 0 on success; a failing piped command terminates the process with a nonzero exit code and the error on stderr, never landing in an interactive shell regardless of console availability or PUNK_PIPE_EOF; `<punkexe> script <file> [<args>...]` executes the file with conventional ::argv0/::argv and propagates its error status the same way; the script path installs none of the `shell` subcommand's shellfilter stacks/transforms and the launch plumbing itself emits nothing on stdout/stderr (the current stub's stderr diagnostics removed) so exec-style callers see only the script's own output; the motivating example works with no package require boilerplate: piping `dev projects.work *<name>*` to `<punkexe> script` emits the matching-project table and exits 0, because the script interp carries the default punk shell module/alias environment.
### G-033 [achieved 2026-07-28] `proj:` package-mode scope prefix: visitor binary resolves dev/src against the cwd's project → detail: goals/archive/G-033-proj-mode-cwd-project.md
Scope: src/vfs/_config/punk_main.tcl (package-mode dispatch and boot-time root discovery); src/modules/punk/repo-999999.0a1.0.tm (find_project / is_project_root - reuse or lean boot mirror); bin/AGENTS.md (mode docs)
Acceptance: `<installed-punkexe> proj:internal-src shell` (the documented canonical visitor invocation - kit copies win same-version ties, protecting the visiting shell's infrastructure; `proj:src` is the documented faithful-vintage variant where the project's copies win) launched from within a punk project's tree discovers the project root by walking up from cwd to the nearest VCS repo root and feeds it to the existing src-mode path machinery (src/modules, src/bootsupport/modules, src/vendormodules on the module path, src/lib on auto_path), so the session loads the project's dev-versioned modules while ordinary version resolution still lets the project supply anything the kit lacks or exceeds; the launch reports the detected project root and effective path precedence (never a silent rebind); with no project found walking up from cwd, or a `proj:` string containing no root-using block (dev/src), it warns and proceeds without false rebind; proven for a standalone binary outside any source tree (internal = kit contents regardless of binary location) against a project that builds no executable (tomlish is the natural first); exe-relative `src`/`dev` discovery is unchanged for a binary that IS in a project's bin/; the packagemode help text drafted in the detail file becomes the live punk::args documentation when implemented (rendered via G-032).
### G-036 [achieved 2026-07-08] Root-cause the Tcl 9 console+udp worker-thread event-loop wedge; minimal repro for possible upstream reporting → detail: goals/archive/G-036-tcl9-udp-console-worker-wedge.md
Scope: src/modules/shellthread-999999.0a1.0.tm; src/bootsupport/modules/shellthread-1.6.2.tm; src/modules/shellfilter-999999.0a1.0.tm (as characterised - no product-code changes required by this goal; the punkshell mitigations are separate fixes)
Acceptance: (reworked 2026-07-08 after the root cause was found) the wedge mechanism is identified and written up in the detail file - DONE: bundled tcludp 1.0.12's Windows per-thread UDP_ExitProc closes the process-global synchronization events, proven by dump handle-table analysis plus a live CloseHandle breakpoint and confirmed by the upstream 1.0.12->1.0.13 diff, which already fixes it (so no upstream report is required; the standalone minimal repro originally required here is waived as moot by the user); the tcl9 kits bundle tcludp >= 1.0.13 with the in-context batch harness baseline resolved - DONE 2026-07-08 (run-2 syslog workers alive vs the 4/4-wedged 1.0.12 baseline); DONE 2026-07-08 (punk::lib 0.3.0 has_libbug_udp_threadexit, surfaced via 'help tcl' in punk 0.2.1): a has_bug-style detection in the punkshell check machinery (in the vein of punk::lib::check::has_tclbug_* / punk::console::check::has_bug_*, surfaced through the same reporting as 'help tcl'/'help console') reports the vulnerable combination - simple version-based detection (loaded/bundled tcludp < 1.0.13 on Tcl 9 Windows) is sufficient, no behavioural probe needed; loose-end decisions (punk8win 8.6 kit's udp 1.0.12 swap; optional upstream tickets for residual tcludp trunk weaknesses) recorded in the detail file when made (open as of 2026-07-08 - non-gating).

6
GOALS.md

@ -189,10 +189,6 @@ Detail: goals/G-031-componentized-kit-boot.md
Scope: src/vfs/_config/ (default dispatch); src/lib/app-punkshell and sibling app packages as touched
Detail: goals/G-032-launcher-punkargs.md
### G-033 [proposed] `proj:` package-mode scope prefix: visitor binary resolves dev/src against the cwd's project
Scope: src/vfs/_config/punk_main.tcl (package-mode dispatch and boot-time root discovery); src/modules/punk/repo-999999.0a1.0.tm (find_project / is_project_root - reuse or lean boot mirror); bin/AGENTS.md (mode docs)
Detail: goals/G-033-proj-mode-cwd-project.md
### G-034 [proposed] Zip-based #modpod modules mount in the shell code-interp on Tcl 8.6
Scope: src/modules/punk/mix/ (modpod mount path); vfs::zip availability in the repl code interp; src/modules/punk/cap/ (templates capability handler)
Detail: goals/G-034-modpod-codeinterp-tcl86.md
@ -416,7 +412,7 @@ Scope: src/make.tcl (post-assembly offset-style probe at the G-133 advisory-chec
Detail: goals/G-134-baked-kits-pinned-archive-relative.md
### G-135 [proposed] Asset provenance records: a verifiable master-to-derived icon chain with a platform-neutral generator
Scope: src/assets/logo/ (assetorigin.toml records, masters and generated icons); src/assets/logo/make-ico.ps1 (replaced in place by a Tcl generator, then removed); scriptlib/developer/ (provenance checker, sibling to goals_lint and architecture_lint); checker home revisited if it becomes a bake step (a punk:: module rather than scriptlib, which make.tcl must not depend on); src/runtime/punkshell.ico and src/vfs/_vfscommon.vfs/punkshell.ico (recorded as derived copies, not relocated)
Scope: src/assets/logo/ (per-asset *.assetorigin.toml sidecars, masters and generated icons); src/assets/logo/make-ico.ps1 (replaced in place by a Tcl generator, then removed); scriptlib/developer/ (provenance checker, sibling to goals_lint and architecture_lint); checker home revisited if it becomes a bake step (a punk:: module rather than scriptlib, which make.tcl must not depend on); src/runtime/punkshell.ico and src/vfs/_vfscommon.vfs/punkshell.ico (recorded as derived copies, not relocated)
Detail: goals/G-135-asset-provenance-records.md
### G-136 [proposed] Generated projects are seeded with a default icon from a single punkshell-held master

8
bin/AGENTS.md

@ -87,7 +87,7 @@ platform-specific difference left in examples is path separator style
### Launch package modes (built punk shells)
The first argument to a built punk shell may be a dash-delimited package mode composed of tokens from `dev`, `os`, `src`, `internal` (e.g. `punksys src`, `punk902z dev-os`). `internal` is the default and is always appended when absent. A first argument that is not a valid mode list is treated as a subcommand instead. Implementation: `src/vfs/_config/punk_main.tcl` (search `all_package_modes`).
The first argument to a built punk shell may be a dash-delimited package mode composed of tokens from `dev`, `os`, `src`, `internal` (e.g. `punksys src`, `punk902z dev-os`), optionally scoped with the `proj:` prefix (e.g. `punk91 proj:internal-src`). `internal` is the default and is always appended when absent. A first argument that is not a valid mode list is treated as a subcommand instead (a `proj:` prefix on a non-mode string is not consumed either). Implementation: `src/vfs/_config/punk_main.tcl` (search `all_package_modes`). The full packagemode contract (block meanings, ordering, proj: examples) is the punk::args documentation at id `(script)::punkexe` (module `punk::args::moduledoc::punkexe`).
`src` mode is the one that matters for verifying working-tree changes:
@ -95,6 +95,12 @@ The first argument to a built punk shell may be a dash-delimited package mode co
- Prepends `src/modules`, `src/modules_tcl<N>`, `src/bootsupport/modules{,_tcl<N>}` and `src/vendormodules{,_tcl<N>}` to the module path, sets `package prefer latest` so dev-numbered `999999.0a1.0` source modules beat kit-stamped snapshots on unversioned `package require`, and registers `#modpod` modules from `src/modules` (startup notice: `src mode: registered N #modpod modules from .../src/modules`).
- Consequence: `punksys src` / `punk902z src` exercises current working-tree source with no kit rebuild; a plain launch (`punksys`) exercises the module snapshots baked into the kit at build time. `package present <pkg>` reporting `999999.0a1.0` (vs a release version like `0.7.1`) tells you which set a session is running - runbooks with version expectations must state the intended launch mode.
`proj:` scope (G-033, achieved - see goals/archive/G-033-proj-mode-cwd-project.md) makes `dev`/`src` resolve against the project containing the CURRENT DIRECTORY instead of the executable's own project - visitor mode for an installed/standalone punk binary exploring a project that builds no shell of its own (the project may be modules-only, e.g. tomlish):
- Root discovery walks up from the cwd to the nearest git/fossil repo root that looks like a punkshell-style project (has `./src` plus one of `src/modules`, `src/vfs`, `src/scriptapps`, or `punkproject.toml` - a lean boot mirror of `punk::repo::is_project_root`).
- The launch always reports the detected root and effective mode precedence on stderr; when no project is found it warns and proceeds with dev/src unbound (never a silent or false rebind, no exe-relative fallback). `proj:` with no dev/src block warns that it has no effect.
- Canonical visitor invocation: `<punkexe> proj:internal-src shell` - kit copies win same-version ties, protecting the visiting shell's own infrastructure. `proj:src` is the faithful-vintage variant where the visited project's copies win ties. The project's genuinely-own code (dev-versioned or absent from the kit) loads from the project in either order.
### Kit-wrappable runtime requirements (G-129)
What a runtime must provide for `make.tcl bake` to wrap it as a punk ZIP kit and for that

10
goals/G-016-projects-work-git-discovery.md

@ -87,8 +87,10 @@ Result-shape considerations:
(reliable piped invocation - achieved 2026-07-07) and G-017 (agent guidance documenting the call).
- The `-cd` / `-detail` options and case-insensitive glob behaviour of the
existing command are contracts to preserve.
- G-033 relationship (recorded 2026-07-24 after overlap review): proj:'s
cwd-anchored root discovery (punk::repo find_project/is_project_root) is the
interactive counterpart of this goal's registry enumeration - a project found by
one surface should be found by the other.
- G-033 relationship (recorded 2026-07-24 after overlap review; G-033 achieved
2026-07-28 - see goals/archive/G-033-proj-mode-cwd-project.md): proj:'s
cwd-anchored root discovery (delivered as a lean boot mirror of
punk::repo find_project/is_project_root - ::punkboot::proj_root_find in
punk_main.tcl) is the interactive counterpart of this goal's registry
enumeration - a project found by one surface should be found by the other.
- Archived-goal references in this file: G-049 achieved 2026-07-10 (goals/archive/G-049-punkargs-parse-status-model.md).

3
goals/G-018-zig-plain-tclsh-kits.md

@ -69,4 +69,5 @@ This defines one end of a deliberate spectrum of buildable executables:
make.tcl surfacing of suite builds landed as G-104 (achieved 2026-07-25 -
see goals/archive/G-104-maketcl-buildsuite-surface.md:
'make.tcl buildsuite list/info/build'). The executable-spectrum framing
this goal contributed remains referenced from G-019/G-023/G-031/G-033.
this goal contributed remains referenced from G-019/G-023/G-031 and G-033
(achieved 2026-07-28 - see goals/archive/G-033-proj-mode-cwd-project.md).

5
goals/G-031-componentized-kit-boot.md

@ -80,6 +80,11 @@ permanently own - a thousand lines of boot code.
(boot-core vintage reporting), G-032 (punk::args-defined dispatch built on
the registration model), G-012 (layout payload hygiene), G-018 (plain tclsh
kits deliberately carry NO punk boot layer - out of scope here).
- G-033 (archived) recorded a fork-drift datapoint for this goal: the proj:
scope prefix and its `::punkboot::proj_root_find` walk-up landed in
punk_main.tcl only - project_main.tcl still lacks src mode and now also
proj:, widening the divergence this consolidation resolves - see
goals/archive/G-033-proj-mode-cwd-project.md.
- G-089 relationship (recorded 2026-07-24 after overlap review): its
boot-provided packagemode hint (for scriptlib resolution) is a boot-core
interface this goal's registration model should carry - one boot "running

10
goals/G-032-launcher-punkargs.md

@ -27,11 +27,13 @@ in `-help` by registration alone.
with @cmd summaries, package-mode leader documented) and per-subcommand
options. `<punkexe> -help`, `<punkexe> help <subcommand>`, and
`<subcommand> -help` all render tabled usage.
- The packagemode leader's help text is pre-drafted in G-033's detail file
- The packagemode leader's help text is LIVE as of G-033's achievement
(2026-07-28, goals/archive/G-033-proj-mode-cwd-project.md): the drafted text
(block semantics, ordering-as-tie-break rule, the `proj:` scope prefix with
the kit-first `proj:internal-src` canonical example) - use that as the source
text, noting the `proj:` portions go live only when G-033 implements the
prefix.
the kit-first `proj:internal-src` canonical example) now sits as the
packagemode leader in punk::args::moduledoc::punkexe 0.1.1's
`(script)::punkexe` definition. This goal's remaining lane is the
rendering/parse wiring that consumes it.
- Parse errors on declared subcommands produce punk::args usage errors
(tabled), not silent fallthrough. The unknown-first-arg -> script
reclassification survives only where it does not swallow obvious mistakes -

3
goals/G-035-mixed-tm-pkgindex-provision.md

@ -62,7 +62,8 @@ is a realistic hazard - and same-version-different-content drift (the
## Notes
- Related: the shadowing pin-tests (same suite family - this goal's tests
extend them), G-033 (visitor-mode path mixing makes cross-form collisions
extend them), G-033 (achieved 2026-07-28, goals/archive/G-033-proj-mode-cwd-project.md -
visitor-mode path mixing is now live, making cross-form collisions
more reachable: a kit's internal libs vs a visited project's .tm trees),
G-026/G-024 (same-version drift provenance), punk::packagepreference 0.1.1
(its moduledoc auto-load hook lives in exactly this machinery).

3
goals/G-043-subshell-definition-plugins.md

@ -99,7 +99,8 @@ Phases:
is a natural bundle of this goal's composition plus theme/restrictions), G-002/G-010
(non-nested subshells - restore-on-switch semantics), G-003 (restricted subshells -
a restricted subshell composing plugin commandsets needs the expose/hide interaction
considered), G-033 (visitor binaries - shellproject-anchored resources vs cwd-project
considered), G-033 (achieved 2026-07-28, goals/archive/G-033-proj-mode-cwd-project.md -
visitor binaries: shellproject-anchored resources vs cwd-project
resources, same anchor question as the templates pathtypes).
- Rough edges catalogued 2026-07-08 (this goal's acceptance covers the first two):
punk::cap pkg_unregister "destroy api objects?" review; silent unhandled-capability

8
goals/G-047-declared-primary-vcs.md

@ -49,6 +49,8 @@ The original G-047 draft (2026-07-08) declared a single team-wide primary with t
three layout copies carry the bake/bakehouse vocabulary); its AGENTS.md
workflow edits landed - this goal's Commit-Conventions edit touches other
sections of the same docs.
- G-033 relationship: its proj: visitor root discovery and this goal's primary-VCS
anchoring share the punk::repo::is_project_root marker as the root test - a nested
punkproject.toml must never fool either reader.
- G-033 relationship (G-033 achieved 2026-07-28 - see
goals/archive/G-033-proj-mode-cwd-project.md): its proj: visitor root discovery
(boot mirror ::punkboot::proj_root_find in punk_main.tcl) and this goal's
primary-VCS anchoring share the punk::repo::is_project_root marker as the root
test - a nested punkproject.toml must never fool either reader.

2
goals/G-057-kit-icon-embedding.md

@ -131,7 +131,7 @@ delete-then-write). Requirements sketch agreed 2026-07-10:
in the Acceptance that the override is shared across a kit definition's targets.
- Related: G-135 - the source-tree provenance records this goal's sidecar can read. The
sidecar is emitted per kit at bake time and describes what got embedded; G-135's
assetorigin.toml is committed and describes a derivation. Populating the sidecar's
per-asset assetorigin sidecars are committed and describe a derivation. Populating the sidecar's
"source .ico identity and provenance" from those records closes the gap where this
goal's provenance otherwise stops at the .ico bytes, one tier short of the SVG master
they were generated from.

9
goals/G-089-scriptlib-kits-and-modes.md

@ -47,9 +47,12 @@ Findings from the 2026-07-18 lib: extensionless work (punk::path 0.3.0):
## Notes
- Related goals: G-033 (proj: scope prefix - the visitor root discovery this
goal's proj: scriptlib clause rides on; its notes already flag that
`proj:... script` benefits), G-018/G-019 (installable/trimmed kits),
- Related goals: G-033 (achieved 2026-07-28, goals/archive/G-033-proj-mode-cwd-project.md -
the proj: visitor root discovery this goal's proj: scriptlib clause rides on
is now live: ::punkboot::proj_root_find in punk_main.tcl remains defined
post-boot, so this goal can re-derive the visited root; the boot-interface
packagemode hint this goal needs is still absent - the discovered proj root
is a boot-local variable, not exposed), G-018/G-019 (installable/trimmed kits),
G-015 (achieved - script subcommand, goals/archive/G-015-script-subcommand-piped-stdin.md).
- `lib:<name>.kit` dispatch (restored in punkshell 0.14.0 via punk::path
0.3.0's known-extensions fix) has no committed test fixture - a `.kit`

95
goals/G-135-asset-provenance-records.md

@ -1,9 +1,9 @@
# G-135 Asset provenance records: a verifiable master-to-derived icon chain with a platform-neutral generator
Status: proposed
Scope: src/assets/logo/ (assetorigin.toml records, masters and generated icons); src/assets/logo/make-ico.ps1 (replaced in place by a Tcl generator, then removed); scriptlib/developer/ (provenance checker, sibling to goals_lint and architecture_lint); checker home revisited if it becomes a bake step (a punk:: module rather than scriptlib, which make.tcl must not depend on); src/runtime/punkshell.ico and src/vfs/_vfscommon.vfs/punkshell.ico (recorded as derived copies, not relocated)
Scope: src/assets/logo/ (per-asset *.assetorigin.toml sidecars, masters and generated icons); src/assets/logo/make-ico.ps1 (replaced in place by a Tcl generator, then removed); scriptlib/developer/ (provenance checker, sibling to goals_lint and architecture_lint); checker home revisited if it becomes a bake step (a punk:: module rather than scriptlib, which make.tcl must not depend on); src/runtime/punkshell.ico and src/vfs/_vfscommon.vfs/punkshell.ico (recorded as derived copies, not relocated)
Goal: Any committed icon in the tree can state what it was derived from and be checked against that claim on any platform, and regenerating one from its master needs no Windows-only tooling - while an icon carrying no record stays a fully supported and silent case.
Acceptance: `assetorigin.toml` is documented with a `schema` key and directory-scoped relative paths, and a reader tolerates an absent file, unknown keys and an unrecognised schema version without erroring; a checker written in plain Tcl - no rasterizer, no external binary, runnable under any punkshell runtime - classifies each recorded asset as exactly one of `unrecorded`, `verified`, `source-absent`, `replaced` or `stale`, demonstrably distinguishing `stale` (source changed since the artifact was generated) from `replaced` (artifact changed since recording) on constructed fixtures, and is advisory only, never failing a build, in the manner of the G-133 payload checks; the icon generator is reimplemented with no Windows-only component (`System.Drawing` in particular), producing byte-identical `.ico` output to the current `make-ico.ps1` for every master under `src/assets/logo/` before that script is removed; and records exist and verify for `src/assets/logo/`, `alternative/`, `web/` and `project-default/`.
Acceptance: the `<asset-filename>.assetorigin.toml` sidecar format is documented with a `schema` key, the recorded asset bound by the sidecar's own filename (suffix stripped, same directory) and the source reference relative to that directory, files ending in the suffix being records, never assets; a reader tolerates a missing sidecar, unknown keys and an unrecognised schema version without erroring; a checker written in plain Tcl - no rasterizer, no external binary, runnable under any punkshell runtime - classifies each asset it examines as exactly one of `unrecorded` (no sidecar), `verified`, `artifact-absent` (a sidecar whose paired asset is gone), `source-absent`, `replaced` or `stale` per the state table in this file, where `verified` requires every hash the sidecar records to match, so a sidecar carrying only the artifact hash is verified on that alone, demonstrably distinguishing `stale` (source changed since the artifact was generated) from `replaced` (artifact changed since recording) and from `artifact-absent` on constructed fixtures, and is advisory only, never failing a build, in the manner of the G-133 payload checks; the icon generator is reimplemented with no Windows-only component (`System.Drawing` in particular), regenerating every generated `.ico` under `src/assets/logo/` byte-identically to the current `make-ico.ps1` under the invocation profile that produced it before that script is removed, and (re)writing the sidecar of each artifact it produces - artifact and source hashes plus the invocation options - so regeneration cannot leave a stale record; and sidecars exist and verify for every generated artifact under `src/assets/logo/`, `alternative/`, `web/` and `project-default/`.
## Context
@ -42,27 +42,39 @@ container assembly downstream is pure `binary format`.
- The record is OPTIONAL by construction. Absence means `unrecorded` - silent,
never a warning. A record is an opt-in claim, and nothing may read it to decide
whether a build proceeds. Most projects live in this state permanently.
- Directory-scoped `assetorigin.toml` carrying an `[[asset]]` array with
RELATIVE paths, so it survives being copied wholesale into a derived tree with
no rewriting (the property G-136 depends on).
- Every field except `path` is optional. An entry carrying only a path and a
hash means "I know this file, I do not know where it came from" - which serves
an owner who drops in their own `.ico` but still wants change detection.
- Per-asset sidecar records: `<asset-filename>.assetorigin.toml` beside the
asset it describes. The pairing is the filename - no `path` key - so create,
replace and remove are always the file pair, with no shared record to edit;
the pair survives wholesale directory copies (the property G-136 depends on)
and single-asset copies alike; and overlay merges compose correctly by
construction (merge_over's same-path replacement carries asset and sidecar
together). Files ending in `.assetorigin.toml` are records, never assets.
- Every field except the artifact `hash` is optional. A sidecar carrying only
a hash means "I know this file, I do not know where it came from" - which
serves an owner who drops in their own `.ico` but still wants change
detection.
- Unknown keys and unrecognised `schema` versions are skipped, not errors, so a
future writer cannot break an older reader.
- Five states, with policy left to the consumer rather than baked into the
format:
- Six states, evaluated in table order with the first match winning (which is
what makes "exactly one" true by construction), policy left to the consumer
rather than baked into the format:
| State | Condition |
|---|---|
| `unrecorded` | no record file |
| `verified` | artifact and source hashes both match |
| `source-absent` | artifact matches, source not present in the tree |
| `replaced` | artifact hash differs from the record |
| `stale` | artifact matches the record, source present but changed |
| Order | State | Condition |
|---|---|---|
| 1 | `unrecorded` | no sidecar for the file |
| 2 | `artifact-absent` | a sidecar exists but its paired asset does not |
| 3 | `replaced` | asset present, hash differs from the sidecar (regardless of source state) |
| 4 | `source-absent` | asset matches, a recorded source is not present in the tree |
| 5 | `stale` | asset matches, recorded source present but its hash differs |
| 6 | `verified` | asset matches, and every other hash the sidecar records also matches |
`stale` is the point of the whole goal; it is also distinguishable from
`replaced`, which means the opposite thing and deserves the opposite response.
Hash comparisons apply only to hashes actually recorded - a claim with no
hash contributes only a presence check, so a source named without a source
hash can never produce `stale`; drift on unhashed claims is the record's own
limitation, not the checker's. `stale` is the point of the whole goal; it is
distinguishable from `replaced`, which means the opposite thing and deserves
the opposite response, and from `artifact-absent`, which means the record
itself has gone stale and needs repair.
- A `role` field (`pe-resource` | `web` | `generic`) makes an existing hazard
machine-checkable rather than a documentation footnote: `web/favicon.ico` is
all-PNG, which is exactly what GDI+ and tklib's `ico` package cannot read, so a
@ -81,15 +93,34 @@ container assembly downstream is pure `binary format`.
- `punkorigin.toml`, G-027's generated-project carrier - rejected: that answers
project lineage ("this project came from punkshell layout X"), a different
question from asset derivation. Keep them separate.
- Per-file sidecars instead of one record per directory - rejected:
`src/assets/logo/web/` alone would carry six, and a directory record with
relative paths is what makes verbatim copying work.
- One record file per directory carrying an `[[asset]]` array - the original
draft shape - rejected at the 2026-07-28 pre-activation review: entries are
shared state (every writer does a read-modify-write - the punkcheck lesson:
G-094 + G-095, both achieved 2026-07-21, archived at
goals/archive/G-094-punkcheck-single-lifecycle.md and
goals/archive/G-095-punkcheck-concurrent-writer-safety.md), a record at a
.vfs root is clobbered
file-level by overlay merges (a kit-tree record would replace the common one
wholesale, entries and all), dangling entries are invisible in listings, and
copying a single asset out of a directory loses its record. Accepted in
exchange: `web/` carries one sidecar per generated raster, and per-directory
facts (format documentation, cross-asset notes) live in AGENTS.md rather
than in the record file.
- A fauxlink-carried record (toml body per the fauxlink extension convention,
source path encoded in the name) - rejected: the filename would encode a
mutable fact, so master renames invalidate sidecar filenames, and overlay
pairing would need a nominal-keyed composition invariant in merge_over and
every other composer; the ls-visible derivation edge does not pay for that.
The nominal-keyed idea itself (at most one fauxlink per effective nominal
per directory, last layer wins) is recorded as generally useful fauxlink
hardening independent of this goal - the tree already satisfies it (71
fauxlinks, no same-directory nominal collisions, surveyed 2026-07-28).
- Making the `.ico` a build output regenerated at bake time - rejected: G-057
requires bakes to succeed with no build toolchain installed.
## Notes
- Related: G-057 - consumer. Its per-kit sidecar is specified to carry "source
- Related: G-057 - consumer. Its per-kit icon sidecar is specified to carry "source
.ico identity and provenance" in a documented plain-text form; these records
are the natural thing it reads to populate those fields, which closes the gap
where its provenance otherwise stops one tier short of the actual source. Its
@ -113,3 +144,21 @@ container assembly downstream is pure `binary format`.
subcommand. `stale` is a design-time mistake rather than a build-time one, which
argues for a subcommand plus an opportunistic check only when a bake actually
consumes an icon.
- Override behaviour in baked kits (recorded 2026-07-28): a kit .vfs that
overrides a common asset without shipping its own sidecar produces a kit
where the travelled common sidecar classifies the override as `replaced` -
truthful and intended. An overrider that wants `verified` inside the built
artifact ships its own sidecar beside the override; merge_over carries the
pair by same-path replacement with no new machinery.
- The sidecar shape eases the checker's parsing posture: each record is one
small flat toml table, so a self-contained subset reader stays defensible if
the tomlish dependency is unwanted in the scriptlib context - the checker's
toml/hash dependency posture is still an open decision for the work
(pre-activation review 2026-07-28).
- Open (pre-activation review 2026-07-28): whether sidecars for the
build-consumed `punkshell.ico` copies are acceptance-required - Scope names
two of the four (`src/runtime/`, `_vfscommon.vfs`; `mkzipfix.vfs` and
`punk8_statictwapi.vfs` carry byte-identical copies too) - and the explicit
decision that a sidecar committed in `_vfscommon.vfs` ships inside every
baked kit (the per-asset shape makes that collision-free; the shipping
intent itself is the open call).

18
goals/G-136-generated-project-icon-seeding.md

@ -3,7 +3,7 @@
Status: proposed
Scope: src/assets/logo/project-default/ (the single held seed artwork); src/modules/punk/mix/commandset/project-999999.0a1.0.tm (generation-time asset injection beside bootsupport_inject); src/project_layouts/ (per-layout icon-slot declaration with no artwork stored in layout trees); src/modules/punkcheck-999999.0a1.0.tm (install records for injected assets)
Goal: A newly generated project arrives with a working and inspectable icon - a readable vector master plus a ready-to-use `.ico` - injected from punkshell's single held copy at generation time, with no icon artwork stored in any layout payload tree, and regeneration never silently discards an owner's replacement.
Acceptance: `dev project.new` against a layout declaring an icon slot produces `src/assets/logo/` in the generated project containing `icon.svg`, `icon.ico` and an `assetorigin.toml` that the G-135 checker reports as `verified` in that tree (source and artifact both present, hashes matching), with the artwork sourced from `src/assets/logo/project-default/` at generation time rather than from any file under `src/project_layouts/` - verified by that tree containing no icon `.svg` or `.ico` payload; each injected file is recorded as a punkcheck install event in the same manner as `bootsupport_inject`; a layout declaring no icon slot generates a project with no `src/assets/logo/` and no warning; and re-running generation over a project whose `icon.svg` or `icon.ico` differs from the injected original leaves the owner's file intact and reports the skip by name.
Acceptance: `dev project.new` against a layout declaring an icon slot produces `src/assets/logo/` in the generated project containing `icon.svg`, `icon.ico` and `icon.ico.assetorigin.toml` that the G-135 checker reports as `verified` in that tree (artifact and recorded source both present, hashes matching), with the artwork sourced from `src/assets/logo/project-default/` at generation time rather than from any file under `src/project_layouts/` - verified by that tree containing no icon `.svg` or `.ico` payload; each injected file is recorded as a punkcheck install event in the same manner as `bootsupport_inject`; a layout declaring no icon slot generates a project with no `src/assets/logo/` and no warning; and re-running generation over a project whose `icon.svg` or `icon.ico` differs from the injected original leaves the owner's file intact and reports the skip by name.
## Context
@ -42,10 +42,11 @@ unbranded so it reads "replace me" rather than as a product identity.
a rasterizer, and requiring one of a fresh project would defeat the purpose;
the pair also gives the owner a complete worked example of the master-to-derived
relationship, which no amount of documentation prose achieves.
- The `assetorigin.toml` copies verbatim. Because G-135's record is
directory-scoped with relative paths, it needs no rewriting at the destination
and reads `verified` there - source and artifact are both present in the
generated tree.
- The `icon.ico.assetorigin.toml` sidecar copies verbatim. Because G-135's
record is a per-asset sidecar bound by its own filename with
directory-relative source references, it needs no rewriting at the
destination and reads `verified` there - artifact and recorded source are
both present in the generated tree.
- Per-layout icon-slot declaration. A layout may decline, and declining is not a
failure or a warning.
- Never clobber a replacement. Re-running generation over a project whose icon
@ -70,9 +71,10 @@ unbranded so it reads "replace me" rather than as a product identity.
## Notes
- Related: G-135 - depends on. Consumes the `assetorigin.toml` format and the
checker, and relies specifically on the record being directory-scoped with
relative paths so it survives injection unchanged.
- Related: G-135 - depends on. Consumes the sidecar record format and the
checker, and relies specifically on the record being a per-asset sidecar
with directory-relative references so it survives injection unchanged (and
a single asset re-injected travels with its record as a pair).
- Related: G-027 - consumer. Pull-based infrastructure updates for derived
projects would later refresh seeded assets, and both goals record their
installs through punkcheck.

53
goals/G-033-proj-mode-cwd-project.md → goals/archive/G-033-proj-mode-cwd-project.md

@ -1,6 +1,6 @@
# G-033 `proj:` package-mode scope prefix: visitor binary resolves dev/src against the cwd's project
Status: proposed
Status: achieved 2026-07-28
Scope: src/vfs/_config/punk_main.tcl (package-mode dispatch and boot-time root discovery); src/modules/punk/repo-999999.0a1.0.tm (find_project / is_project_root - reuse or lean boot mirror); bin/AGENTS.md (mode docs)
Goal: a `proj:` prefix on the package-mode string (e.g. `punkshell proj:internal-src shell`) makes the dev/src path blocks resolve against the punk project containing the current working directory - walking up to the nearest VCS repo root, the marker punk::repo::is_project_root already uses - instead of the executable's own project, so an installed ("visitor") punkshell binary, including one downloaded standalone with no source tree around it, can interactively explore a project that builds no shell-capable binary or no binary at all; the prefix scopes WHICH project, staying outside the ordered dash-list whose block order remains the same-version tie-break dial, and the explicit prefix gates the behaviour so no `cd` silently rebinds a normal launch.
Acceptance: `<installed-punkexe> proj:internal-src shell` (the documented canonical visitor invocation - kit copies win same-version ties, protecting the visiting shell's infrastructure; `proj:src` is the documented faithful-vintage variant where the project's copies win) launched from within a punk project's tree discovers the project root by walking up from cwd to the nearest VCS repo root and feeds it to the existing src-mode path machinery (src/modules, src/bootsupport/modules, src/vendormodules on the module path, src/lib on auto_path), so the session loads the project's dev-versioned modules while ordinary version resolution still lets the project supply anything the kit lacks or exceeds; the launch reports the detected project root and effective path precedence (never a silent rebind); with no project found walking up from cwd, or a `proj:` string containing no root-using block (dev/src), it warns and proceeds without false rebind; proven for a standalone binary outside any source tree (internal = kit contents regardless of binary location) against a project that builds no executable (tomlish is the natural first); exe-relative `src`/`dev` discovery is unchanged for a binary that IS in a project's bin/; the packagemode help text drafted in the detail file becomes the live punk::args documentation when implemented (rendered via G-032).
@ -188,3 +188,54 @@ ships with the prefix, not before):
already flag that `proj:... script` benefits; the two share the same root walk
and the same never-silent rebind rule.
- Archived-goal references in this file: G-015 achieved 2026-07-07 (goals/archive/G-015-script-subcommand-piped-stdin.md).
- Related: G-043 references this goal one-directionally (visitor binaries: shellproject-anchored
resources vs cwd-project resources) - relationship recorded at activation (2026-07-28
goals_xref survey; the other moderate-score overlaps G-123/G-127/G-131 share only
punk_main.tcl/bin co-location, no proj: semantics).
## Progress
Implemented and verified 2026-07-28 (activation and achievement same day; punkshell
0.29.0, punk::args::moduledoc::punkexe 0.1.1):
- Boot chicken-and-egg decision: option (a) - lean inline walk-up in punk_main.tcl
using only Tcl builtins, as `::punkboot::proj_root_find` (remains defined post-boot
for probing, like the G-129 mount procs). It mirrors punk::repo::is_project_root
including the is_candidate_root requirements (unwise-path exclusion; ./src plus one
of src/modules, src/vfs, src/scriptapps, or punkproject.toml) so boot-time and
runtime discovery agree (the G-016 findable-by-both principle). One recorded
divergence: `.git` is accepted as file OR directory (worktree/submodule checkouts),
where punk::repo::is_git_root requires a directory.
- proj: with an invalid mode remainder is not consumed (whole arg passes through as
subcommand/script, matching the existing invalid-mode fallthrough); bare `proj:`
is consumed as internal and then warned as having no root-using block.
- dev under proj: resolves <projroot>/modules{,_tcl<N>} and <projroot>/lib{,_tcl<N>}
only - the exe-relative and cwd-relative lib candidates of the exe-anchored dev
mode are deliberately not mixed in.
- Verification (punk91 kit rebaked with the new boot; standalone copy of the kit
placed in a session scratchpad outside any source tree):
- `punkvisit.exe proj:internal-src script <probe>` from c:/repo/jn/tclmodules/tomlish
(fossil root, builds no executable): root detected and reported, precedence line
reported, tomlish src paths appended after kit-internal paths, and
`package require tomlish` -> 999999.0a1.0 sourced from tomlish/src/modules.
- Same from C:/repo/jn/shellspy: "src mode: registered 6 #modpod modules" (modpod
scanner fed by the visited root) and the punkexe moduledoc loads from the visited
project's src/modules at 999999.0a1.0.
- `proj:src` variant: tomlish src paths BEFORE kit-internal paths (faithful-vintage
ordering).
- No-project case (cwd = scratchpad): warns and proceeds, script still runs,
dev/src unbound.
- `proj:os`: warns 'proj:' has no effect (no dev/src block).
- Exe-relative regression: `bin/punk91 src script <probe>` unchanged (modpods
registered, dev module versions load); piped `punk` subcommand under
proj:internal-src evaluates in the shell environment with the visited project's
modules (its exit code 1 on piped `exit` is pre-existing, present without proj:).
- packagemode help text is live: the drafted leader text (extended with the proj:
wording) sits in punk::args::moduledoc::punkexe 0.1.1 as the packagemode leader of
`(script)::punkexe` (@leaders max raised to 2); rendering/parse wiring remains
G-032's lane. The freshly deployed kit still carries moduledoc 0.1.0 - the 0.1.1
stamp reaches kits at the next vfscommonupdate promotion (deliberately not run from
a dirty tree in this change-set).
- Docs: bin/AGENTS.md launch-package-modes section (proj: contract + canonical
invocations), src/vfs/AGENTS.md punk_main contract line, ARCHITECTURE.md entry-point
bullet; CHANGELOG 0.29.0 entry (minor bump - new launch invocation).

2
punkproject.toml

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

38
src/modules/punk/args/moduledoc/punkexe-999999.0a1.0.tm

@ -91,9 +91,13 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
An optional FIRST argument selects package modes: one or more of
the tokens dev, os, src, internal joined with '-' when combined
(e.g 'dev', 'src', 'dev-src'). Modes decide which module sources
the shell trusts and their precedence; 'internal' (kit-bundled
modules) is always appended when absent. Details: bin/AGENTS.md
(e.g 'dev', 'src', 'dev-src'), optionally scoped with the
'proj:' prefix (e.g 'proj:internal-src') so dev/src resolve
against the project containing the current directory instead of
the executable's own (G-033 visitor mode). Modes decide which
module sources the shell trusts and their precedence; 'internal'
(kit-bundled modules) is always appended when absent. Full
contract: the packagemode leader below and bin/AGENTS.md
'launch package modes' in the punkshell source tree.
The next argument selects a subcommand from the choices below.
@ -102,7 +106,33 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
('shell'); any other first argument is treated as a script
invocation (handled as for the 'script' subcommand)."
@form -synopsis "<punkexe> ?packagemode? ?subcommand? ?arg ...?"
@leaders -min 0 -max 1
@leaders -min 0 -max 2
packagemode -type string -optional 1 -default internal -help\
"Package-source mode: an ordered dash-separated list of path
blocks, optionally scoped with the 'proj:' prefix.
Blocks (each adds a group of module/library paths):
internal - paths inside the executable's kit (always included;
appended last unless listed explicitly)
dev - the project's built output (<projectroot>/modules ...)
src - the project's unbuilt source (src/modules,
src/bootsupport/modules, src/vendormodules, src/lib)
os - ad-hoc .tm paths from the current directory/environment
Without 'proj:', dev/src resolve against the executable's own
project (executable in <projectroot>/bin). With 'proj:', they
resolve against the nearest project root at or above the current
directory (a git or fossil repository root) - for an installed
punkshell binary visiting a project that builds no shell of its
own.
ORDER MATTERS: earlier blocks win when the same version of a
module exists in more than one location.
Examples:
src work on the executable's own project source
proj:internal-src explore the cwd project; the executable's own
copies win version ties (robust visitor default)
proj:src explore the cwd project; ITS copies win version
ties (faithful to the project's snapshot vintage)
The launch reports the detected project root and effective
precedence."
subcommand -type string -optional 1 -choicerestricted 0 -choices {tclsh script shell punk shellspy} -choicelabels {
tclsh
" Run as a (near) stock tclsh - no punk modules loaded."

2
src/modules/punk/args/moduledoc/punkexe-buildversion.txt

@ -1,3 +1,3 @@
0.1.0
0.1.1
#First line must be a semantic version number
#all other lines are ignored.

2
src/vfs/AGENTS.md

@ -16,7 +16,7 @@ VFS (Virtual File System) folders define the runtime payloads that get wrapped i
- A `*.vfs` folder built against a runtime is expected to carry a root-level startup script: an actual `main.tcl`, or a root fauxlink resolving to the name `main.tcl` whose target exists and is a `.tcl` file. `make.tcl` warns when neither is present (column-0 `BUILD-WARNING:` token, ANSI-highlighted, recapped at end of run like provenance warnings) but still builds - a kit without a startup script is legal. Overlay-only folders with no runtime mapping (e.g `_vfscommon.vfs`) are not checked.
- VFS content must be compatible with the target platform runtime.
- `_vfscommon.vfs/` is an auto-generated merge of common libraries; manually editing it will be overwritten.
- `_config/punk_main.tcl` accepts an optional package_mode argument before the subcommand. Valid modes are `dev`, `os`, `internal`, and `src`, dash-delimited in priority order (e.g `src-internal`). `internal` is always appended if omitted.
- `_config/punk_main.tcl` accepts an optional package_mode argument before the subcommand. Valid modes are `dev`, `os`, `internal`, and `src`, dash-delimited in priority order (e.g `src-internal`). `internal` is always appended if omitted. An optional `proj:` prefix (G-033, e.g `proj:internal-src`) makes `dev`/`src` resolve against the project containing the cwd (walk-up to the nearest git/fossil repo root with a punkshell-style src tree, via `::punkboot::proj_root_find`) instead of the executable's own project; discovery outcome is always reported on stderr and a failed discovery leaves dev/src unbound rather than falling back exe-relative.
- `_config/punk_main.tcl` captures the runtime's static/builtin packages at boot (G-058): empty-filename `info loaded` prefixes are probe-loaded in a throwaway interp (denylist `::punkboot::static_probe_denylist`, default `tk* vfs mk4tcl vlerq tdbc*` - side-effecting or composite inits) and each package a probe-load actually PROVIDES is recorded in `::punkboot::static_packages` {pkgname {version <v> prefix <p>}} with `::punkboot::static_prefixes` alongside. The boot interp and every punkshell-fabricated interp/thread (punk::lib::interp_sync_package_paths / snapshot_package_paths, repl codethread, shellthread workers) seed `package ifneeded <name> <ver> {load {} <prefix>}` from it, and punk::packagepreference resolves static-vs-bundled version-aware. Composite statics whose script layer lived in the runtime's own (replaced) zipfs provide nothing under the probe and are correctly left to bundled copies.
- `src` mode loads unbuilt modules and libraries from the project's `src/` tree (`src/modules`, `src/lib`, `src/bootsupport`, `src/vendormodules`) instead of built output. It also runs an inline `#modpod` package-ifneeded scanner (using Tcl builtins only, since no punk modules are loaded at boot time) and sets `package prefer latest` so `999999.0a1.0` dev modules are preferred over stable bootsupport/vendored copies.
- `_config/punk_main.tcl` and `_config/project_main.tcl` derive the kit's payload location from the runtime's own zipfs mount table (G-129): zipfs presence keys on `tcl::zipfs::mount` (not `tcl::zipfs::root`, which the androwish/undroidwish 8.6 backport lacks), the mount base is the table entry whose archive file is `[info nameofexecutable]` (fallback: the mount containing the boot script), `//zipfs:/app` stays the expected modern answer rather than a compiled-in assumption, and a mounted archive that cannot be attributed to the executable is reported on stderr. The derivation lives in `::punkboot` procs (`zipfs_kit_mountbase`, `zipfs_mount_pairs`, `path_within`) that remain defined after boot for probing and tests. Both files carry identical copies of this logic (G-031 is the planned consolidation). Characterization: `src/tests/shell/testsuites/punkexe/kitmountpoint.test`.

235
src/vfs/_config/punk_main.tcl

@ -366,6 +366,45 @@ apply { args {
}
return ""
}
proc proj_root_find {startdir} {
#G-033: lean boot mirror of punk::repo::find_project (scanup on
#is_project_root) using only Tcl builtins - punk::repo is not loadable at
#the package-mode boot phase. Walks up from $startdir to the nearest VCS
#repo root (git or fossil control markers; 'file exists' sees
#windows-hidden items) that also passes a lean punk::repo::is_candidate_root
#check: not an unwise location, has ./src, and one of ./src/modules,
#./src/vfs, ./src/scriptapps or ./punkproject.toml. Keep the semantics
#aligned with punk::repo so a project findable at boot is findable by the
#runtime layer and vice versa (known divergence: .git is accepted as file
#OR dir - git worktree/submodule checkouts are legitimate visit targets).
#Returns the project root, or "" when no candidate is found.
set unwise_paths [list "/" "/dev" "/bin" "/root" "/etc" "/opt" "/usr" "/usr/local" "/usr/local/bin" "/usr/local/lib" "c:/windows"]
set dir [file normalize $startdir]
while 1 {
set is_repo_root 0
foreach marker [list .git _FOSSIL_ .fslckout .fos] {
if {[file exists [file join $dir $marker]]} {
set is_repo_root 1
break
}
}
if {$is_repo_root && [string tolower $dir] ni $unwise_paths} {
if {[file isdirectory [file join $dir src]]} {
if {[file isdirectory [file join $dir src modules]]\
|| [file isdirectory [file join $dir src vfs]]\
|| [file isdirectory [file join $dir src scriptapps]]\
|| [file exists [file join $dir punkproject.toml]]} {
return $dir
}
}
}
set parent [file dirname $dir]
if {$parent eq $dir} {
return ""
}
set dir $parent
}
}
}
#G-129: key zipfs presence on tcl::zipfs::mount - present in every supported zipfs
@ -613,14 +652,24 @@ apply { args {
#Token-by-token validation: instead of exhaustively listing all permutations,
#split the first arg on dash and validate each token against the known mode set.
#This scales to any number of modes without enumerating every permutation.
#G-033: an optional 'proj:' prefix on the mode string (e.g proj:internal-src)
#scopes WHICH project the dev/src blocks resolve against - the project containing
#the cwd instead of the executable's own. The prefix sits outside the ordered
#dash-list, whose block order remains the same-version tie-break dial.
set proj_scope 0
set test_mode_string $test_package_mode
if {[string match proj:* $test_package_mode]} {
set proj_scope 1
set test_mode_string [string range $test_package_mode 5 end]
}
set package_modes ""
set arglist ""
if {$test_package_mode eq ""} {
#empty first arg consumed as equivalent of 'internal'
if {$test_mode_string eq ""} {
#empty first arg (or bare 'proj:') consumed as equivalent of 'internal'
set package_modes internal
set arglist [lrange $args 1 end]
} else {
set tokens [split $test_package_mode -]
set tokens [split $test_mode_string -]
set valid 1
foreach t $tokens {
if {$t ni $all_package_modes} {
@ -636,6 +685,9 @@ apply { args {
set arglist [lrange $args 1 end]
} else {
#not a package_mode - treat as subcommand
#(a 'proj:' prefix on a non-mode string is not consumed either - the
#whole arg passes through, e.g as a script name)
set proj_scope 0
set package_modes internal
set arglist $args
}
@ -644,6 +696,28 @@ apply { args {
set ::argv $arglist
set ::argc [llength $arglist]
#assert: package_modes is now a list of at least length 1 (in which case the only possible value is: internal)
#--------------------------------------------------------
#G-033 proj: scope - resolve dev/src against the project containing the cwd
#(walk-up to the nearest VCS repo root, the punk::repo::is_project_root marker)
#instead of the executable's own project. Explicit prefix = opt-in; discovery and
#its outcome are always reported on stderr (a rebind must never be silent), and a
#failed discovery never falls back to exe-relative roots (no false rebind).
#--------------------------------------------------------
set proj_root ""
if {$proj_scope} {
if {!("dev" in $package_modes || "src" in $package_modes)} {
puts stderr "proj: WARNING - 'proj:' has no effect: package mode list '[join $package_modes -]' contains no project-root-using block (dev or src)"
} else {
set proj_root [::punkboot::proj_root_find [pwd]]
if {$proj_root eq ""} {
puts stderr "proj: WARNING - no project root found walking up from [pwd] (nearest git/fossil repo root with a punkshell-style src tree) - dev/src blocks are not bound to any project (proceeding; internal/os paths unaffected)"
} else {
puts stderr "proj: project root detected (walk-up from [pwd]): $proj_root"
puts stderr "proj: effective package mode precedence: [join $package_modes -] (earlier blocks win same-version ties)"
}
}
}
#Note regarding the use of package forget and binary packages
#If the package has loaded a binary component - then a package forget and a subsequent package require can result in both binaries being present, as seen in 'info loaded' result - potentially resulting in anomalous behaviour
#In general package forget after a package has already been required may need special handling and should be avoided where possible.
@ -722,24 +796,36 @@ apply { args {
#case differences could represent different paths on unix-like platforms.
#It's perhaps a little unwise to configure matching paths with only case differences for a cross-platform tool .. but we should support it for those who use it and have no interest in windows - todo! review
if {"dev" in $package_modes} {
set normexe_dir [file dirname $normexe]
if {[file tail $normexe_dir] eq "bin"} {
#underlying exe in a bin dir - backtrack 1
lappend exe_module_folders [file dirname $normexe_dir]/modules
lappend exe_module_folders [file dirname $normexe_dir]/modules_tcl$tclmajorv
set exe_module_folders [list]
if {$proj_scope} {
#G-033: dev module paths resolve against the cwd-walk-up project root
#only - no exe-relative fallback (a proj: launch must never silently
#rebind to the executable's own project; a failed discovery was
#already warned above and the dev block then contributes nothing).
if {$proj_root ne ""} {
lappend exe_module_folders $proj_root/modules
lappend exe_module_folders $proj_root/modules_tcl$tclmajorv
}
} else {
lappend exe_module_folders $normexe_dir/modules
lappend exe_module_folders $normexe_dir/modules_tcl$tclmajorv
}
set nameexe_dir [file dirname [file normalize [info nameofexecutable]]] ;#must be normalized for capitalisation consistency
set normexe_dir [file dirname $normexe]
if {[file tail $normexe_dir] eq "bin"} {
#underlying exe in a bin dir - backtrack 1
lappend exe_module_folders [file dirname $normexe_dir]/modules
lappend exe_module_folders [file dirname $normexe_dir]/modules_tcl$tclmajorv
} else {
lappend exe_module_folders $normexe_dir/modules
lappend exe_module_folders $normexe_dir/modules_tcl$tclmajorv
}
set nameexe_dir [file dirname [file normalize [info nameofexecutable]]] ;#must be normalized for capitalisation consistency
#possible symlink (may resolve to same path as above - we check below to not add in twice)
if {[file tail $nameexe_dir] eq "bin"} {
lappend exe_module_folders [file dirname $nameexe_dir]/modules
lappend exe_module_folders [file dirname $nameexe_dir]/modules_tcl$tclmajorv
} else {
lappend exe_module_folders $nameexe_dir/modules
lappend exe_module_folders $nameexe_dir/modules_tcl$tclmajorv
#possible symlink (may resolve to same path as above - we check below to not add in twice)
if {[file tail $nameexe_dir] eq "bin"} {
lappend exe_module_folders [file dirname $nameexe_dir]/modules
lappend exe_module_folders [file dirname $nameexe_dir]/modules_tcl$tclmajorv
} else {
lappend exe_module_folders $nameexe_dir/modules
lappend exe_module_folders $nameexe_dir/modules_tcl$tclmajorv
}
}
#foreach modulefolder $exe_module_folders {
@ -766,7 +852,10 @@ apply { args {
# }
#}
if {![llength $exe_module_folders]} {
puts stderr "Warning - no 'modules' or 'modules_tcl$tclmajorv' folders found relative to executable (or it's symlink if any)"
#proj_scope with no discovered root was already warned at proj: discovery
if {!$proj_scope} {
puts stderr "Warning - no 'modules' or 'modules_tcl$tclmajorv' folders found relative to executable (or it's symlink if any)"
}
} else {
set tm_additions_dev $exe_module_folders
}
@ -776,21 +865,28 @@ apply { args {
#Unlike dev mode (which points at built output in <projectroot>/modules),
#src mode points at the unbuilt source in <projectroot>/src/modules etc.
if {"src" in $package_modes} {
#reuse the dev-mode project root discovery (exe in bin/ -> backtrack 1)
set src_project_root ""
set normexe_dir_for_src [file dirname $normexe]
if {[file tail $normexe_dir_for_src] eq "bin"} {
set src_project_root [file dirname $normexe_dir_for_src]
if {$proj_scope} {
#G-033: src resolves against the cwd-walk-up project root; empty
#(warned at discovery) means the src block contributes nothing -
#never an exe-relative fallback rebind.
set src_project_root $proj_root
} else {
set src_project_root $normexe_dir_for_src
}
#also check symlink target
if {$src_project_root eq ""} {
set nameexe_dir_for_src [file dirname [file normalize [info nameofexecutable]]]
if {[file tail $nameexe_dir_for_src] eq "bin"} {
set src_project_root [file dirname $nameexe_dir_for_src]
#reuse the dev-mode project root discovery (exe in bin/ -> backtrack 1)
set normexe_dir_for_src [file dirname $normexe]
if {[file tail $normexe_dir_for_src] eq "bin"} {
set src_project_root [file dirname $normexe_dir_for_src]
} else {
set src_project_root $nameexe_dir_for_src
set src_project_root $normexe_dir_for_src
}
#also check symlink target
if {$src_project_root eq ""} {
set nameexe_dir_for_src [file dirname [file normalize [info nameofexecutable]]]
if {[file tail $nameexe_dir_for_src] eq "bin"} {
set src_project_root [file dirname $nameexe_dir_for_src]
} else {
set src_project_root $nameexe_dir_for_src
}
}
}
@ -816,7 +912,14 @@ apply { args {
}
}
} else {
puts stderr "Warning - src mode: no src/ directory found relative to executable ($normexe_dir_for_src)"
if {$proj_scope} {
#no discovered root was already warned at proj: discovery
if {$src_project_root ne ""} {
puts stderr "Warning - src mode (proj:): no src/ directory under detected project root ($src_project_root)"
}
} else {
puts stderr "Warning - src mode: no src/ directory found relative to executable ($normexe_dir_for_src)"
}
}
}
@ -947,36 +1050,50 @@ apply { args {
#on other platforms, case differences could represent different paths
#review
set process_folders [list]
foreach libsub [list lib_tcl$tclmajorv lib] {
if {[file tail $nameexe_dir] eq "bin"} {
set libfolder [file dirname $nameexe_dir]/$libsub
} else {
set libfolder $nameexe_dir/$libsub
}
if {[file isdirectory $libfolder]} {
#lappend auto_path_additions_dev $libfolder
lappend process_folders $libfolder
}
# -------------
if {[file tail $normexe_dir] eq "bin"} {
set libfolder [file dirname $normexe_dir]/$libsub
} else {
set libfolder $normexe_dir/$libsub
}
if {[file isdirectory $libfolder]} {
#lappend auto_path_additions_dev $libfolder
if {$libfolder ni $process_folders} {
lappend process_folders $libfolder
if {$proj_scope} {
#G-033: dev lib paths resolve against the cwd-walk-up project root
#only (no exe-relative or cwd-relative candidates - see the dev
#module-path block above for rationale).
if {$proj_root ne ""} {
foreach libsub [list lib_tcl$tclmajorv lib] {
set libfolder $proj_root/$libsub
if {[file isdirectory $libfolder] && $libfolder ni $process_folders} {
lappend process_folders $libfolder
}
}
}
# -------------
set libfolder [pwd]/$libsub
if {[file isdirectory $libfolder]} {
#lappend auto_path_additions_dev $libfolder
if {$libfolder ni $process_folders} {
} else {
foreach libsub [list lib_tcl$tclmajorv lib] {
if {[file tail $nameexe_dir] eq "bin"} {
set libfolder [file dirname $nameexe_dir]/$libsub
} else {
set libfolder $nameexe_dir/$libsub
}
if {[file isdirectory $libfolder]} {
#lappend auto_path_additions_dev $libfolder
lappend process_folders $libfolder
}
# -------------
if {[file tail $normexe_dir] eq "bin"} {
set libfolder [file dirname $normexe_dir]/$libsub
} else {
set libfolder $normexe_dir/$libsub
}
if {[file isdirectory $libfolder]} {
#lappend auto_path_additions_dev $libfolder
if {$libfolder ni $process_folders} {
lappend process_folders $libfolder
}
}
# -------------
set libfolder [pwd]/$libsub
if {[file isdirectory $libfolder]} {
#lappend auto_path_additions_dev $libfolder
if {$libfolder ni $process_folders} {
lappend process_folders $libfolder
}
}
}
}
foreach f $process_folders {

340
src/vfs/_vfscommon.vfs/modules/argparsingtest-1.2.0.tm → src/vfs/_vfscommon.vfs/modules/argparsingtest-1.3.0.tm

@ -8,7 +8,7 @@
# (C) Julian Noble 2024
#
# @@ Meta Begin
# Application argparsingtest 1.2.0
# Application argparsingtest 1.3.0
# Meta platform tcl
# Meta license MIT
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_argparsingtest 0 1.2.0]
#[manpage_begin punkshell_module_argparsingtest 0 1.3.0]
#[copyright "2024"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
@ -50,15 +50,28 @@
package require Tcl 8.6-
package require punk::args
package require opt
package require cmdline
package require tepam
# Every parser package this module compares is OPTIONAL, including the tcllib ones.
# A comparison harness that cannot load at all because one of the libraries it
# compares is absent is useless on exactly the runtime you most want to measure -
# and punkshell builds do ship without tcllib. A missing library must degrade to a
# not_loaded row (see the {optional <pkg>} roster markers), never to a load failure.
# Guarded here rather than at the call sites because the guard needed differs:
# cmdline - used only INSIDE proc bodies, so the requires below are the whole story
# opt - tcl::OptProc DEFINES the wrapper procs, so each definition site is
# tepam additionally guarded by an 'is the package present' test. Those sites
# test presence rather than catching, so a genuine error in a spec still
# surfaces loudly on a runtime that does have the package.
# argp, parse_args and argparse are required further down, at their own sites.
catch {package require opt}
catch {package require cmdline}
catch {package require tepam}
#*** !doctools
#[item] [package {Tcl 8.6}]
#[item] [package {punk::args}]
#[item] [package {opt}]
#[item] [package {cmdline}]
#[item] [package {tepam}]
#[item] [package {opt}] (optional - parser under test)
#[item] [package {cmdline}] (optional - parser under test)
#[item] [package {tepam}] (optional - parser under test)
# #package require frobz
# #*** !doctools
@ -163,13 +176,13 @@ namespace eval argparsingtest {
punkargs_by_id always
punkargs_parsecache always
punkargs_validate_ansistripped always
opt always
cmdline_untyped always
cmdline_typed always
opt {optional opt}
cmdline_untyped {optional cmdline}
cmdline_typed {optional cmdline}
argp {optional argp}
parse_args {optional parse_args}
argparse {optional argparse}
tepam always
tepam {optional tepam}
}
}
tkstyle {
@ -180,8 +193,8 @@ namespace eval argparsingtest {
punkargs always
punkargs_by_id always
punkargs_parsecache always
opt always
tepam always
opt {optional opt}
tepam {optional tepam}
argparse {optional argparse}
cmdline_untyped unsupported
cmdline_typed unsupported
@ -197,10 +210,10 @@ namespace eval argparsingtest {
punkargs always
punkargs_by_id always
punkargs_parsecache always
opt always
cmdline_untyped always
cmdline_typed always
tepam always
opt {optional opt}
cmdline_untyped {optional cmdline}
cmdline_typed {optional cmdline}
tepam {optional tepam}
parse_args {optional parse_args}
argparse {optional argparse}
argp unsupported
@ -214,7 +227,7 @@ namespace eval argparsingtest {
punkargs always
punkargs_by_id always
punkargs_parsecache always
opt always
opt {optional opt}
argparse {optional argparse}
cmdline_untyped unsupported
cmdline_typed unsupported
@ -1494,24 +1507,27 @@ namespace eval argparsingtest::opts {
-join -type none -multiple 1
}]
}
tcl::OptProc opt {
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
} {
set opts [dict create]
foreach v [info locals] {
dict set opts $v [set $v]
#tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
if {![catch {package present opt}]} {
tcl::OptProc opt {
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
} {
set opts [dict create]
foreach v [info locals] {
dict set opts $v [set $v]
}
return $opts
}
return $opts
}
#cmdline::getoptions is much faster than typedGetoptions
@ -1736,22 +1752,25 @@ namespace eval argparsingtest::opts {
-join -type none -multiple 1
}]
}
tepam::procedure {tepam} {
-args {
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default ""}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
}
} {
return [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]
#tepam::procedure DEFINES this proc, so skip the definition when tepam is absent - see the optional-package requires at the module top
if {![catch {package present tepam}]} {
tepam::procedure {tepam} {
-args {
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default ""}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
}
} {
return [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]
}
}
#*** !doctools
@ -1967,28 +1986,31 @@ namespace eval argparsingtest::tkstyle {
-join -type none -multiple 1
}]
}
tcl::OptProc opt {
{p1 -string "first positional argument"}
{p2 -string "second positional argument"}
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
} {
set opts [dict create]
foreach v [info locals] {
if {$v ni {p1 p2 opts args Args}} {
dict set opts $v [set $v]
#tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
if {![catch {package present opt}]} {
tcl::OptProc opt {
{p1 -string "first positional argument"}
{p2 -string "second positional argument"}
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
} {
set opts [dict create]
foreach v [info locals] {
if {$v ni {p1 p2 opts args Args}} {
dict set opts $v [set $v]
}
}
return [list $p1 $p2 $opts]
}
return [list $p1 $p2 $opts]
}
namespace eval argdoc {
@ -2015,25 +2037,28 @@ namespace eval argparsingtest::tkstyle {
-join -type none -multiple 1
}]
}
tepam::procedure {tepam} {
-named_arguments_first 0
-args {
{p1 -type string}
{p2 -type string}
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default ""}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
}
} {
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]]
#tepam::procedure DEFINES this proc, so skip the definition when tepam is absent - see the optional-package requires at the module top
if {![catch {package present tepam}]} {
tepam::procedure {tepam} {
-named_arguments_first 0
-args {
{p1 -type string}
{p2 -type string}
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default ""}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
}
} {
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]]
}
}
namespace eval argdoc {
@ -2296,28 +2321,31 @@ namespace eval argparsingtest::tclstyle {
p2 -type string -optional 0
}]
}
tcl::OptProc opt {
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
{p1 -string "first positional argument"}
{p2 -string "second positional argument"}
} {
set opts [dict create]
foreach v [info locals] {
if {$v ni {p1 p2 opts args Args}} {
dict set opts $v [set $v]
#tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
if {![catch {package present opt}]} {
tcl::OptProc opt {
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
{p1 -string "first positional argument"}
{p2 -string "second positional argument"}
} {
set opts [dict create]
foreach v [info locals] {
if {$v ni {p1 p2 opts args Args}} {
dict set opts $v [set $v]
}
}
return [list $p1 $p2 $opts]
}
return [list $p1 $p2 $opts]
}
namespace eval argdoc {
@ -2439,24 +2467,27 @@ namespace eval argparsingtest::tclstyle {
p2 -type string -optional 0
}]
}
tepam::procedure {tepam} {
-args {
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default ""}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
{p1 -type string}
{p2 -type string}
}
} {
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]]
#tepam::procedure DEFINES this proc, so skip the definition when tepam is absent - see the optional-package requires at the module top
if {![catch {package present tepam}]} {
tepam::procedure {tepam} {
-args {
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default ""}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
{p1 -type string}
{p2 -type string}
}
} {
return [list $p1 $p2 [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]]
}
}
namespace eval argdoc {
@ -2848,31 +2879,34 @@ namespace eval argparsingtest::sandwich {
p5 -type string -optional 0
}]
}
tcl::OptProc opt {
{p1 -string "first leading positional argument"}
{p2 -string "second leading positional argument"}
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
{p3 -string "first trailing positional argument"}
{p4 -string "second trailing positional argument"}
{p5 -string "third trailing positional argument"}
} {
set opts [dict create]
foreach v [info locals] {
if {$v ni {p1 p2 p3 p4 p5 opts args Args}} {
dict set opts $v [set $v]
#tcl::OptProc DEFINES this proc, so skip the definition when opt is absent - see the optional-package requires at the module top
if {![catch {package present opt}]} {
tcl::OptProc opt {
{p1 -string "first leading positional argument"}
{p2 -string "second leading positional argument"}
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x "" "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
{p3 -string "first trailing positional argument"}
{p4 -string "second trailing positional argument"}
{p5 -string "third trailing positional argument"}
} {
set opts [dict create]
foreach v [info locals] {
if {$v ni {p1 p2 p3 p4 p5 opts args Args}} {
dict set opts $v [set $v]
}
}
return [list [list $p1 $p2] [list $p3 $p4 $p5] $opts]
}
return [list [list $p1 $p2] [list $p3 $p4 $p5] $opts]
}
namespace eval argdoc {
@ -2985,7 +3019,7 @@ namespace eval ::punk::args::register {
package provide argparsingtest [namespace eval argparsingtest {
variable pkg argparsingtest
variable version
set version 1.2.0
set version 1.3.0
}]
return

4
src/vfs/_vfscommon.vfs/modules/oolib-0.1.3.tm → src/vfs/_vfscommon.vfs/modules/oolib-0.1.4.tm

@ -136,7 +136,7 @@ namespace eval oolib {
error "[self object] collection key must not be an integer. Use another structure if integer keys required"
}
if {[dict exists $o_data $key]} {
error "[self object] col_processors object error: key '$key' already exists in collection"
error "[self object] collection error: key '$key' already exists in collection"
}
dict set o_data $key $value
return [expr {[dict size $o_data] - 1}] ;#return index of item
@ -196,5 +196,5 @@ namespace eval oolib {
package provide oolib [namespace eval oolib {
variable version
set version 0.1.3
set version 0.1.4
}]

44
src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/punkexe-0.1.0.tm → src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/punkexe-0.1.1.tm

@ -8,7 +8,7 @@
# (C) 2026
#
# @@ Meta Begin
# Application punk::args::moduledoc::punkexe 0.1.0
# Application punk::args::moduledoc::punkexe 0.1.1
# Meta platform tcl
# Meta license BSD
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::args::moduledoc::punkexe 0 0.1.0]
#[manpage_begin punkshell_module_punk::args::moduledoc::punkexe 0 0.1.1]
#[copyright "2026"]
#[titledesc {punk executable launch documentation}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
@ -91,9 +91,13 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
An optional FIRST argument selects package modes: one or more of
the tokens dev, os, src, internal joined with '-' when combined
(e.g 'dev', 'src', 'dev-src'). Modes decide which module sources
the shell trusts and their precedence; 'internal' (kit-bundled
modules) is always appended when absent. Details: bin/AGENTS.md
(e.g 'dev', 'src', 'dev-src'), optionally scoped with the
'proj:' prefix (e.g 'proj:internal-src') so dev/src resolve
against the project containing the current directory instead of
the executable's own (G-033 visitor mode). Modes decide which
module sources the shell trusts and their precedence; 'internal'
(kit-bundled modules) is always appended when absent. Full
contract: the packagemode leader below and bin/AGENTS.md
'launch package modes' in the punkshell source tree.
The next argument selects a subcommand from the choices below.
@ -102,7 +106,33 @@ tcl::namespace::eval punk::args::moduledoc::punkexe {
('shell'); any other first argument is treated as a script
invocation (handled as for the 'script' subcommand)."
@form -synopsis "<punkexe> ?packagemode? ?subcommand? ?arg ...?"
@leaders -min 0 -max 1
@leaders -min 0 -max 2
packagemode -type string -optional 1 -default internal -help\
"Package-source mode: an ordered dash-separated list of path
blocks, optionally scoped with the 'proj:' prefix.
Blocks (each adds a group of module/library paths):
internal - paths inside the executable's kit (always included;
appended last unless listed explicitly)
dev - the project's built output (<projectroot>/modules ...)
src - the project's unbuilt source (src/modules,
src/bootsupport/modules, src/vendormodules, src/lib)
os - ad-hoc .tm paths from the current directory/environment
Without 'proj:', dev/src resolve against the executable's own
project (executable in <projectroot>/bin). With 'proj:', they
resolve against the nearest project root at or above the current
directory (a git or fossil repository root) - for an installed
punkshell binary visiting a project that builds no shell of its
own.
ORDER MATTERS: earlier blocks win when the same version of a
module exists in more than one location.
Examples:
src work on the executable's own project source
proj:internal-src explore the cwd project; the executable's own
copies win version ties (robust visitor default)
proj:src explore the cwd project; ITS copies win version
ties (faithful to the project's snapshot vintage)
The launch reports the detected project root and effective
precedence."
subcommand -type string -optional 1 -choicerestricted 0 -choices {tclsh script shell punk shellspy} -choicelabels {
tclsh
" Run as a (near) stock tclsh - no punk modules loaded."
@ -335,7 +365,7 @@ namespace eval ::punk::args::register {
package provide punk::args::moduledoc::punkexe [tcl::namespace::eval punk::args::moduledoc::punkexe {
variable pkg punk::args::moduledoc::punkexe
variable version
set version 0.1.0
set version 0.1.1
}]
return

BIN
src/vfs/_vfscommon.vfs/modules/punk/mix/templates-0.2.0.tm

Binary file not shown.

175
src/vfs/_vfscommon.vfs/modules/punk/zip-0.2.0.tm → src/vfs/_vfscommon.vfs/modules/punk/zip-0.3.0.tm

@ -9,7 +9,7 @@
# (C) 2009 Path Thoyts <patthyts@users.sourceforge.net>
#
# @@ Meta Begin
# Application punk::zip 0.2.0
# Application punk::zip 0.3.0
# Meta platform tcl
# Meta license MIT
# @@ Meta End
@ -19,7 +19,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::zip 0 0.2.0]
#[manpage_begin punkshell_module_punk::zip 0 0.3.0]
#[copyright "2024"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
@ -66,7 +66,15 @@ package require punk::args
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::zip {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
#variable xyz
#G-126 accelerator state - see punk::zip::accelerator and punk::zip::unzip.
#The pure-Tcl reader is the always-available floor; the vendored punkzip
#binary is an optional per-call extraction accelerator.
variable accelerator_config auto ;#auto | none | <path to punkzip executable>
variable accelerator_resolved ""
variable accelerator_resolved_for "\uFFFF" ;#config value the cached resolution was computed for
variable last_unzip_engine "" ;#tcl | accelerated - which engine the last unzip used
variable last_accelerator_note "" ;#why the last unzip skipped the accelerator or fell back
#*** !doctools
#[subsection {Namespace punk::zip}]
@ -1104,6 +1112,79 @@ tcl::namespace::eval punk::zip {
return [Select_members [dict get $arc members] $globs $excludes]
}
punk::args::define {
@id -id ::punk::zip::accelerator
@cmd -name punk::zip::accelerator\
-summary\
"Query or configure the optional punkzip extraction accelerator"\
-help\
"punk::zip can hand whole-archive extraction to the vendored punkzip
tool (goal G-126; built to bin/ by 'make.tcl tool build punkzip')
when a usable binary is present - materially faster for large member
counts - while the pure-Tcl reader remains the always-available
floor and the authority on preflight refusals, member selection and
returned names.
With no argument, returns the currently resolved accelerator path,
or an empty string when none is usable. With an argument, sets the
configuration and returns the new resolution:
auto - (default) probe: env(PUNKZIP_EXE) if set, else a punkzip
executable beside [info nameofexecutable]
none - disable the accelerator (pure-Tcl always)
<path> - use the punkzip binary at an explicit path
Resolution is cached until the configuration changes. See
punk::zip::unzip for when the accelerator is actually used: calls it
cannot serve identically run pure-Tcl, and an accelerator failure
falls back to pure-Tcl silently. For diagnostics and tests,
punk::zip::last_unzip_engine records which engine the last unzip
used (tcl|accelerated) and punk::zip::last_accelerator_note records
why the accelerator was skipped or abandoned."
@values -min 0 -max 1
config -optional 1 -default "" -help\
"auto | none | path of a punkzip executable.
Empty (or omitted) queries without changing the configuration."
}
proc accelerator {args} {
set argd [punk::args::parse $args withid ::punk::zip::accelerator]
variable accelerator_config
variable accelerator_resolved
variable accelerator_resolved_for
set config [dict get $argd values config]
if {$config ne ""} {
set accelerator_config $config
}
if {$accelerator_resolved_for eq $accelerator_config} {
return $accelerator_resolved
}
set resolved ""
set candidates [list]
switch -exact -- $accelerator_config {
none {}
auto {
if {[info exists ::env(PUNKZIP_EXE)] && $::env(PUNKZIP_EXE) ne ""} {
lappend candidates $::env(PUNKZIP_EXE)
} else {
set exedir [file dirname [info nameofexecutable]]
lappend candidates [file join $exedir punkzip.exe] [file join $exedir punkzip]
}
}
default {
lappend candidates $accelerator_config
}
}
foreach c $candidates {
#file executable is unreliable for some windows setups - existence suffices there
if {[file isfile $c] && ([file executable $c] || $::tcl_platform(platform) eq "windows")} {
set resolved [file normalize $c]
break
}
}
set accelerator_resolved $resolved
set accelerator_resolved_for $accelerator_config
return $resolved
}
punk::args::define {
@id -id ::punk::zip::unzip
@cmd -name punk::zip::unzip\
@ -1124,6 +1205,15 @@ tcl::namespace::eval punk::zip {
naming the reason instead of leaving a half-populated directory. A
member whose path would escape targetdir is refused the same way.
When the punkzip accelerator is available (see punk::zip::accelerator)
and the call is one it serves identically - whole archive, default
-overwrite/-mtime/-verify, ascii member names - the member data is
written by the accelerator instead of the pure-Tcl loop, with mtimes
re-stamped to this module's convention afterwards; preflight, member
selection and the returned names always come from punk::zip's own
reader, and any accelerator failure falls back to pure Tcl silently.
punk::zip::last_unzip_engine records which engine ran.
Returns the list of member names extracted (see -return).
Examples:
@ -1178,6 +1268,11 @@ tcl::namespace::eval punk::zip {
set restoremtime [dict get $argd opts -mtime]
set verify [dict get $argd opts -verify]
variable last_unzip_engine
variable last_accelerator_note
set last_unzip_engine tcl
set last_accelerator_note ""
set arc [Open_archive $zipfile 1]
set chan [dict get $arc chan]
set extracted [list]
@ -1186,6 +1281,7 @@ tcl::namespace::eval punk::zip {
set selected [Select_members [dict get $arc members] $globs $excludes]
#preflight - nothing is written until every selected member is known good
set targets [list]
set names_ascii 1
foreach m $selected {
set reason [Member_unsupported_reason $m]
if {$reason ne ""} {
@ -1195,24 +1291,71 @@ tcl::namespace::eval punk::zip {
if {!$overwrite && !([dict get $m isdirectory]) && [file exists $target]} {
error "punk::zip::unzip: '$target' already exists and -overwrite is 0"
}
if {![string is ascii [dict get $m name]]} {
set names_ascii 0
}
lappend targets $target
}
file mkdir $targetdir
foreach m $selected target $targets {
set name [dict get $m name]
if {[dict get $m isdirectory]} {
file mkdir $target
if {$restoremtime && [dict get $m mtime]} {
lappend dirtimes $target [dict get $m mtime]
}
#G-126 accelerator: hand whole-archive member WRITING to the vendored
#punkzip binary when this call is one it serves identically. punk::zip's
#own parse above stays authoritative for preflight refusals, member
#selection and the returned names; the pure-Tcl loop below is the
#always-available floor and any accelerator failure falls back to it
#silently. Eligibility: whole archive (globs {*}, no excludes), the
#default -overwrite/-mtime/-verify semantics punkzip matches (it always
#overwrites, restores times and crc-verifies), and ascii member names
#(punkzip's name handling is wtf-8; punk::zip decodes cp437/utf-8 flags).
#punkzip stamps mtimes with its tz-free utc convention, so after a
#successful run the members are re-stamped below with this module's
#local-time convention - the two engines produce identical trees.
set accelerated 0
if {$verify && $overwrite && $restoremtime && $names_ascii
&& [llength $excludes] == 0 && [llength $globs] == 1 && [lindex $globs 0] eq "*"} {
set acc [accelerator]
if {$acc eq ""} {
set last_accelerator_note "no accelerator binary resolved (see punk::zip::accelerator)"
} elseif {[catch {exec $acc extract -d $targetdir $zipfile 2>@1} accout]} {
set last_accelerator_note "accelerator '$acc' failed - fell back to pure tcl: [string range $accout 0 300]"
} else {
file mkdir [file dirname $target]
Extract_member $chan $m $target $verify
if {$restoremtime && [dict get $m mtime]} {
catch {file mtime $target [dict get $m mtime]}
set accelerated 1
}
} else {
set last_accelerator_note "call not accelerator-eligible (selective, non-default options, or non-ascii names) - pure tcl"
}
if {$accelerated} {
set last_unzip_engine accelerated
foreach m $selected target $targets {
if {[dict get $m isdirectory]} {
if {[dict get $m mtime]} {
lappend dirtimes $target [dict get $m mtime]
}
} else {
if {[dict get $m mtime]} {
catch {file mtime $target [dict get $m mtime]}
}
}
lappend extracted [dict get $m name]
}
} else {
foreach m $selected target $targets {
set name [dict get $m name]
if {[dict get $m isdirectory]} {
file mkdir $target
if {$restoremtime && [dict get $m mtime]} {
lappend dirtimes $target [dict get $m mtime]
}
} else {
file mkdir [file dirname $target]
Extract_member $chan $m $target $verify
if {$restoremtime && [dict get $m mtime]} {
catch {file mtime $target [dict get $m mtime]}
}
}
lappend extracted $name
}
lappend extracted $name
}
} finally {
close $chan
@ -1689,7 +1832,7 @@ tcl::namespace::eval punk::zip::lib {
package provide punk::zip [tcl::namespace::eval punk::zip {
variable pkg punk::zip
variable version
set version 0.2.0
set version 0.3.0
}]
return

31
src/vfs/_vfscommon.vfs/modules/punkcheck-0.6.0.tm → src/vfs/_vfscommon.vfs/modules/punkcheck-0.6.1.tm

@ -910,14 +910,31 @@ namespace eval punkcheck {
#(the record keys are -ts_begin/-ts_end - passing the raw record gave the constructor's
# -tsbegin/-tsend defaults, so reconstructed events took 'now' as begin and empty end,
# and any later flush/save_installer_record rewrote prior event history with those values)
set eid [punkcheck::dict_getwithdefault $e -id ""]
#self-heal damaged persisted history rather than abort the caller's operation:
#files written by punkcheck < 0.3.2 carry EVENT records whose -id (and
#-source/-targets/-config) hold the LITERAL strings of the old writer's braced
#template ('$eventid' etc - the 0.3.2 buildversion note fixed the writer, but
#files keep the damage) and any two such records collide on the duplicate key
#here. History is advisory - reconstruct the record under a synthesized unique
#id and warn naming the file, instead of failing e.g a whole bake's vfslibs
#phase. Synthesized ids match no INSTALL record's -eventid reference, so
#healed events age out through normal -keep_events pruning.
if {$eid eq "" || $eid in [my events keys]} {
set healed_id "damaged-id-[my events count]-[clock microseconds]"
set shown [string range $eid 0 60]
set why [expr {$eid eq "" ? "missing" : "duplicates an earlier event"}]
puts stderr "punkcheck: WARNING damaged event history in '$o_checkfile': event -id '$shown' $why - keeping record under synthesized id '$healed_id' (safe to ignore; delete the file to reset history)"
set eid $healed_id
}
set eargs [list]
lappend eargs -id [punkcheck::dict_getwithdefault $e -id ""]
lappend eargs -id $eid
lappend eargs -tsbegin [punkcheck::dict_getwithdefault $e -ts_begin ""]
lappend eargs -tsend [punkcheck::dict_getwithdefault $e -ts_end ""]
lappend eargs -types [punkcheck::dict_getwithdefault $e -types {}]
lappend eargs -config [punkcheck::dict_getwithdefault $e -config {}]
set eobj [punkcheck::installevent create [namespace current]::event_[my events count] [self] [dict get $e -source] [dict get $e -targets] {*}$eargs]
$o_events add $eobj [dict get $e -id]
set eobj [punkcheck::installevent create [namespace current]::event_[my events count] [self] [punkcheck::dict_getwithdefault $e -source ""] [punkcheck::dict_getwithdefault $e -targets ""] {*}$eargs]
$o_events add $eobj $eid
}
}
@ -1426,7 +1443,7 @@ namespace eval punkcheck {
#The -changed flag is computed by comparing -value against the matching virtual SOURCE in the last completed
#install record (no filesystem access) - so virtual sources participate in targetset_source_changes like file sources.
#Typical use: recording the resolved build version of a module target, so records identify which product of an
#unchanging source fileset (e.g <module>-0.6.0.tm + <module>-buildversion.txt) the target represents.
#unchanging source fileset (e.g <module>-0.6.1.tm + <module>-buildversion.txt) the target represents.
proc installsource_add_virtual {file_record id value} {
if {![lib::is_file_record_inprogress $file_record]} {
error "installsource_add_virtual error: bad file_record - expected FILEINFO with last body element *-INPROGRESS ($file_record)"
@ -2069,11 +2086,11 @@ namespace eval punkcheck {
#FILEINFO -targets jjjetc-0.1.0.tm -keep_installrecords 2 -keep_skipped 1 -keep_inprogress 2 {
# INSTALL-RECORD -tsiso 2023-09-20T07:30:30 -ts 1695159030266610 -installer punk::mix::cli::build_modules_from_source_to_base -metadata_us 18426 -ts_start_transfer 1695159030285036 -transfer_us 10194 -elapsed_us 28620 {
# SOURCE -type file -path ../src/modules/jjjetc-buildversion.txt -cksum c7c71839c36b3d21c8370fed106192fcd659eca9 -cksum_all_opts {-cksum_content 1 -cksum_meta 0 -cksum_acls 0 -cksum_usetar 0 -cksum_algorithm sha1} -changed 1 -metadata_us 3423
# SOURCE -type file -path ../src/modules/jjjetc-0.6.0.tm -cksum b646fc2ee88cbd068d2e946fe929b7aea96bd39d -cksum_all_opts {-cksum_content 1 -cksum_meta 0 -cksum_acls 0 -cksum_usetar 0 -cksum_algorithm sha1} -changed 1 -metadata_us 3413
# SOURCE -type file -path ../src/modules/jjjetc-0.6.1.tm -cksum b646fc2ee88cbd068d2e946fe929b7aea96bd39d -cksum_all_opts {-cksum_content 1 -cksum_meta 0 -cksum_acls 0 -cksum_usetar 0 -cksum_algorithm sha1} -changed 1 -metadata_us 3413
# }
# INSTALL-SKIPPED -tsiso 2023-09-20T08:14:26 -ts 1695161666087880 -installer punk::mix::cli::build_modules_from_source_to_base -elapsed_us 18914 {
# SOURCE -type file -path ../src/modules/jjjetc-buildversion.txt -cksum c7c71839c36b3d21c8370fed106192fcd659eca9 -cksum_all_opts {-cksum_content 1 -cksum_meta 0 -cksum_acls 0 -cksum_usetar 0 -cksum_algorithm sha1} -changed 0 -metadata_us 3435
# SOURCE -type file -path ../src/modules/jjjetc-0.6.0.tm -cksum b646fc2ee88cbd068d2e946fe929b7aea96bd39d -cksum_all_opts {-cksum_content 1 -cksum_meta 0 -cksum_acls 0 -cksum_usetar 0 -cksum_algorithm sha1} -changed 0 -metadata_us 3338
# SOURCE -type file -path ../src/modules/jjjetc-0.6.1.tm -cksum b646fc2ee88cbd068d2e946fe929b7aea96bd39d -cksum_all_opts {-cksum_content 1 -cksum_meta 0 -cksum_acls 0 -cksum_usetar 0 -cksum_algorithm sha1} -changed 0 -metadata_us 3338
# }
#}
@ -2778,6 +2795,6 @@ namespace eval ::punk::args::register {
package provide punkcheck [namespace eval punkcheck {
set pkg punkcheck
variable version
set version 0.6.0
set version 0.6.1
}]
return
Loading…
Cancel
Save