issues-cli¶
The spex issue / spex remark CLI surface, at its own altitude — argv parsing, console output and exit codes for the issue and remark verbs, above the layer the eval package imports.
raw source¶
These handlers used to live inside issues.ts and localIssues.ts — the modules the eval package imports.
A CLI surface is by definition the topmost layer: it reads argv, prints, and returns an exit code. Hosting
one inside a store/feature module gave those files two altitudes at once, and that is what held the
spec↔eval package cycle in place. The loop-in's candidate resolution needs eval knowledge; its only callers
were these handlers; and from below the eval layer they could not reach it. Every cheap alternative failed on
the same wall — moving a store primitive down, lifting the loop-in, extracting the read projection — because
each moved a LEAF of the ring while the ring was held by a module hosting several heights.
expanded spec¶
issues-cli owns the spex issue and spex remark verb surfaces: flag parsing, the flag-decides-the-parse
discriminators, human-readable output, and exit codes. It owns no store state and no issue semantics — it
calls the read/write verbs that issues.ts and localIssues.ts export, and it renders what they return.
The split is by ALTITUDE, not by domain: the issue domain still belongs to issues and the local store to
local-issues; what moved is the part that talks to a terminal.
Its position is what makes it useful. Sitting above both the store modules and the eval layer, it is a place
where a value composed from both can legally be assembled — which is what the remaining half of the cycle
work needs and what no module below eval could offer. Its own imports of issues.ts are therefore ordinary
STATIC imports; the deferred await import('./issues.js') that localIssues.ts used to carry existed only
because a handler down there had to reach a module that imported it back, and it is gone with the handler.
This module is deliberately NOT merged into cli.ts. That file is the thin dispatch hub (cli-surface),
whose roughly eighty lazy import sites keep a single invocation from loading every verb's implementation;
folding 265 lines of verb bodies in would trade one two-altitude module for another and cost the startup
property that discipline exists to buy. The hub reaches this module the same way it reaches every other verb:
one lazy line.
The argv helpers travel WITH the surface rather than being exported to it. fl, hasFlag, bare,
readBody, repeated and the value-flag set are parsing concerns, so they belong at parsing altitude; two
byte-identical copies of fl existed while the surface was split across two modules, and one copy is what
remains. A helper that both this module and a store module need is a signal to re-examine which of them is
really asking, not a reason to widen a store module's exports.