Phase 1 of converging the command frameworks onto one typed base. Extract
LeafSpec's flag registration, alias/env/default effective-value fallback,
required validation, cross-flag constraint declaration checks + runtime
enforcement, Risk-driven write confirmation (--dry-run/--yes/global-flag
aware via a 3-level bool lookup), toolArgs assembly, and Agent Runtime
Schema projection into a new dispatch-agnostic internal/cmdcore package.
internal/helpers/leaf.go now keeps only the LeafSpec shell (with MCP
dispatch fields) and NewLeafCommand orchestration; LeafFlag/LeafFlagKind/
LeafConstraint/LeafConstraintKind/LeafRisk and their constants become
aliases to cmdcore types, so all 27 devapp call sites compile unchanged.
Dispatch (callMCPTool/OnServer/Call) stays in helpers.
Pure extraction, zero behavior change: catalog is byte-identical
(check-generated-drift ok), the leaf unit + risk/constraint tests pass,
and changed-code coverage is 100% (224 statements across both packages).
Only the leaf framework code is touched; Shortcut delegation is deferred
to Phase 2/3.
No production LeafSpec uses LeafInt64; devapp only needs LeafInt
(non-zero-only putInt semantics). The default MCP dispatch and Server
routing stay — they are the framework's documented main path for
future MCP-direct products.
Post-review cleanup round:
- leaf.go: required validation now matches leafArgs inclusion rules
(LeafInt explicit 0 / LeafInt64 <= 0 count as missing) via
leafHasEffectiveValue; fallback-chain candidates are judged after
TrimSpace when Trim is set so pure-whitespace values fall through.
- command_meta.go: drop catalogStringVal/catalogStringSliceVal in favor
of existing schemaString/schemaStringSlice.
- fetch_mcp_metadata: cross-owned canonicals skip name-coincidence
direct merges; the reviewed cross-server identity is the sole source.
The leaf fallback chain read only string flags, so LeafInt/LeafInt64
flags could never satisfy Required via alias or env, alias values for
integer flags were silently dropped, and a registered Default shadowed
alias/env values. Resolution order is now explicit flag > alias > env >
Default > ArgDefault, aliases register with the primary flag's Kind, and
unparsable integer env values fail loudly.