Changelog
Every release of flagstaff, newest first, from its CHANGELOG.md — what changed and the pull request it came from.
2.0.2
Patch Changes
- #1564
593c0b4Thanks @ofri-peretz! - Measures withlinegauge/v8, string-width 8.3.0's rules, which every incumbent these packages replace still resolves. Nothing a box, table, spinner, prompt, ink screen or help page draws changes:linegauge's root moved to string-width 9.0.0, and these stay on the measurement theirwrapandslicecut by. - Updated dependencies [
593c0b4]:- linegauge@2.2.0
2.0.1
Patch Changes
-
#1548
f190400Thanks @ofri-peretz! - The weight comparisons are restated as each incumbent resolves today, with ansi-regex 6.6.0:- ora 10.0.0 is 129,073 B across 17 packages, and
flagstaff/orais 41% of it; - log-update 8.0.0 is 115,186 B;
- boxen 9.0.0 is 116,671 B.
- ora 10.0.0 is 129,073 B across 17 packages, and
-
Updated dependencies [
f190400]:- linegauge@2.1.0
2.0.0
Major Changes
- #1491
5054fb7Thanks @ofri-peretz! - Requires Node 22.13 or later; Node 18 and 20 are end-of-life.engines.nodeis now>=22.13.0(was^20.19.0 || >=22.13.0), and Node 22.13, 24 and 26 are the versions tested.burgee migratenow warns when a project'sengines.nodeadmits a Node below 22.13.0, and its suggested fix isnpm pkg set "engines.node=>=22.13.0".
Patch Changes
- Updated dependencies [
fca94b2,5054fb7]:- linegauge@2.0.0
- closeout@2.0.0
- paratext@2.0.0
- roundel@2.0.0
1.8.2
Patch Changes
- #1483
3e69fb2Thanks @ofri-peretz! - The package manifest names its author and publishes withpublishConfig{ "access": "public", "provenance": true }. burgee'shomepageis its landing page, https://burgee.interlace.tools. oxmutate gainskeywords, so npm search finds it, and asideEffectslist (its CLI, its worker and its Vitest runner run on load), so a bundler can drop the rest. No code changes. - Updated dependencies [
3e69fb2]:- closeout@1.1.10
- linegauge@1.2.1
- paratext@1.0.13
- roundel@1.3.2
1.8.1
Patch Changes
-
#1472
99fefcfThanks @ofri-peretz! - Three fixes.- A plugin key named like an
Object.prototypemember is checked like any other. The schema walker readproperties.toStringandproperties.constructoroff the prototype, as a schema that admits anything, so{ name: 'x', toString: 1 }passed an object that allows no other keys. A required key is now present only when the object has it, or inherits it from a prototype of its own (a component written as a class still keepsstaticthere) —{}no longer satisfiesrequired: ['constructor']. markdownreads a line that opens with a code span as a paragraph, not a fence.```x``` is codeopened a code block that swallowed the rest of the reply. A backtick fence's info string holds no backtick (CommonMark), so it is now a paragraph with the code span drawn; a tilde fence still takes any info string.markdowndrops a heading's closing run of#s when it draws it.# Title #was drawn asTitle #; it is nowTitle, as CommonMark has it. A#with text against it (# C#,# a #b) is still text.
- A plugin key named like an
-
Updated dependencies [
99fefcf,99fefcf]:- paratext@1.0.12
- roundel@1.3.1
1.8.0
Minor Changes
- #1411
e500294Thanks @ofri-peretz! -flagstaff/orafollows ora 10.0.0, graded 223 / 223 by ora 10's own suite (control 223 / 223). The frame is laid out the way a terminal shows it — a tab to its stop, a wide character that does not fit moved to the next row, a carriage return back to the start of the row — and kept above the last row of the screen, with a truncation message that shortens to fit. A resize never raises the number of rows erased, a line another writer left unfinished pauses rendering until its newline (there is no 200 ms timeout any more), and a timer, drain or external-write render whose affix function or stream throws stops the spinner instead of crashing the process.{ isEnabled: false }logs a line on every.start(), a symbol is written plain on a stream that cannot render colour, an unknown spinner name throws on every terminal, andoraPromise()keeps the action's own error or result whenfailText,successTextor the final write throws. The weight comparisons are restated as each incumbent resolves today: ora 10.0.0 at 128,182 B across 17 packages, log-update 8.0.0 at 114,295 B and boxen 9.0.0 at 115,780 B.
Patch Changes
- Updated dependencies [
e500294]:- linegauge@1.2.0
1.7.5
Patch Changes
- #1274
8c9c088Thanks @ofri-peretz! - The README's first paragraph no longer names burgee: flagstaff leads with its own problem and its own incumbents, as every layer does (cli-output-stackR12). The dependency statement stays in the third paragraph and the badge — four dependencies, all from this repository, none outside it.
1.7.4
Patch Changes
-
#1258
e3b3a41Thanks @ofri-peretz! -checkreads a.jsonplugin file as data. It handed every file toimport(), and Node refuses a.jsonmodule without an import attribute (ERR_IMPORT_ATTRIBUTE_MISSING), so a plugin written as JSON got Node's message and no verdict, from the host's owncheckand throughburgee check, which runs it. -
#1266
02e6f9fThanks @ofri-peretz! - The family plugin schema (schema.json, identical in every plugin host) now describesformats, burgee's output-format key. This package reads nothing new, and a plugin carryingformatsregisters here as before. -
#1252
efc994eThanks @ofri-peretz! - Every benchmark figure in the README, a ratio, a byte count or a cold-start time, now links to the benchmarks page where it is measured. -
Updated dependencies [
e3b3a41,02e6f9f,efc994e,efc994e]:- closeout@1.1.8
- linegauge@1.1.5
- paratext@1.0.11
- roundel@1.2.1
1.7.3
Patch Changes
- #1186
af24328Thanks @ofri-peretz! - Published declarations now keep each doc comment's first paragraph, its code examples and its@param,@returns,@throws,@example,@deprecated,@defaultand@seetags, and drop the longer design notes below them, so the tarballs are smaller (burgee by 5.7% gzipped, bellpull and closeout by about a fifth). Types are unchanged, and hover text in an editor keeps its summary.burgee's README also namesburgee/program-schema.json, the JSON Schema every--schemadocument validates against. - Updated dependencies [
af24328,122635d]:- closeout@1.1.6
- linegauge@1.1.4
- paratext@1.0.10
- roundel@1.2.0
1.7.2
Patch Changes
- #1160
0b381a0Thanks @ofri-peretz! - Export./package.json.require('<package>/package.json')threwERR_PACKAGE_PATH_NOT_EXPORTED, which broke tools that read a dependency's manifest that way: bundlers, license scanners and version checks. - Updated dependencies [
0b381a0]:- closeout@1.1.5
- linegauge@1.1.3
- paratext@1.0.9
- roundel@1.1.3
1.7.1
Patch Changes
- #1130
c05c86eThanks @ofri-peretz! - Every drop-in subpath now type-checks undermoduleResolution: node10, and undermodule: commonjswith no resolution set, which is TypeScript's default there.import … from 'burgee/commander'used to fail with TS2307 in such a project, althoughrequire()of the same specifier worked. Each package now declarestypesand atypesVersionsmap, derived fromexports, with one key per typed subpath pointing at the fileexportsalready names.exportsis unchanged, sonode16,nodenextandbundlerread exactly what they read before.controlroom/ink's declarations no longer name the untypedreact-reconciler, which was TS7016 for consumers withskipLibCheck: false. - Updated dependencies [
c05c86e]:- closeout@1.1.4
- linegauge@1.1.2
- paratext@1.0.8
- roundel@1.1.2
1.7.0
Minor Changes
- #1095
98a0004Thanks @ofri-peretz! - A live frame never outgrows the terminal.frameWriterreads the writer'srowsat every paint and clips a frame taller than the screen to its tail under one dim… N moreline, so a repaint never climbs above the top row and leaves lines it cannot erase.releasewrites the clipped frame whole, so nothing it held is lost, and a change of height repaints from the top. A writer withoutrows(a pipe) is never clipped, and the static projection is untouched.Writergains an optionalrows.
1.6.0
Minor Changes
- #1072
582bc15Thanks @ofri-peretz! -flagstaff/progressreports to an MCP client instead of drawing. Inside a burgee--mcptool call whose client sent_meta.progressToken, the bar sends each count asnotifications/progress, with its static line (12/30 files · 40%) as the message, and draws nothing into the tool result. Anywhere else it draws as before. The bridge is on theflagstaff/progresssubpath only:progressfrom the rootflagstaffentry always draws, so a program that never serves MCP does not pay for it.
Patch Changes
- Updated dependencies [
4a62884]:- paratext@1.0.7
1.5.0
Minor Changes
- #1058
31a38e7Thanks @ofri-peretz! - Atable()column can say what happens past its width:columns: [{ overflow: 'truncate' }]cuts a cell to one row ending in…, by display width throughlinegauge/truncate, with a link kept around the text that survives.'wrap', the default, is the behaviour tables have always had.tableComponent()'s static projection prints every cell whole whatevercolumnssays.
Patch Changes
- #1046
1797388Thanks @ofri-peretz! - Twooraspinners on one stream, stopped in the order they started, leavewriteas they found it. The second used to restore the first's wrapper as its "original", so a stopped spinner stayed hooked into every later write and cleared lines it no longer owned. - Updated dependencies [
1797388]:- closeout@1.1.3
1.4.0
Minor Changes
- #1054
b45f141Thanks @ofri-peretz! -table()takescolumns, per-columnminandmaxcontent widths, positional likealign. A column withmaxnever grows past it; a column withminis not narrowed below it while another column can give way, and when the mins add up pastwidththe table is drawn wider rather than break them. Bounds that cannot hold (min > max, negative, fractional,maxbelow 1) throw aTypeErrornaming the column. A table withoutcolumnsdraws exactly as before, and the static projection is unchanged.
Patch Changes
- #1045
c4fd9a3Thanks @ofri-peretz! - The family plugin schema (schema.json, identical in every plugin host) now describeslocales, burgee's locale-pack key. A plugin carryinglocalesvalidates against the shared schema as it does againstburgee/locale-pack-schema.json, which lists every message id. This package reads nothing new, and a plugin carryinglocalesregisters here as before. - Updated dependencies [
c4fd9a3]:- closeout@1.1.2
- linegauge@1.1.1
- paratext@1.0.6
- roundel@1.1.1
1.3.0
Minor Changes
- #1014
65afee5Thanks @ofri-peretz! - A quiet runtime. roundel'sRuntimegains an optionalquietfield, and flagstaff draws nothing when it istrue: no spinner, no progress, no status line, and the frame clock never armed. Data and errors stay the caller's to print and are never quieted. burgee's global--quietsets it.
Patch Changes
-
#1036
1357061Thanks @ofri-peretz! - The plugin host's JSON Schema walker reads a node's own keywords beside itsanyOf: a branch that admits the value no longer excuses a siblingrequiredorproperties. flagstaff's own plugin schema uses noanyOf, so no plugin is accepted or refused differently. -
#1031
45a70beThanks @ofri-peretz! - The JSON Schema walker the plugin host validates with reads four more keywords:anyOf,enum, a list of types, and a$refinto draft-07definitions. flagstaff's own plugin schema uses none of them, so no plugin is accepted or refused differently. burgee's tests use them to validate every message its--mcpserver writes against the MCP 2025-06-18 schema. -
#1011
1968eb4Thanks @ofri-peretz! - The README quick start runs as written. On npm it was broken for flagstaff (rtundefined) and linegauge (styledundefined), controlroom's imported flagstaff without installing it, and paratext's printed nothing. No code changed;readme-quick-start-locknow runs every package's quick start. -
#1022
ecb0a00Thanks @ofri-peretz! - The tarball no longer carries declaration files that noexportsentry reaches. TypeScript could never open them, because a deep import is refused byexports. Every entry's types are unchanged. The ten packages drop 71 files and 118,312 bytes between them, burgee 35 files and 76,504 bytes, which takes its tarball from 251,814 to 225,278 bytes gzipped. -
Updated dependencies [
bfe4ab8,1968eb4,65afee5,bcc438a,ecb0a00]:- linegauge@1.1.0
- paratext@1.0.5
- roundel@1.1.0
- closeout@1.1.1
1.2.5
Patch Changes
- #938
9babb6dThanks @ofri-peretz! - npm description and README: the description says what the package does, then its dependency fact in one of two wordings ("Zero dependencies." or "No dependency outside the burgee family."), then its drop-in paths. The README's family section states how the family is built — the leaves, one-way dependencies, nothing from outside the family, trusted publishing with provenance — and its table column is "Migrates from". No API, compatibility grade or benchmark changes. - Updated dependencies [
9babb6d]:- closeout@1.0.4
- linegauge@1.0.8
- paratext@1.0.4
- roundel@1.0.4
1.2.4
Patch Changes
- #917
735f0f6Thanks @ofri-peretz! - README: the opening paragraph says what the package does first. The drop-in path follows it as one line, naming the incumbent andnpx burgee migrate, and every compatibility row and benchmark is unchanged. - Updated dependencies [
735f0f6]:- closeout@1.0.3
- linegauge@1.0.7
- paratext@1.0.3
- roundel@1.0.3
1.2.3
Patch Changes
- #897
f29f159Thanks @ofri-peretz! - controlroom has its own docs site at https://controlroom.interlace.tools: its README's Docs line, itshomepage, and every family table now link there. - Updated dependencies [
f29f159]:- closeout@1.0.2
- linegauge@1.0.6
- paratext@1.0.2
- roundel@1.0.2
1.2.2
Patch Changes
-
#848
6ae533eThanks @ofri-peretz! - The familyschema.jsondescribes what five values look like.contractis1, and burgee refuses a plugin that declares none. A caique widget'sstatic(spec)gets{ kind, message, ...sample.done }. A seniorityranksits between the built-in layers at flag 0, environment 10, config file 20,package.json30 and default 40. A burgee hook'sfilteris{ command: RegExp }, now withcommandrequired, so the schema and the host refuse the same filters. -
#857
d80b2d0Thanks @ofri-peretz! - The familyschema.jsoncloses a bellpull resolver'swhenwithadditionalProperties: false, so the schema and bellpull's own validation refuse the same unknown keys. -
#854
fd8e659Thanks @ofri-peretz! -flagstaff/boxendraws a box about 40% faster: text with no escape, tab or backspace skips the control-character walk, and a border bar of ASCII or box-drawing characters is cut by index instead of walked. Output is unchanged; boxen 9.0.0's own suite still passes 213 / 213. -
Updated dependencies [
6ae533e,d80b2d0]:- closeout@1.0.1
- linegauge@1.0.5
- paratext@1.0.1
- roundel@1.0.1
1.2.1
Patch Changes
- Updated dependencies [
1945d65,1945d65,9ebef65,1945d65]:- closeout@1.0.0
- paratext@1.0.0
- roundel@1.0.0
1.2.0
Minor Changes
- #827
cd34546Thanks @ofri-peretz! -flagstaff/boxenis boxen 9.0.0's API, graded 213 / 213 by boxen 9's own suite (control 213 / 213). New options:footerandfooterAlignment,titleColor,borderBackgroundColor,maxWidth; a tab, a backspace or a cursor move inside the text, a label or a border is written the way a terminal would draw it; a border side may be wider than one column or empty; and a size or spacing that is not a usable number means its default. Two of boxen 8's answers change with boxen 9: a hex colour must be real hex (#GGGnow throws, as it does in boxen 9), andvertical/horizontalare a fallback for the sides rather than an override of them.
Patch Changes
- #824
4be8d59Thanks @ofri-peretz! - The README states ora's current tree, 114,102 B (it was 113,577 B on 2026-09-09);flagstaff/orais still 49% of it.
1.1.1
Patch Changes
- #816
5230016Thanks @ofri-peretz! - controlroom hosts plugins (R10):keymapsandpanesregister throughcontrolroom/plugin'sregister()against the family schema, a screen takes either by name, andcontrolroom check <plugin-file>reports what a plugin contributes. The family schema every host ships gains thekeymapsandpanesdefinitions. - Updated dependencies [
5230016,5230016,5230016]:- closeout@0.7.0
- paratext@0.9.0
- linegauge@1.0.4
- roundel@0.6.3
1.1.0
Minor Changes
-
#806
f30e011Thanks @ofri-peretz! - Newflagstaff/markdown: a reply streamed as tokens arrive, committed a block at a time (headings, lists, emphasis, inline code, fenced code); off a terminal it prints the markdown's own source, each block once. Newflagstaff/diff: a unified diff with old and new line numbers on a terminal, and the diff unchanged everywhere else. -
#806
f30e011Thanks @ofri-peretz! -frameWriter()fromflagstaff/loop: paint a whole frame and only the changed rows are written, in one synchronized-output block.hoistrepaints through it, so a terminal frame no longer redraws unchanged text. Newflagstaff/log-tail(the last lines of a stream,┊and◆, a static projection that appends) andflagstaff/tab-bar(the active tab's label off a terminal), each registered throughregister(). The task list's pending mark is the replaceablependingglyph.
1.0.3
Patch Changes
1.0.2
Patch Changes
-
#763
6c2e9c5Thanks @ofri-peretz! - Faster, and lighter:link()fromparatextreads the process once, on its first call, where it used to rebuild the runtime and re-read the environment on every call.paratext/terminal-linkdecides hyperlink support once per stream, assupports-hyperlinksdoes at import, and emits a link as a single concatenation.- Templates are parsed once, and
eraseLineskeeps the strings for the counts a redraw uses. - In B5 (ours ÷ incumbent, in-process),
paratextagainst ansi-escapes went from 8.9× to 0.97× locally, andparatext/terminal-linkagainst terminal-link from 20.9× to 0.78×. - The root bundle is 1,356 B smaller (8,417 → 7,061), because the plugin-schema fragments paratext and flagstaff import to validate no longer carry the schema's prose. The published
schema.jsonis unchanged.
-
Updated dependencies [
6c2e9c5,6c2e9c5]:- linegauge@1.0.1
- paratext@0.7.5
1.0.1
Patch Changes
- Updated dependencies [
a115799]:- roundel@0.6.0
1.0.0
Major Changes
- #685
6ef8227Thanks @ofri-peretz! - flagstaff 1.0.0. No API changes from 0.4: this release makes a promise. Every published entry point is now under semver and can change incompatibly only in a new major:flagstaffandflagstaff/loop,plugin,import,spinner,progress,tasks,boxandtable, the four drop-in subpaths, theschema.jsonplugin contract and theflagstaffbin. Each drop-in path is graded at 100% by its incumbent's own test suite, vendored at the release tag and run unmodified: ora 9.4.1 by 99 of 99 cases (flagstaff/ora), log-update 8.0.0 by 99 of 99 (flagstaff/log-update), boxen 8.0.1 by 84 of 84 (flagstaff/boxen) and cli-table3 0.6.5 by 29 of 29 (flagstaff/cli-table3). Out of scope:flagstaff/boxenis a boxen 8 drop-in. boxen 9 is released but is not graded or claimed, and a program on it is left alone byburgee migrate. Earlier majors of the four incumbents are not claimed either.
Patch Changes
-
#680
7f59bc2Thanks @ofri-peretz! - Raw mode is paired with its undo throughcloseout/cursor'srawMode, the way the cursor already was.caique/raw: a list prompt on a stream that was already in raw mode — a prompt library's, or the program's own — no longer switches raw mode off when it ends; it used to callsetRawMode(false)unconditionally and take the keyboard from its owner. Raw mode the prompt did turn on is now turned off onSIGINTandSIGTERMtoo, not only in the prompt's ownfinally.KeyStreamgains an optionalisRaw.flagstaff/ora: stdin-discarder's raw mode goes through the same pairing. Behaviour is unchanged except that an already-raw stdin is no longer written to at all.
-
#711
d26728bThanks @ofri-peretz! - Code no test could reach is gone, and nothing a caller can observe changes.table(): the column-shrinking loop no longer checks for a column already at the three-cell minimum —table()never offers less than that per column, so while the table is too wide its widest column is always wider than the minimum. The widths are found withMath.max/indexOfinstead of an indexed loop with?? 0fallbacks that could not fire. Ties still go to the leftmost column.flagstaff/tableis 342 B lighter.- The terminal projection no longer keeps a placeholder cursor net for a
close()without anopen(), or for a secondclose():hoist()opens first and lowers at most once, so neither can happen.
-
#685
6ef8227Thanks @ofri-peretz! - Fixed:hoist()on a terminal left stale rows behind when a frame was wider than the terminal. The tty projection counted the rows it had painted as lines of text, so a line that wrapped onto the next row was erased as one and the rows it wrapped onto stayed on screen under every repaint. It now counts painted rows withlinegauge'slineCountat the writer'scolumns(80 when the writer does not say), the measurementflagstaff/oraalready clears by.Writergains an optionalcolumns, whichprocess.stdoutalready carries. -
#665
12fea8eThanks @ofri-peretz! - Three defects carried over from the incumbents, and three places where a port answered differently from the incumbent on a bad value.burgee/yargs/parser: withunknown-options-as-args, every--prefixed argument ran through five flag regexes, and two of them backtracked — one quadratically, one cubically (a 4,000-character argument took ten seconds). They are linear scans now, and give the same answer as the regexes for every input, checked against them over every short string of the characters involved. yargs' own suite still passes 804 of 804.burgee/yargs/parser:{ "a": null }in one config anda.bfrom a default or a second config threw "Cannot read properties of null". Anullparent is now an absent one, as the parser's own key lookup already treated it.burgee/yargs:showHelp()with an async default-command builder that rejected left an unhandled rejection that ended the process. The rejection now goes tofail, where yargs sends a command handler's rejection, so a.fail()handler receives it.burgee/meow:importMeta: nullthrows meow's own "TheimportMetaoption is required" TypeError instead of a null dereference, andinput: nullor an array is refused as meow refuses it.flagstaff/cli-table3: a style name that cannot be read off a colour function (caller,arguments) draws the cell plain, as cli-table3 does, instead of throwing out oftoString().
-
#674
e9f45d8Thanks @ofri-peretz! - README: family header, badges, install, migrating, the family table.Every package README now opens the same way — lockup, tagline, one badge row in one order (npm version, downloads, Quality Gate, the package's own coverage, OpenSSF Scorecard, unpacked size, dependencies, types, Node, licence, npm provenance), a row of compatibility badges read from the graded baseline — and carries the same sections in the same order: Install for npm, pnpm, yarn and bun, Quick start, Migrating as a before/after diff, Compatibility, Benchmarks, For agents, API, and a generated table of the nine packages. Links are absolute, so they work on npm as well as GitHub.
-
#684
6c7b55aThanks @ofri-peretz! -paratext/csi: the CSI half ofansi-escapesas a subpath of its own — cursor moves, erases, scrolling, the alternate screen and synchronized output, byte-exact withansi-escapes7.3.0. It is 2,700 bytes and, unlike the package root, registers no built-ins when imported.flagstaff/log-update,flagstaff/ora,caique/rawandcaique/inquirertake their cursor sequences from it instead of carrying their own copies; caique now depends on paratext. Output is unchanged, with one spelling difference:caique/raw's repaint clears withESC[Jrather than the equivalentESC[0J.caique/inquirerkeeps@inquirer/ansi's answer of nothing for a zero-row move, whereansi-escapes'cursorUp(0)isESC[0A. -
#678
088ceccThanks @ofri-peretz! - Whether anybody is there, whether to colour, and whether a tick can be drawn are roundel's questions, and three packages answered them by hand.roundel/terminal(new subpath, 878 B, reaching nothing):interactive(rt)— a terminal on stdin, noCI, and no agent variable (CLAUDECODE,AI_AGENT,CURSOR_AGENT,CODEX_THREAD_ID,GEMINI_CLI, exported asAGENTS), withFORCE_TTY=1as the override — andunicode(rt), is-unicode-supported 2.1.0's table over{ env, platform }.caique/decidenow depends onroundeland asksinteractive(). Behaviour change: under an agent that has a terminal —CLAUDECODE=1and a TTY on stdin — a missing required value is refused with a usage error naming the flag (--x is required when nobody is there to answer) instead of prompting and hanging the agent.FORCE_TTY=1now prompts even without a terminal on stdin, as it does for burgee.caique/inquirer's tick andflagstaff/ora's log symbols and spinner fallback use roundel'sunicode(). caique's copy was a four-condition subset: the Linux console (TERM=linux) now gets√rather than✔, and ConEmu/Cmder, Terminus, Alacritty, rxvt-unicode and JetBrains' terminal on Windows now get✔, asfiguresdraws them.burgeehelp colour is roundel'scolorLevel(rt) > 0. Behaviour changes:NO_COLORnow beatsFORCE_COLOR;--no-colorand--color=…on the command line are honoured;CLI_ACCESSIBLEturns help colour off; and a terminal that sets noTERM(Windows' conhost) gets plain help unlessFORCE_COLOR,--colororCOLORTERMasks for colour.burgee/contrastrounds with roundel'sround2; no output changes.paratext: the supports-color fork behindparatext/terminal-linkis unchanged, and now held to roundel's policy by a parity test everywhere their two incumbents agree.
-
Updated dependencies [
6d8aadf,ff4159d,5e635b0,ff4159d,6ef8227,7c77cd2,6ef8227,6ef8227,e9f45d8,8a338ba,6c7b55a,620fc74,088cecc,4319563]:- closeout@0.6.0
- linegauge@1.0.0
- paratext@0.7.3
- roundel@0.5.5
0.4.4
Patch Changes
-
#627
4a629a9Thanks @ofri-peretz! - Lint with every published Interlace ESLint plugin, and fix what the upgrade surfaced.- caique: the inquirer theme merge skips
__proto__,constructorandprototypekeys, so a theme object cannot swap the merged object's prototype. - burgee: last-element reads use
.at(-1). - burgee, closeout, flagstaff, roundel: helpers that capture nothing from their enclosing function move to module scope.
- seniority: suppression comments name the
no-dynamic-requirerule that now reports the config loader's dynamicrequire.
No public API or output changes.
- caique: the inquirer theme merge skips
-
Updated dependencies [
4a629a9]:- closeout@0.5.4
- roundel@0.5.4
0.4.3
Patch Changes
- #604
0e7b1e8Thanks @ofri-peretz! - Each README links to its migration guides under the docs link: "Migrating from: chalk", "ora · log-update · boxen · cli-table3", and so on. That puts a path from the npm page to the guide for the library you are replacing. No code changes. - Updated dependencies [
0e7b1e8]:- roundel@0.5.3
- linegauge@0.5.4
- closeout@0.5.3
- paratext@0.7.2
0.4.2
Patch Changes
-
#474
1955419Thanks @ofri-peretz! - burgee plugins can hook two more stages.parseruns before the command is resolved: it receives argv and may return a replacement, which is how an alias plugin mapsdtodeploy.shutdownruns once as the program exits, whether the command succeeded or failed. The familyschema.jsonshipped in every package now describes both stages. -
#522
f4be6a8Thanks @ofri-peretz! -require('bellpull/cross-spawn'),require('flagstaff/cli-table3'),require('burgee/yargs'),require('seniority/dotenv')andrequire('seniority/rc')now return what the incumbent'srequire()does — the function, the class, the factory, the object — instead of an ES module namespace. Each exports its default as'module.exports', which is what Node hands a CommonJS caller, and which yargs' own entry already does.const spawn = require('…'); spawn(…)threw before. -
#519
77ff1cbThanks @ofri-peretz! - The drop-ins now export their incumbents' type names, so a TypeScript program migrates by its import alone:roundel/chalkgains chalk'sColor,ForegroundColor,BackgroundColor,ModifiersandOptions;flagstaff/oragainsSpinner,PrefixTextGeneratorandSuffixTextGenerator;flagstaff/boxengainsOptions,CustomBorderStyleandBoxes;flagstaff/log-update,linegauge,linegauge/wrapandcloseout/exit-hookgainOptions;burgee/yargs/parsergainsArguments,OptionsandConfiguration. Types only — no runtime bytes. -
Updated dependencies [
866b972,1955419,1b002e0,77ff1cb,dc1b1a7,0592441]:- paratext@0.7.0
- closeout@0.5.2
- linegauge@0.5.2
- roundel@0.5.2
0.4.1
Patch Changes
- #508
1aae1e2Thanks @ofri-peretz! -<package> --helpand--versionanswer instead of crashing. The bin took its first argument as the plugin file to import, soroundel --helpfailed withCannot find module '…/--help'and exit 1.-h/--helpnow print usage and exit 0,-V/--versionprint the version and exit 0, and any other flag where the plugin file belongs is a usage error, exit 2. - Updated dependencies [
1aae1e2]:- closeout@0.5.1
- linegauge@0.5.1
- paratext@0.6.1
- roundel@0.5.1
0.4.0
Minor Changes
- #507
b8e97dcThanks @ofri-peretz! - Runs on Node 20 and 22, not just 24+:engines.nodeis now^20.19.0 || >=22.13.0. Those are the first releases whererequire(esm)loads without a warning, so the CommonJSrequire()path keeps working. Every package's test suite runs on exactly 20.19.0 and 22.13.0, on Linux, macOS and Windows. caique's prompts no longer callPromise.withResolvers, which Node 20 doesn't have.
Patch Changes
- Updated dependencies [
9800b43,b8e97dc]:- closeout@0.5.0
- linegauge@0.5.0
- paratext@0.6.0
- roundel@0.5.0
0.3.7
Patch Changes
- #494
f7f6d4bThanks @ofri-peretz! - Each package'shomepageand README docs link now point at its own documentation site,https://<package>.interlace.tools, instead of a page on burgee's site. The oldburgee.interlace.tools/docs/packages/<package>URLs answer with a 301 to the new host, so nothing already linked breaks. closeout's README override example also resolves to the current release again (npm:closeout@^0.4; the 0.4.0 release left it at^0.3). - Updated dependencies [
f7f6d4b]:- roundel@0.4.3
- linegauge@0.4.4
- closeout@0.4.1
- paratext@0.5.4
0.3.6
Patch Changes
0.3.5
Patch Changes
-
#454
b4584e7Thanks @ofri-peretz! - Every package's npmhomepagenow points at its page on the docs site,https://burgee.interlace.tools/docs/packages/<name>, and each README links it under the header. The keywords add what people and models search for:burgeegainscli-framework,argument-parser,subcommands,json-schema,mcp-server,model-context-protocol,ai-agent,llm,shell-completion,typescript,zero-dependency,commander-alternativeandyargs-alternative; the other eight gainagent,ai-agent,non-tty,jsonandzero-dependencywhere the package does that —zero-dependencyonly on the six that install nothing at all.burgee's README gains a short FAQ (commander alternative, agent use, MCP, dependencies) and states the compatibility counts the oracle holds — 1,360 / 1,360 of commander's tests and 804 / 804 of yargs' — where it had said 1,215 and 1,185.caique's README no longer calls a released package pre-release. -
#442
bdaf364Thanks @ofri-peretz! - Every package now listsplugin,pluginsandextensiblein its npm keywords, because every package takes plugins through one shared contract.A plugin is a plain object, validated against the
schema.jsonthat ships in every package, and checked with the package's owncheckcommand. Each package reads its own key and ignores the rest, so one object can extend any subset of the family. The plugins page has a nine-layer example that every package'scheckaccepts in CI. -
#435
7888524Thanks @ofri-peretz! -schema.jsonnow describes every plugin host in the family.The one schema each package ships as its plugin contract used to cover only four hosts: roundel's
tokens, flagstaff'sglyphs,spinners,bordersandcomponents, paratext'scapabilities, and linegauge'swidths. Five hosts validated their keys in their own code, but the file an author (or a model) writes against said nothing about them. It now describes all of them:- bellpull
resolvers, including the absolute-path rule onpaths - caique
widgets - closeout
handlers, including the phases a plugin may use - seniority
sources, including the rank bounds - burgee
commands,hooksandenforce
Where the schema can express a rule, it gives the same verdict as the host's own validator, and a test holds the two together. Function-valued fields (
static,run,read,handler) are described and required, but not typed, because JSON Schema can't say "function".flagstaff now validates a plugin against only its own keys, not the whole family schema. It no longer refuses a plugin over another host's key, which lets one plugin object contribute to several hosts. Its entry points are also 4.7–5.9 KB lighter for it.
- bellpull
-
#445
dac303eThanks @ofri-peretz! - Every package now declaressideEffectstruthfully, so bundlers can drop what you don't import.Six packages declared nothing, so no bundler could drop any of their modules. A named import from the root now bundles to the same bytes as the same import from its subpath:
import before after import { explain } from 'seniority'2,939 B 1,067 B import { decide } from 'caique'1,235 B 734 B import { strip } from 'linegauge'1,102 B 940 B import { once } from 'closeout'353 B 235 B flagstaff and roundel used to declare
false, but each ships acheckcommand whose file runs when loaded. Each now lists that file, which is the true statement. paratext also lists the two modules that register its built-in capabilities when they load. -
#457
44edb2fThanks @ofri-peretz! - flagstaff's npm description no longer says "Zero dependencies" (it takes four, all in-family); caique's README badge names both of its dependencies. -
Updated dependencies [
b4584e7,bdaf364,7888524,dac303e]:- closeout@0.3.1
- linegauge@0.4.1
- paratext@0.5.1
- roundel@0.4.1
0.3.4
Patch Changes
-
#430
4d1b2b3Thanks @ofri-peretz! -checknow reports every refusal with its code and its fix, wherever it was raised.Some plugin files register themselves on import: they call
register()at the top of the module and export the result. Until now, when such a file was refused, the error was thrown insidecheck'simport(), before the onlytrythat turns aPluginErrorintoE_PLUGIN_SCHEMA: …plus afix:line. The author got the bare message on stderr, with no code and no fix. Now the whole ofcheckruns inside that one handler, so every refusal comes out the same way on every host. -
#421
db3c59eThanks @ofri-peretz! - linegauge hosts plugins —widths, and it is the ninth of nine.scripts/extension-surface-lock.test.tshas carriedlinegauge: { plugin: false }since it was written, and the row was empty honestly: a width function is not obviously extensible, and an extension point invented to fill a table is worse than a gap that says so.What makes
widthsreal is that the package already admits the problem.width.tssays ambiguous-width characters are "counted narrow, which is what a terminal does unless it has been told it is rendering an East Asian locale" — and that covers only the ambiguity Unicode sanctions. A Nerd Font putting a two-column icon in the Private Use Area, a code point added by a Unicode release newer than the table compiled into this build, a font drawing U+2500 wide: each is a real, local disagreement with the built-in answer, and until now a user had no way to settle it short of patching the package.export default { name: "nerd-font", widths: { icons: { ranges: [[0xe000, 0xf8ff]], columns: 2, why: "Nerd Font patches two-column icons into the PUA; measured in WezTerm", }, }, };Three fields of plain data, so a plugin can arrive as JSON, be diffed, be generated and be printed without running its author's code (R7).
whyis required, which no other$defin the family does: a width table with no provenance cannot be audited when it turns out to be wrong, and wrong is the normal outcome for ambiguous width.A later registration wins over an earlier one and over the built-in tables, which is the point — the built-in answer is right for most terminals and the user is the authority on theirs. An override applies before the zero-width and emoji rules, or it would be decorative. A program with no plugin pays one
length === 0per cluster, and the ASCII fast path never reaches it.The family schema gains
widthRange,widthOverrideandwidths, and because it is one byte-identical file across every host, every host that validates against it grows by about 1.3 KB — five flagstaff budgets and two paratext ones moved for a definition only linegauge reads. That trade is the design's and is recorded as D-108 rather than absorbed. -
Updated dependencies [
4d1b2b3,db3c59e,db3c59e]:- closeout@0.3.0
- linegauge@0.4.0
- paratext@0.5.0
- roundel@0.4.0
0.3.3
Patch Changes
-
#404
c70ff9cThanks @ofri-peretz! -flagstaff/cli-table3'sCellcarriesColSpanCellandRowSpanCell, the way cli-table3's ownsrc/cell.jspublishes them —module.exports = Cell; module.exports.ColSpanCell = …; module.exports.RowSpanCell = …. A caller who reachesCell.RowSpanCellon the incumbent now reaches it here. Both names were already named exports of the module; this is a second spelling of the incumbent's shape, and nothing new is published.With it, cli-table3's internal suite reads 103 / 104 against a control of 103 / 104 — the target matches the reference exactly, up from 90.
0.3.2
Patch Changes
-
#398
ee35904Thanks @ofri-peretz! - A__proto__key in a caller's corpus stays a style.fromCliSpinnersandfromCliBoxesbuilt their maps by assigningmap[key] = valueover the caller's JSON. JSON can carry the key__proto__, and that assignment hands it to the prototype setter rather than defining a property: the entry vanished from the plugin and whatever it held became the fallback that every otherlookupSpinnerandlookupBorderinherited. Both now build withObject.fromEntries, which defines an own property for every key, and the returned map keepsObject.prototype.The registry's
deepFrozencopy and caique's prompt binding write the same shape from a loop they cannot turn into an expression, and useObject.definePropertyinstead.flagstaff/importis 80 bytes lighter for it — 838 B to 758 B — because two loops became two expressions.
0.3.1
Patch Changes
-
#375
98ac9a3Thanks @ofri-peretz! -flagstaff/cli-table3— cli-table3's internal surface now hangs off the default export, and the informational internals column moves 0 / 104 to 90 / 104 against a control of 103 / 104.No behaviour changed and the gated row is 29 / 29 before and after. All 104 internal cases were failing as
X is not a function: the compat oracle reaches a target's internals through a CommonJS shim whose body ismodule.exports = loaded?.default ?? loaded, and that unwrap hands the suite theTableclass rather than the namespace whereCell,strlen,computeWidthsand fifteen more already lived.Object.assign(Table, { … })at the foot of the module publishes them the way cli-table3's ownsrc/cell.jspublishesColSpanCellandRowSpanCell— a second spelling of names this subpath already exported, plus six that were private only because nothing had asked.Two ceilings are recorded with the measurement in
compat-oracle/src/hosts.tsrather than chased: 13 cases intable-layout-test.jsthat resolveCelltoTablebecause the shim collapses four internal modules onto one entry, and the 94 cases ofcell-test.js, which never register in the control run either../cli-table3's byte ratchet rises 29,000 to 29,300 for the 240 B this costs, with the reasoning inweight.test.ts. It is a ceiling moving in the loosening direction and is the owner's to reverse. -
#373
a1f1d40Thanks @ofri-peretz! - Stage 2's artifact is nowspec.md, the name Anthropic's AI-Native SDLC playbook gives it, so the source comments and README sections that cite a package's own design document point atspec.mdrather thandesign.md.No behaviour changes. The published tarballs do move, by two bytes per surviving reference —
design.mdis nine characters andspec.mdis seven — so the four packages carrying a weight band were re-measured against it: linegauge 83,538 to 83,536; paratext 66,343 to 66,341; closeout 84,455 to 84,453; bellpull 86,113 to 86,107. -
Updated dependencies [
f3224f4,2f6cb16,a1f1d40]:- paratext@0.4.0
- closeout@0.2.1
- linegauge@0.3.1
0.3.0
Minor Changes
-
#340
c123029Thanks @ofri-peretz! -flagstaff/boxandflagstaff/tablerender a path or a url as a terminal hyperlink, andflagstaffis the first package in the family to build onparatext(paratext R12).A table cell may be
{ text, href }and a box may be given{ href }. On a terminal believed to understand OSC 8 the text becomes a real hyperlink; on a pipe, in a log, underTERM=dumb, and for a screen reader it readssrc/index.ts (file:///repo/src/index.ts)— the destination survives rather than being dropped with the escape, and no control byte reaches a file. Neither the guess nor the sequence is flagstaff's: both come fromparatext/link, andflagstaffpasses it a runtime instead of re-deciding.flagstaff/cli-table3'shyperlink()now builds its sequence the same way. It still emits unconditionally and byte for byte what upstream emits — that is the drop-in contract, and cli-table3 still grades 29 / 29 — but the escape itself is no longer written out a second time in this package.src/link.test.tslocks that: no published file here spells an OSC 8 sequence of its own.paratext/linkrather thanparatext: 2,410 B and no registry against 20,221 B andregisterBuiltins()at import, measured in paratext's owndist/.flagstaff/tablegrew 1,675 B andflagstaff/box1,502 B; the two budgets inweight.test.tsmoved with them and the reasoning is recorded there.
Patch Changes
-
#332
3ea38c3Thanks @ofri-peretz! -flagstaffno longer carries its own copy of "put the cursor back however the process dies".src/cursor.tsis deleted and its three consumers — theorafaçade, thelog-updatefaçade and the loop'sttyprojection — reachcloseoutinstead, which ownsrestore-cursorandsignal-exitand grades 6 / 6 againstrestore-cursor's own suite. That module's own header argued there is exactly one correct implementation of this and that a second copy is a second place to get it wrong; it was the second copy. There was a third, incaique.The two façades use
closeout/restore-cursor, whose contract is the one their incumbents grade: the stream is a property of the process — stderr if it is a terminal, else stdout — decided when you call, and written at exit whateverisTTYsays by then. The projection usescloseout'sonExitin therestorephase, because it draws on the stream the Runtime handed it and must not learn thatprocessexists.closeout/exit-hookis deliberately not used: it is faithful to its own incumbent, which never registers SIGHUP, so a closing terminal would not have reached the restore.A defect went with it. The deleted module held a process-wide
cursorRestoreInstalledflag — first caller installs the net, every later caller gets a no-op. That reads like a guard against a duplicate restore. It was a lost one: the second surface's writer was never registered, so a program with a hoisted frame on stdout and a spinner on stderr hid two cursors and put back one, leaving stderr's hidden. Measured on the previous build atstderr { hide: 1, show: 0 }. Registering per caller fixes it, andsrc/cursor-net.test.tsgrades both halves — every hidden stream restored, and the one redundant (idempotent) show that two surfaces on a single stream now write.No compatibility row moves: ora 99 / 99, log-update 99 / 99, boxen 84 / 84. None of those suites kills the process, which is why the guarantee is graded by flagstaff's own signal cases against the built
dist/in a child that is really signalled.flagstaffnow depends oncloseout. The per-entry weight measurements fall —.−1,666 B,./loop−1,666 B,./ora−1,591 B,./log-update−1,591 B — and nothing got lighter: the walk stops at a bare specifier, so the code left the measurement while staying in the program. Installed bytes go up, not down. -
#326
88f7ba6Thanks @ofri-peretz! - OneRuntimeseam per package, and one file in each that names the process (Y9).roundel/src/runtime.tsandflagstaff/src/runtime.tseach declare aRuntime— the slice of the world that package actually needs — and aprocessRuntime()that is the only place the real process is named. Six files stop naming it:roundel/chalk, and flagstaff'scli,ora,boxen,cursorandlog-update.Nothing about the ports' behaviour moved, and the shape of each seam is what holds that. roundel's returns a literal, because chalk's contract is to detect the terminal once at import; flagstaff's hands back the live process narrowed to the interface, because its incumbents read the process at call time — boxen takes
stdout.columnsevery time a box is drawn, so a box drawn after a resize still uses the new width, and ora still hooks the real stream objects and still looks upkillwhen it re-signals a swallowed Ctrl+C. The compatibility rows are unchanged: chalk 58/58, ora 99/99, log-update 99/99, boxen 84/84, restore-cursor 6/6. -
#294
3f92a60Thanks @ofri-peretz! - paratext validates against the family plugin schema, with its shape undercapabilities.paratext shipped its own
schema.jsonwhose root was one capability, so the family had three plugin schemas where the contract says one (PRINCIPLES 14,plugin-contractR2). The capability shape is now$defs/capabilityof the shared file, reached through acapabilitieskey besidespinners,tokensandcomponents, andpackages/*/src/schema.jsonhashes to one value. flagstaff and roundel ship the same bytes: their published./schema.jsongains the capability definitions and nothing about what they validate changes.check()follows the schema's$defs/capabilityDocumentand takes either shape:- a plugin carrying its capabilities under
capabilities, which is where they live from now on, and whose problems are reported atcapabilities.<key>; - deprecated — one capability written as the whole document, which is what a 0.2
capability file looks like. It still validates, and
check()returns adeprecated:line saying to move it undercapabilities. paratext 1.0 stops accepting it (.sdlc/PLAN.mdD2).
refusals()andisDeprecation()are exported to tell the two kinds of line apart; the lines that are not deprecations are the ones that block, and the onesregister()throws on.register(capability)is unchanged: it takes one capability, not a document, so it neither reports nor accepts the document-level deprecation. - a plugin carrying its capabilities under
-
#339
f295630Thanks @ofri-peretz! -schema.jsonconstrains token names, because it was promising something no host honours.tokenswas described as any name to a#rrggbbcolour.roundel'svalidate()accepts ten semantic names —error,warn,ok,hint,muted,command,flag,value,heading,ground— and throws on everything else. So a plugin author doing exactly what their ownE_PLUGIN_SCHEMAerror tells them, comparing their object againstroundel/schema.json, got a green from the schema and"accent" is not a tokenfromregister(). Measured 2026-09-16 with{ accent: '#336699' }.The schema now carries
propertyNames.enum, andscripts/plugin-contract-lock.test.tspins the enum and the runtime set to each other from both sides, so neither can grow a name the other does not know.Every host ships a byte-identical copy of this file (
plugin-schema-lock.test.tsasserts it), which is why nine packages are listed. Only the keyroundelowns is constrained: describingwidgets,handlers,sources,resolversorcommandsin a file all eight hosts share is what made flagstaff start validating caique's key last time (PluginError: plugin.widgets.later: expected object, got boolean), and those stay inplugin-schema-lock'sUNDESCRIBEDlist with that reason.linegaugeis in the list for a different change:ceilings.json's R9 block now records the bar as D1's tree-inclusive ceiling — 83,538 against 170,342, a ratio of 0.4904 — and keeps the supersededget-east-asian-widthbar beside it with the count of entries that cleared it. -
Updated dependencies [
c8acb28,fc640dd,3f92a60,3ea38c3,fc640dd,3ea38c3,c8acb28,88f7ba6,c8acb28,3f92a60,fc640dd,3ea38c3,0f00f72,f295630]:- closeout@0.2.0
- linegauge@0.3.0
- roundel@0.3.1
- paratext@0.3.0
0.2.1
Patch Changes
- Updated dependencies [
214f6f8,214f6f8,ecedfa2,ea58e63,3d744d9,59d910c,93114d3]:- roundel@0.3.0
- linegauge@0.2.0
0.2.0
Minor Changes
-
#86
e927678Thanks @ofri-peretz! - Addflagstaff/boxen: boxen 8's API, graded 84 / 84 by boxen's own test suite.Every one of boxen's 84 cases is a snapshot of the exact characters the box comes out as, so matching the drawing byte for byte is the compatibility claim rather than a way of avoiding one — a user leaving boxen cares about one thing, whether the box still looks the same.
borderStyle(all eight cli-boxes styles, a style object, ornone),borderColor,backgroundColor,dimBorder,title/titleAlignment,textAlignment,padding,margin,width,height,float,fullscreen, and the_borderStylesre-export.Eight dependencies folded in. boxen reaches
string-width,wrap-ansi,cli-boxes,ansi-align,widest-line,camelcase,chalkandtype-fest; this reacheswidth.jsandwrap.js— both already shipped forflagstaff/oraandflagstaff/log-update— plusroundel/chalk. 43.0 KB in two packages, against boxen 8.0.1's 151.4 KB in fourteen.It carries cli-boxes' table itself rather than reading the plugin registry:
_borderStylesis boxen's public surface, and a façade whose drawing changed when somebody registered a plugin would be reinterpreting its host. Named borders through the registry stayflagstaff/box's job. -
#116
3daa412Thanks @ofri-peretz! - Addflagstaff/cli-table3: cli-table3 0.6.5's API, graded 29 / 29 by cli-table3's own test suite.The full option surface —
head,chars,style,colWidths,rowHeights,colAligns,rowAligns,truncate,wordWrap,wrapOnWordBoundary, per-cellcolSpan,rowSpan,hAlign,vAlign,href, and thedebugchannel withtable.messagesandTable.reset(). It extendsArray, because cli-table3 does and its callers push rows onto it.One module, not four. Upstream is
table.js,layout-manager.js,cell.jsandutils.js, and 201 of its 234 cases test those files directly. Those are reported beside the number and never gate it — passing them would mean copying cli-table3's file layout rather than matching its behaviour, which is the one thing a façade owes its users.42.3 KB in two packages, against cli-table3 0.6.5's 161.7 KB in seven. It reaches
width.js, already shipped for the other three façades, plusroundel/chalkfor the two default styles. It carries its own wrapping rather than sharingwrap.js: cli-table3 splits on/(\s+)/and counts with its ownstrlen, which a wrap-ansi port does not reproduce.
Patch Changes
-
#149
0d2520bThanks @ofri-peretz! - Correct the published weight comparisons against boxen and cli-table3, both of which overstated the incumbent. boxen 8.0.1 is 132,414 B across nineteen packages, not the 151,351 in fourteen the README and weight rules claimed; cli-table3 0.6.5 is 105,983 across seven, not 161,690. ora and log-update reproduce to the byte and are unchanged. -
#82
61bd11bThanks @ofri-peretz! - One door into the registry, and acheckthat grades what it actually found.registered()handed out the live registry behind aReadonly<Registry>type that freezes property bindings, not theMaps behind them — soregistered().spinners.set(…)put a spinner with no static projection wherespinner()would find it, and.clear()removed the built-ins. It now returns a copy over the frozen objectsregister()stores, which makes U3's "a contribution without a static projection is refused at the door" a property of the code rather than advice. Registering also copies: edit your plugin object afterwards and the registry does not change.flagstaff checkopens with a census of the contributions it found and closes with the verdict, sookis never printed before the rendering that would justify it. A plugin whose keys are misspelled — the schema allows unknown keys on purpose, for the rest of the family — is nowE_NO_CONTRIBUTIONand exit 1 with the unknown keys named, rather thanokand exit 0. Each component block states the state it was rendered with: a component may declaresample: { running, done }, and without one the assumed{ phase }shape is said out loud instead of silently invented. Astaticthat throws isE_COMPONENT_THREWwith a fix and the modes it broke in, rather than an uncaught crash after anok.roundel is bumped with it because the plugin schema is hosted in both packages and both publish it:
packages/roundel/src/schema.jsongained the samesamplekey, andplugin-schema-lock.test.tsrequires the two to be byte-identical. Without a roundel release the copies would agree in git and disagree in the registry — the contract's own "byte-identical in every tarball" rule holding in the repository and breaking where anyone would actually read it. This is the first contract change since roundel became a plugin host, so the pairing is worth establishing now rather than after the second one.Both of those codes are now members of the exported
PluginErrorCode, which is the union every refusal in the family comes from. They were bare string literals insidecli.ts, so a second host could have spelled either one its own way and nothing would have noticed — the plugin contract's "one error vocabulary" held only as long as nobody tested it.refuse()takesPluginErrorCoderather thanstring, and a repo lock reads each host's declaration out of its source and refuses anyE_…literal that is not in it. The union is a type, so this costs no bytes on any subpath. -
#117
ec43c47Thanks @ofri-peretz! -register()lists a plugin name once instead of accumulating it — every other contribution already landed in aMap, so re-registering replaced entries while the name list grew, andflagstaff checkand the docs gallery both project that list. -
#75
f2eaa6aThanks @ofri-peretz! -hoist()puts the cursor back when a signal ends the process.close()restored it, andclose()does not run for a signal with no listener — so Ctrl+C during a frame left the terminal with no cursor at all. The loop now shares thecursor.jsboth façades use. -
#182
28a838fThanks @ofri-peretz! -linegaugeis real:widthandwrapmove out offlagstaffinto the foundation package that was reserved for them (F1, the move only). The default export iswidth, call-compatible withstring-width's default.flagstaffimports them and deletes both files; its 227 tests pass unchanged, and B4's bundled bytes are identical to the byte — the code went to a different file, not away. -
Updated dependencies [
61bd11b,8586f58,28a838f,7c5eeb0]:- roundel@0.2.0
- linegauge@0.1.0
0.1.0
Minor Changes
-
#45
4e376feThanks @ofri-peretz! - The first working release:hoist()with a static projection per mode,register()overschema.json, thedotsandlinespinners as a plugin, andflagstaff check. -
#62
5e34676Thanks @ofri-peretz! -flagstaff/ora— ora 9's whole API, graded 99 / 99 by ora's own test suite. One import changes; the seventeen packages ora ships become two, 113,577 B of JavaScript becomes 55,641 B (49%), and the spinner corpus, the display width, the log symbols, the cursor control — restored onSIGINT,SIGTERMandSIGHUPas well as a clean exit — and the stdin discarder come with it. Both sides counted the same way from the entry point: shipped.jsplus the.jsona module imports,package.jsonexcluded.
Patch Changes
-
#66
b43e1d3Thanks @ofri-peretz! - The four remaining built-ins:progress,tasks,boxandtable, each on its own subpath.box()andtable()are also plain string functions for the callers who want the string. Every one answers the static projection separately — a progress bar is12/30 files · 40%off a terminal, a table isheader: valuepairs — because a stripped drawing is not information. -
#68
8666f70Thanks @ofri-peretz! -flagstaff/log-updaterestores the cursor when the process is signalled, not only when it exits normally. It shipped withprocess.once('exit', …)and nothing else — which node does not run when a signal with no listener terminates the process — so Ctrl+C mid-frame left the terminal with no cursor. That is the same defectflagstaff/orafixed before it shipped, so the fix is now one module,src/cursor.ts, that both façades import:signal-exit's 22.0 KB in 1.4 KB, with the re-raise and itslistenerCountguard, so a program that installed its ownSIGINThandler is still delivered exactly one signal and is never overruled. Graded per façade against the builtdist/in a child process that is really signalled. -
#66
b43e1d3Thanks @ofri-peretz! -flagstaff/import—fromCliSpinners()andfromCliBoxes()turn the corpora you already have into ordinary plugins, through the sameregister()and the same schema. Neither corpus is bundled; 838 B, reaching nothing. The plugin contract gainsborders, and the built-in border styles move into the built-ins plugin with the spinners, sobox()can draw with a style a plugin registered. -
#66
b43e1d3Thanks @ofri-peretz! -flagstaff/log-update— log-update 8's API, graded 99 / 99 by log-update's own suite, which renders every frame through a real terminal emulator. Sixteen packages and 113.4 KB become none and 28.7 KB: the subpath reaches no package at all. Bringswrap(), an ANSI-aware wrapper graded differentially against wrap-ansi, whichboxandtableshare. -
#76
847f79aThanks @ofri-peretz! - Exportflagstaff/schema.json.PluginError's fix forE_PLUGIN_SCHEMAtells a plugin author to "compare the object against flagstaff/schema.json", and that specifier did not resolve — following the advice gotERR_PACKAGE_PATH_NOT_EXPORTED. The file already shipped in the tarball; only theexportsentry was missing. -
#66
b43e1d3Thanks @ofri-peretz! - The static projection writes only what is new. A component whose projection is a growing list —tasks, whose static is every task that has settled — reprinted every line already in the log on each change; it now writes the lines past the common prefix. An empty projection writes nothing at all, rather than a blank line. Found by generating the docs gallery from the components themselves. -
Updated dependencies [
183ebc9,c65bad8]:- roundel@0.1.0