Skip to content

Releases: markii-org/markii

v0.16.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 15:40
v0.16.0
ab2a7be

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.16.0

All eight packages, if you want them explicitly:

npm install @markii/core@0.16.0
npm install @markii/stdlib@0.16.0
npm install @markii/bundle@0.16.0
npm install @markii/pack@0.16.0
npm install @markii/runtime@0.16.0
npm install @markii/lua@0.16.0
npm install @markii/react@0.16.0
npm install @markii/html@0.16.0

Downloads

The attached tarballs are the packed npm packages. The names are
stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.15.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 05:03
v0.15.0
a9d85a0

The @markii/* packages and the VS Code extension ship this release as
0.15.0, the Obsidian plugin as 0.12.0.

Added

  • @markii/ansi: a terminal renderer. A third platform engine beside
    @markii/react and @markii/html, for a note that is read in a shell:
    a command line tool, a CI log, a pager, a file someone will cat. It
    consumes the same sanitized tree the other engines do and emits a plain
    string, with renderMarkToAnsi, renderMarkNodeToAnsi and
    renderMarkInlineToAnsi mirroring their counterparts. The whole standard
    component set is there, drawn with box-drawing characters and block
    characters: framed cards and tables, a bar-and-sparkline chart, side by
    side row cells that stack when the terminal is narrow. The package depends
    on @markii/core and @markii/stdlib and nothing else, so the ANSI
    escapes, the display-width measurement and the box drawing are all its own.

    Color is the caller's decision, not the engine's. It never reads
    process, standard output, or the environment, so the same render is
    correct going to a terminal, to a log file, and to a test; detectColorLevel
    is exported for a caller that wants detection and honors NO_COLOR,
    FORCE_COLOR, TERM and COLORTERM. Colors come from a theme that maps
    every Tier 1 doc.css token, with a coverage test that fails when a new
    token has no entry, the same rule the two host theme layers follow.

    Author text can never put an escape sequence into a reader's terminal.
    Every string is stripped of control characters before it is printed, so the
    only escapes in the output are the engine's own, and a probe suite proves it
    by stripping the permitted sequences and asserting nothing is left.

  • markii, a command line tool (apps/cli, not published yet; build it
    from source). markii view renders a note, a directory bundle or a .mkz
    to standard output, running its scripts first when it is talking to a real
    terminal. markii export writes HTML through the same path the editor
    hosts export with, the terminal rendering, or a plain CommonMark downgrade.
    markii run runs a note's scripts once at the manual tier, prompting on the
    terminal for each host the closure scan finds. It runs scripts through the
    same shared, security-critical run path both editor hosts use, in a Node
    worker thread with the same watchdog, and stores grants per device under the
    platform's own configuration directory. There is no unattended-grant flag.

Removed

  • This repository's own GitHub Pages deployment of apps/playground.
    The vault playground (markii-vault, https://sadigaxund.github.io/markii-vault/)
    is now the one deployed playground; apps/playground stays a local dev
    harness only.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.15.0

All eight packages, if you want them explicitly:

npm install @markii/core@0.15.0
npm install @markii/stdlib@0.15.0
npm install @markii/bundle@0.15.0
npm install @markii/pack@0.15.0
npm install @markii/runtime@0.15.0
npm install @markii/lua@0.15.0
npm install @markii/react@0.15.0
npm install @markii/html@0.15.0

Downloads

The attached tarballs are the packed npm packages. The names are
stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.14.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 21:45
v0.14.0
105263e

The @markii/* packages and the VS Code extension ship this release as
0.14.0, the Obsidian plugin as 0.11.0.

Added

  • @markii/stdlib: an ./editor subpath. The pure editor helpers move
    here from the private @markii/host, so a third-party editor host can
    install the behavior the two reference hosts have. It holds directive
    completion and hover (completionAt, hoverAt, the directive-context
    scanner), the Insert Component skeleton builder and the standard-set
    catalog, and container fence lengthening. The package still has zero
    dependencies, so a host that only wants to complete the standard
    components does not pull in pack loading, a bundler, or the script
    runtime. @markii/host re-exports all of it unchanged.
  • @markii/stdlib/editor: CompletionContext.tokenStart. The offset
    where a directive name begins, after the colon run, beside the existing
    replaceStart. A completion widget that filters candidates against typed
    text anchors on tokenStart and edits from replaceStart; both reference
    hosts previously derived this value themselves.
  • @markii/stdlib/editor: closesOpenContainerFence. Tells a host's
    completion trigger that a bare colon run closes a container already open
    above it rather than starting a new one, so accepting a suggestion cannot
    insert a component into a closing fence. completionAt is unchanged and
    still offers the catalog for a bare opener.
  • @markii/stdlib: INTERACTIVE_ATTRIBUTE and the diagnostic envelope.
    INTERACTIVE_ATTRIBUTE (data-mk-interactive) is the one spelling both
    renderers, and packs, mark a genuinely interactive element with.
    DiagnosticEvent, DiagnosticKind, OnDiagnostic and reportDiagnostic
    are the neutral shape behind both renderers' onDiagnostic option;
    reportDiagnostic keeps a throwing host callback from breaking a render.
  • @markii/core: isRecognizedTextDirective. The post-parse word-start
    rule that decides whether a tokenized inline directive is kept or demoted
    back to plain text, exported for an editor grammar that has to make the
    same call. It is the demotion rule only: the colon-run and bracket rules
    live in the upstream directive parser.
  • @markii/core: ScriptBlock.permissions. An optional list of
    hostnames a script fence declares through a permissions attribute. It is
    display only, never an input to what is granted, mirroring how a bundle
    manifest's permissions.net is already treated.
  • @markii/react and @markii/html: resolveHref. The link twin of
    resolveImageSrc, applied to an ordinary markdown link's href, sharing
    the same dangerous-scheme refusal rather than a second copy of it.
  • @markii/react and @markii/html: whole-document rendering.
    renderMarkNode and renderMarkNodeToHtml now accept the Root parse
    returns as well as a single node, so a host does not loop over top-level
    children itself.
  • @markii/react and @markii/html: renderMarkInline and
    renderMarkInlineToHtml.
    Renders source that is exactly one paragraph
    holding one inline directive without the paragraph wrapper; any other
    source falls back to the ordinary render unchanged.
  • @markii/react and @markii/html: onDiagnostic. Called once for
    each quiet marker a render produces for a value it recognized and
    declined, with the kind, directive, attribute, and the marker's own
    wording, so a host can route it to its diagnostics surface. An unknown
    attribute name never triggers it.
  • @markii/react and @markii/html: store and vault on the render
    options.
    The same values the third and fourth positional arguments take,
    available on the options object instead. The option wins when both forms
    are given.
  • @markii/react and @markii/html: a quiet marker for a recognized and
    declined value.
    A known attribute whose value is outside its closed set,
    and a figure source refused as unsafe, still render, now carrying a
    data-mk-notice attribute and a title explaining why instead of
    discarding the value in silence.
  • @markii/react and @markii/html: data-mk-interactive on tabs'
    buttons, a details summary, and the collapsed script marker's summary.

Changed

  • @markii/react: loadPack returns { registry, dropped? } instead
    of a bare Registry, and installPacks's success result carries
    dropped: { name, engine }[]. A pack built for another renderer was
    previously discarded with no record a caller could read. This is a
    breaking change to loadPack's return type.
  • @markii/lua: an ungranted capability denies instead of vanishing.
    With no grants at all, net and its methods exist and record a denial
    through the same non-spoofable channel a wrong-host call already used, so
    the run's outcome is a capability failure rather than a Lua nil-index
    error. Observable: a script that feature-detects with if net then now
    always sees a table.

Fixed

  • @markii/pack: a .mkp zipped as a folder says so. An archive whose
    entries all sit under one top-level directory is reported by naming that
    directory, instead of claiming there is no pack.json when there is one a
    level down. __MACOSX entries are ignored when making that call.
  • doc.css: an align= wrapper no longer collapses a block inside a
    :::row.
    The automatic inline margin is cancelled for a row grid item
    that carries no width= preset, so the item keeps its column instead of
    shrinking to its content.
  • doc.css: a host that renders into its own container keeps the derived
    tokens.
    The Tier 2 derivations and the other rules that were scoped to
    .doc (vertical rhythm, base typography, tables, code, task lists) now
    also apply under [data-mk-root], which a host adds to its own container.
    The table rule is the scroll container a wide table needs, so a non-.doc
    host was losing that too.

VS Code extension (0.14.0)

  • Directive completion no longer opens on a line that closes a container,
    and the popup filters on the directive name rather than on the colon run.
  • Insert Component and completion insert no empty {} for a component with
    no required attributes, and put the cursor in the body of a container or
    after the name of a leaf.
  • Add Pack Folder validates the folder before adding it, says what it found,
    and writes the reason for anything skipped to the Markii output channel.
  • Completion, hover and Insert Component only offer components from packs
    built for this renderer.
  • A render's quiet markers reach the Markii output channel, deduplicated,
    instead of living only in a tooltip.

Obsidian plugin (0.11.0)

  • The Markii Preview header action appears on a freshly created .mk.md
    note, without the view having to be split first.
  • The Markii Preview pane converts wikilinks and image embeds the way
    Reading view does, so a note renders the same on both surfaces.
  • Directive completion no longer opens on a line that closes a container.
  • Insert Component and completion offer only components from packs built for
    this renderer.
  • A render's quiet markers reach the console, deduplicated, alongside the
    plugin's other diagnostics.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.14.0

All eight packages, if you want them explicitly:

npm install @markii/core@0.14.0
npm install @markii/stdlib@0.14.0
npm install @markii/bundle@0.14.0
npm install @markii/pack@0.14.0
npm install @markii/runtime@0.14.0
npm install @markii/lua@0.14.0
npm install @markii/react@0.14.0
npm install @markii/html@0.14.0

Downloads

The attached tarballs are the packed npm packages. The names are
stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.13.0

Choose a tag to compare

@github-actions github-actions released this 02 Sep 22:45
v0.13.0
2c299a0

The @markii/* packages and the VS Code extension ship this release as
0.13.0, the Obsidian plugin as 0.10.0.

Added

  • @markii/lua: a json table for scripts. json.decode(text) parses
    JSON into ordinary Lua data, and json.encode(value) converts a Lua value
    back into JSON text. Both are present on every trigger tier and need no
    capability grant, because neither does any I/O. They reuse the decoder and
    the marshal walk the runtime already has rather than adding a second copy
    of either, so json.decode is bound by the same size, depth, and
    node-count budget net.fetch_json applies, and json.encode rejects a
    cycle, a function, a non-string table key, or a non-finite number exactly
    as a script's own return value is rejected.

  • @markii/bundle: createMemoryBundleStorage(files). A third
    BundleStorage form beside the zip and directory forms, backed by a plain
    map of bundle-relative paths to strings or bytes. It routes every path
    through the package's own jail and is exported from the browser-safe main
    entry, so a host that already holds a bundle's files as values does not
    need Node to use them.

  • @markii/react and @markii/html: a resolveImageSrc render option.
    renderMark and renderMarkNode, and renderMarkToHtml and
    renderMarkNodeToHtml, accept an optional function that turns a relative
    <img src> into a URL the host can load. It covers both an ordinary
    markdown image and a component that builds its own <img>, such as the
    standard figure, and it is never asked about a source that already carries
    a scheme. A resolver that returns nothing, or throws, leaves the source as
    written. A javascript: or vbscript: result is refused, judged the way a
    browser parses a URL rather than by the raw text, so a disguised scheme
    cannot slip through.

Changed

  • Both hosts resolve a note's images during the render instead of after
    it.
    The VS Code preview and Obsidian's preview and Reading view pass
    resolveImageSrc and no longer sweep the mounted DOM rewriting <img>
    elements once React has finished. The images resolve the same way they did,
    including Obsidian's report of a source that names nothing in the vault, but
    the page no longer briefly requests the unresolved URL first.

Fixed

  • Host-compiled packs no longer leave a __markiiJSX global behind. The
    pack builder passed its JSX shim through esbuild's banner option, which
    writes text outside the format: 'iife' wrapper, so every pack the VS Code
    extension compiled from source, and both hosts' bundled read, dash, and
    prep packs, leaked that global. The shim is now an injected module inside
    the wrapper. This also fixes a component that renders through a helper
    module: because a banner cannot put the shim in scope of a non-entry
    module, JSX in such a helper failed at render time. Packs rebuild once on
    upgrade.
  • @markii/bundle: the bundle write grant is spelled write:.cache/.
    The writable directory is documented everywhere as .cache/, but the write
    jail accepted only the undotted cache/ prefix, so bundle.write(".cache/x")
    was denied even with the grant while a write to cache/x landed outside the
    documented directory. The jail, the grant token, and the manifest grammar
    now all use .cache/. Breaking for bundles: a manifest declaring the
    retired write:cache/ no longer parses, and reports a diagnostic naming the
    correct token instead of being silently accepted.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.13.0

All eight packages, if you want them explicitly:

npm install @markii/core@0.13.0
npm install @markii/stdlib@0.13.0
npm install @markii/bundle@0.13.0
npm install @markii/pack@0.13.0
npm install @markii/runtime@0.13.0
npm install @markii/lua@0.13.0
npm install @markii/react@0.13.0
npm install @markii/html@0.13.0

Downloads

The attached tarballs are the packed npm packages. The names are
stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.12.1

Choose a tag to compare

@github-actions github-actions released this 02 Sep 14:15
v0.12.1
a345afa

Added

  • doc.css: a data-mk-theme override on .doc. Setting
    data-mk-theme="light" holds the light Tier 1 palette whatever the
    reader's operating system prefers, and data-mk-theme="dark" holds the
    dark one. Both are attribute selectors, so an explicit attribute wins over
    the automatic prefers-color-scheme palette and over a host's own token
    mapping. The automatic palette's own selector is unchanged, so a host that
    never sets the attribute behaves exactly as before, and
    exportHtmlDocument still emits no attribute and still follows the
    reader's preference.

Changed

  • VS Code: Markii: Export Pack writes a .mkp archive only. The
    folder output and the format quick pick are gone. The command asks which
    pack when more than one is configured, builds the archive, then opens a
    save dialog prefilled with <name>-<version>.mkp, or <name>.mkp when
    the manifest declares no version. Building before asking means a build
    failure never costs the user a destination they would have to pick again,
    and the save dialog owns the overwrite confirmation. @markii/host's
    folder-writing exportPack stays: it is how the extension build lays out
    its bundled packs, and the archive export composes through it.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.12.1

All eight packages, if you want them explicitly:

npm install @markii/core@0.12.1
npm install @markii/stdlib@0.12.1
npm install @markii/bundle@0.12.1
npm install @markii/pack@0.12.1
npm install @markii/runtime@0.12.1
npm install @markii/lua@0.12.1
npm install @markii/react@0.12.1
npm install @markii/html@0.12.1

Downloads

The attached tarballs are the packed npm packages. The names are
stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 02 Sep 10:43
v0.12.0
72eb538

The @markii/* packages and the VS Code extension ship this release as
0.12.0, the Obsidian plugin as 0.9.0.

Added

  • VS Code: Markii: Install Pack from File… (markii.installPack).
    Picks a .mkp file, validates it, asks the user to confirm that
    installing it will let its code run inside every Markii preview, asks
    before replacing an already-installed pack of the same namespace, unzips
    it into the extension's own installed-packs directory under
    globalStorage, and adds that directory to markii.packs. A rejected
    archive reports the reason on the Markii output channel and installs
    nothing. An archive is the only way a pack enters a host this way: a
    markii.packs entry always names a folder.

  • VS Code: Markii: Remove Installed Pack…
    (markii.removeInstalledPack).
    Lists the packs installed under
    globalStorage, each with the version its manifest declares, asks for
    confirmation, then deletes the pack's directory and removes its
    markii.packs entry in one step, so an installed pack can be taken back
    out without finding the storage folder by hand.

  • VS Code: Markii: Export Pack gains an archive output. Alongside
    today's folder export, the command now offers a single .mkp file,
    built by @markii/host's new exportPackArchive (the same compile,
    zipped with fflate instead of written as separate files) and named
    with @markii/pack's packArchiveFileName.

  • @markii/host: exportPackArchive, the archive-producing counterpart
    of exportPack: it compiles a pack through the same build cache and
    returns a .mkp file's bytes rather than writing a folder.

  • Obsidian: three bundled component packs, read, dash, and prep,
    need no installation. Their prebuilt registration scripts and stylesheets
    are compiled at plugin build time (reusing @markii/host's
    buildPackRegistrationScript, the same compiler VS Code and this plugin's
    own on-demand pack loading already use) and embedded into main.js as
    base64, the same esbuild.options.mjs pattern the Run path's worker
    bundle and wasmoon's glue.wasm already use, with the build failing
    loudly if the substitution did not happen. That makes the three-file BRAT
    install carry them, with no esbuild-wasm runtime required at load time.
    They behave as ordinary packs: namespaced (read_source, and so on),
    listed by a note's uses:, and shown in the Insert Component and
    completion catalogs. They load before any installed pack, and an
    installed pack that claims a namespace one of the three already holds is
    refused at install time: the bundled pack wins the namespace, matching
    the ordinary collision rule rather than making an exception to it. The pack contract itself is unchanged; only
    apps/obsidian's build and pack-loading pipeline gained a bundled-pack
    source ahead of its on-disk one.

  • Obsidian: an app-managed pack store. Installed packs live in the
    plugin's own directory, one folder per namespace, and the settings tab
    lists them with the version each manifest declares, a Remove control that
    deletes the folder and the device's trust entry together, and an Enable
    control for a pack folder that is present without being installed here.
    Which namespaces this device loads is recorded device-locally, never in
    plugin data, so a synced or shared vault carries none of those decisions.
    A pack folder that arrives another way, through Sync or a hand copy, sits
    inert until it is enabled, and enabling asks the same consent question
    installing asks. A folder whose pack.json declares some other namespace
    than the folder's own name is not loaded at all.

  • Obsidian: Reload Markii packs. Installing, removing, and enabling a
    pack already reload every open preview and Reading view on the spot; this
    command does the same on demand, and each reload writes what loaded and
    what was skipped to the diagnostics console.

  • A table standard component, data-bound like stat, progress, and
    chart. It handles four bound shapes: an array of objects (columns from
    the union of keys, in first-seen order), an array of arrays (rows as
    given), an array of primitives (one column), and a single object
    (key/value rows). columns= picks and orders columns, limit= caps the
    rows shown, caption= adds a caption, and format=/decimals= apply to
    numeric cells only. A missing, stale, or failed binding collapses to one
    quiet empty state rather than an error.

  • format= and decimals= attributes on :value[...], stat,
    progress, and table. number groups thousands, compact shortens
    them, percent reads a fraction as a percentage, and date and
    relative read an ISO date or epoch milliseconds. plain stays the
    default, so existing documents render unchanged. An invalid format or
    decimals is ignored rather than raised, and non-numeric input under a
    numeric format shows unchanged. The logic lives in one @markii/stdlib
    primitive both renderers call, so the two engines cannot format a value
    differently.

  • conformance/render/, a render-level fixture set: each .mk.md input
    is paired with committed .html that @markii/html is byte-diffed
    against, with @markii/react cross-checked for the same classes and
    structure. The existing corpus pins the AST; this pins the rendered
    output.

  • docs/spec.md §9, a requirement-to-fixture map tying every literal
    MUST and MUST NOT in the spec's core sections to the test that pins it. A
    new test in @markii/core parses the table and fails when a row cites a
    fixture that does not exist, so the map cannot rot into decoration.

  • A dark palette for exported documents. doc.css remaps its Tier 1
    tokens under prefers-color-scheme: dark, so a standalone HTML export
    opened by a viewer with a dark OS preference renders themed instead of a
    light page glaring back. A host's own theme layer (VS Code, Obsidian)
    still wins the cascade for its own preview, since it redeclares the same
    tokens unconditionally after doc.css loads: only a page with no such
    layer after it, an export, ever resolves the new block.

  • A print stylesheet for exported documents. @markii/host's
    EXPORT_PAGE_CSS now sets @page margins, keeps a card, callout, or
    table from splitting across a page break, and hides the collapsed script
    marker and the VS Code webview's run marker when printing.

  • An index.html entry file for a cascade export. @markii/host's new
    buildCascadeIndexHtml lists every note a cascade exported by title,
    linking to its file, and both hosts write it into the archive alongside
    the notes. assignCascadeFileNames takes an optional reservedNames
    list so a walked note literally called index gets suffixed instead of
    colliding with the archive's own index page.

  • A hideScriptBlocks export option. buildNoteHtmlExport,
    composeNoteHtmlExport, and buildNoteExport accept it, and
    exportHtmlDocument grew a matching docClassName option to carry it
    onto the .doc wrapper. Both hosts pass their existing preview
    preference (VS Code's markii.hideScriptBlocks, Obsidian's "Hide script
    blocks" setting) into every export, so a note exported with scripts
    hidden in the editor stays that way in the file.

  • Obsidian: .mk.md notes render inline in Reading view. A markdown
    post processor renders the whole note through the same @markii/react
    seam the Markii Preview pane uses, into the first Reading-view section
    Obsidian calls it for, and leaves every later section empty, since
    Obsidian's section splits do not line up with a Markii ::: container's
    span. Wikilinks and embeds are converted to ordinary markdown first,
    resolved through Obsidian's metadata cache, so an unresolved link keeps
    pointing at its own text instead of breaking the render. A run's values
    update the rendered note without reopening it. A plain .md file is
    never touched, and Live Preview stays untouched by design. The new
    "Render components in Reading view" setting, on by default, turns this
    off while leaving the Markii Preview pane exactly as it was.

  • Obsidian: install a pack from a .mkp file. The new "Install Markii
    pack from file" command validates the archive, asks in words that say the
    pack's code will run in the preview, asks again before replacing a pack of
    the same name, and writes nothing until all of that has passed. A rejected
    archive is reported and leaves nothing behind. An entry in the device-local
    pack list can also point straight at a .mkp, read where it sits and never
    compiled, so it works on an install that carries no compiler.

  • An optional version field on a pack manifest (@markii/pack). A
    pack's pack.json may now declare a plain semver version string
    (MAJOR.MINOR.PATCH, digits only, no leading zeros, no prerelease or
    build suffix). Omitting it stays fully valid, with no warning. A present
    but malformed value is a validation error, the same posture name gets,
    since a version a host cannot trust is worse than none. The three
    bundled packs (read, dash, prep) now declare "version": "1.0.0".

  • .mkp pack archives: a reader in @markii/pack. openPackArchive
    takes the raw bytes of a .mkp file (a zip of a pack's prebuilt form,
    files at the archive root: pack.json, webview.js, webview.css when
    present, scripts/ when present) and returns its validated manifest,
    compiled script, optional stylesheet, and optional shared Lua modules, or
    a structured error. It never compiles anything: an archive with no
    webview.js is rejected, since .mkp exists for hosts that may not
    carry a compiler. It reuses @markii/bundle's zip reader and path jail
    rather than a second implementation, so a .mkp gets the same
    decompression-bomb guard and zip-slip rejection (../, an absolute
    path) a .mkz bundle gets. `packArchi...

Read more

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 08:12
v0.11.0
21eb9e5

Added

  • VS Code writes a run's script failures to the Markii output channel,
    one line per failed script with its name, failure kind, and the short
    reason the value marker's tooltip carries, so a failure behind a
    collapsed or hidden marker is discoverable without hovering. Obsidian
    already wrote the same lines to its console.

  • Hide script blocks in the preview (VS Code extension, Obsidian
    plugin). A named Lua fence normally renders as a collapsed marker you can
    expand to read the source. Turn on markii.hideScriptBlocks in VS Code,
    or "Hide script blocks" in the Obsidian settings, and the preview leaves
    those markers out, for a note meant to be read rather than edited.

    The setting is cosmetic and hides the source blocks only. A script that
    fails still marks the value it feeds, still flips the run marker to its
    failed state in VS Code, still produces the failure notice a manual run
    gets in Obsidian, and still writes its full reason to the host's
    diagnostics surface. The renderer is untouched: both hosts put one class
    on the document root and their own theme layer does the rest, so an
    exported note and any other consumer of @markii/react render exactly
    as before.

  • Turn script execution off on this device (VS Code extension, Obsidian
    plugin). Set markii.scriptsDisabled in VS Code, or turn on "Turn off
    script execution on this device" in the Obsidian settings, and no note
    runs its scripts: not an explicit Run, not run on open, and not a
    scheduled refresh. Markii: Toggle Script Execution and Toggle
    Markii script execution
    flip it from the command palette.

    A blocked Run says so in one line. A blocked automatic run is written to
    the host's diagnostics surface instead of interrupting you on every note
    you open, and a blocked scheduled run also stops that preview's timer, so
    the reason is recorded once rather than every interval. Notes still
    preview, still export, and still show whatever values their last run
    produced.

    Grants are untouched in both directions. Turning execution off leaves
    every stored network and bundle grant as it is, and turning it back on
    re-authorizes nothing beyond what was already granted by hand. In VS Code
    the setting is user-scope only, so a workspace cannot turn execution back
    on for you; in Obsidian it is stored per device through local storage,
    never in the vault, so one device's decision never travels with Sync or
    with a shared vault.

  • Values appear one at a time while a run is going (VS Code extension,
    Obsidian plugin). A note's scripts run one after another in a single
    isolate, so the first number is often ready seconds before the last one
    is. The preview now shows each value the moment its script finishes: that
    component switches from stale to fresh while every other component in the
    note stays stale until its own value lands. The run still reports its
    completion at the end, exactly as before, and a run that is cut short by
    the wall-clock watchdog now keeps the values that already arrived instead
    of coming back empty and clearing the note's last-known figures.

  • @markii/runtime: an onValue option on runDocumentScripts. It is
    called once per script, in document order, immediately after that
    script's value is written to the store, and it is called for a failed
    script as well as a successful one. The callback receives a copy of the
    summary entry, cannot change what the run stores or reports, and anything
    it throws is swallowed, so runDocumentScripts still never throws. A
    caller that does not pass it behaves exactly as before.

  • A script can read the note it runs in (@markii/runtime,
    @markii/lua). A doc table is now in scope for every script block:
    doc.directives(filter) returns the note's directives in document order,
    each as {name, form, attributes, text} with the inner markdown
    stripped, and doc.value(name) returns what a script ABOVE the caller
    produced. That is enough for a note to collect what its author already
    wrote: several :::prep_q blocks, one script that turns them into a
    quiz, one component that renders it. filter accepts {name = "..."};
    a directive written inside another appears in the list right after its
    parent, so filtering by name finds every match whatever wraps it.
    doc.truncated says whether anything was left out to stay inside the
    caps.

    The table is read-only and carries no authority, so it is not tier
    gated: an auto or scheduled run sees exactly what a manual run sees, and
    nothing new was granted. Reading a name that belongs to a script further
    down the note (or to the caller itself) fails the run and the marker
    reads "script error: reads "quiz", which runs later in the note", rather
    than quietly returning a value whose meaning depends on where the reader
    happened to be written. An unknown name, and a name whose script failed,
    both read as nil.

  • @markii/runtime: buildDirectiveListing, createDocViewSource,
    laterScriptReadMessage, DEFAULT_DOC_LISTING_LIMITS,
    EMPTY_DIRECTIVE_LISTING, sanitizeText, utf8ByteLength
    , plus the
    DirectiveEntry, DirectiveListing, DocListingLimits, DocView,
    DocValueRead, DocViewSource, DocumentContext and
    DocumentTreeNode types. runDocumentScripts takes a new optional
    doc option (the listing the host built from the tree it already
    parsed) and ScriptExecutor receives a new optional doc input, one
    view per script. An executor written before this still satisfies the
    type and behaves exactly as it did.

    The listing is capped: 512 KiB in total, 2,000 directives, 8 KiB of text
    and 32 attributes per directive, 1 KiB per attribute value, and 200
    levels of tree depth. Being over a cap shortens the listing and sets
    truncated; it is never an error. Text and attribute values reach a
    script with control characters and unpaired surrogates already removed.

  • @markii/lua: buildDoc and the DocConfig/DocRejections types,
    and a doc option on runScript. The listing crosses into Lua as JSON
    text and is decoded by the same trusted in-Lua decoder net.fetch_json
    uses, so a script receives genuine Lua tables. Each doc.directives()
    call decodes afresh, so an entry a script writes to cannot change what
    the next call returns, and each script already runs in its own engine. A
    refused read is recorded out of band, the way capability denials already
    are, so the reported sentence is the clean one rather than a Lua stack
    traceback, and a script cannot forge it.

Added

  • Export a note and the notes it links to as one archive (VS Code
    extension). Markii: Export as HTML cascade… follows the note-relative
    markdown links out of the active note, exports each note it reaches the
    same way the single-note export does, and writes one zip archive at a path
    you pick. Links between exported notes are rewritten to the exported file
    names, so the archive browses on its own, and a link to anything outside
    your workspace or the note's own folder is never followed and stays exactly
    as written. The walk is bounded at four hops and one hundred notes, and
    every note that was skipped or could not be read is named on the Markii
    output channel. This mirrors the Obsidian plugin's Export Markii note as
    HTML cascade
    , and both hosts share the walk, the naming, the link
    rewriting, and the archive itself.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.11.0

All eight packages, if you want them explicitly:

npm install @markii/core@0.11.0
npm install @markii/stdlib@0.11.0
npm install @markii/bundle@0.11.0
npm install @markii/pack@0.11.0
npm install @markii/runtime@0.11.0
npm install @markii/lua@0.11.0
npm install @markii/react@0.11.0
npm install @markii/html@0.11.0

Downloads

The attached tarballs are the packed npm packages. The names are
stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 02:10
v0.10.0
e4b427f

Release Notes - Version 0.10.0

Release Date: September 1, 2026

Summary

This major update introduces cross-axis layout attributes, allowing wrappers to accept their complementary axis, and adds comprehensive text-alignment attributes across core components. It delivers powerful export features, including self-contained HTML generation with embedded images, Obsidian HTML cascades, and direct PDF printing. It also brings pack-declared attributes directly into directive completion and hover documentation, adds a new fit width preset, and improves nested container fence management.

Added

  • A layout wrapper now takes the other axis as an attribute (@markii/react, @markii/html, @markii/stdlib): width sizes a block's box and align places that box in the column, and each of the seven wrappers already sets one of those two by its name. It now accepts the other one as an attribute, so :::center{width=fit} and :::fit{align=center} say the same thing and render as ONE element carrying both classes (mk-layout mk-align-center mk-width-fit), not two nested wrappers. An attribute for the wrapper's own axis is ignored, because the name already decided it: :::center{align=right} is simply centered. Invalid values are ignored as before. Nesting two wrappers still works and still means the same thing. Directive completion follows the same rule: an alignment wrapper offers width only, a width wrapper offers align only.
  • text aligns the content inside a component (@markii/stdlib, @markii/react, @markii/html): row, cell, card, and callout accept text=left|center|right. On a row it reaches every cell; a cell with its own text overrides it, and an alignment wrapper written inside a cell wins over both. text is an ordinary per-component attribute, not a reserved layout key: it reaches the component like any other. It is rendered through one new class set (mk-text-left/mk-text-center/mk-text-right) defined once in doc.css, and it is offered by directive completion and hover on those four components.
  • @markii/stdlib: layoutWrapperAxis, otherLayoutAxis, and the LayoutAxis type: the one classification of which axis each wrapper name decides, plus TEXT_ALIGN_PRESETS, TEXT_ALIGN_ATTRIBUTE, and TEXT_ALIGN_COMPONENTS for the text attribute. Both renderers and the completion layer read these instead of keeping their own copies.
  • **@markii/react: RegistryEntry.layout and the layoutClassName prop; @markii/html: HtmlRegistryEntry.layout and HtmlRenderContext.layoutClassName**: An entry that declares layout is a scope that already sets that axis by its name: the renderer drops that axis's attribute, resolves the other one, and hands the resulting class to the component instead of wrapping it in a second <div>. A component still never receives width or align among its attributes. Every entry without layout behaves exactly as before.
  • Export a note as a self-contained HTML file (VS Code extension, Obsidian plugin): Markii: Export as HTML… in VS Code asks where to save and writes one .html file; Export Markii note as HTML in Obsidian writes it beside the note in the vault. The file carries the shared doc.css inside it and needs nothing beside it. The note's last run is baked in, so a monitoring note exports with the figures it was showing; a note that has never been run exports with its usual empty states, and both hosts say so. Relative image sources are preserved, so a file written beside its note resolves them the same way the note does.
  • Pack components render in an exported file: When the exporting host has packs loaded, the export is rendered with the same merged registry and value store the preview uses, and each loaded pack's stylesheet is embedded after doc.css in the order the host injects it, so the file matches the preview. Obsidian renders directly; VS Code asks its preview webview and waits a bounded moment for the answer. With no packs loaded, or with no renderer to reach, the export falls back to @markii/html, the static string engine, where a pack directive comes out as the ordinary unknown-component fallback: a labeled box with the author's own content still rendered inside it. Neither outcome is treated as a failure, and the two are distinguishable on each host's diagnostics surface without changing what the notice says.
  • Exported files carry their own images: A local image a note references is embedded in the exported HTML as a data: URI, so the file is self-contained: it opens with its pictures intact on a machine that has never seen the vault or the workspace. Remote http and https sources stay live URLs, since embedding them would change what the page fetches. Each host resolves an image the way its own preview does and reads it under its own jail, so an export can never pull in a file the preview itself could not show. An image above 2 MiB keeps its original path rather than inflating the file, and so does one whose extension the embedder does not recognize, or one that could not be read. Every such case is named on the host's diagnostics surface with its file and size. None of them is a failure and none of them reaches the notice. The Obsidian PDF export benefits automatically, since it prints exactly this document.
  • Export a linked set of notes as one archive (Obsidian plugin): Export Markii note as HTML cascade follows the links out of the active note, both wikilinks and markdown links that resolve to notes in the vault, exports every note it reaches as its own HTML file with images embedded, and writes the whole set as one zip beside the root note. Links between exported notes are rewritten to point at the sibling files, so the archive is navigable offline; a link to a note outside the exported set, or to something that is not a note, is left exactly as written. The walk detects cycles and stops at a depth and a note-count bound, and says on the diagnostics surface which bound stopped it. Cascade to PDF is not part of this release.
  • Export a note straight to PDF (Obsidian plugin): Export Markii note as PDF prints exactly the document the HTML export would have written, through Electron's printToPDF in a hidden window, and writes the .pdf beside the note. Where that is unavailable, on a device with no reachable Electron window or a vault with no filesystem path, the command writes the HTML file instead and says which of the two happened. The reason goes to the console, this host's diagnostics surface, never into the notice.
  • **@markii/pack: a component can declare its attributes in pack.json**: The object form of a components entry takes an optional attributes list, each entry carrying a name plus an optional description, required flag, closed values set, and default. The field is optional and every existing manifest keeps parsing unchanged, so this is backward compatible. parsePackManifest validates the list strictly and rejects a manifest that gets it wrong: a bad attribute name, a duplicate name, a non-boolean required, a values list that is not a non-empty array of non-empty strings, or a default outside its own values. An unknown key inside an attribute entry stays a forward-compatible warning. resolvePackComponent normalizes the same field leniently for callers reading a manifest that never went through validation, dropping what it cannot make sense of. New exports: the PackComponentAttribute type, PACK_ATTRIBUTE_NAME_PATTERN, and isPackAttributeName.
  • divider takes a label-align attribute (@markii/stdlib, @markii/react, @markii/html): ::divider{label="Part 2" label-align=left} positions the label along the rule instead of centering it. The value is one of left, center, or right, and an absent or unrecognized value falls back to center, so every existing divider renders exactly as it did. It is a component-scoped attribute, distinct from the reserved width and align layout attributes, which are unchanged. Both renderers emit the same mk-divider--label-left / mk-divider--label-right modifier class, and only for the non-default values, so doc.css still covers both.
  • A fit width preset (@markii/stdlib, @markii/react, @markii/html): width=fit shrinks a block to its own content instead of filling the column, and the matching :::fit wrapper does the same for plain markdown that has no attributes to write on. The width scale now reads fit, narrow, normal, wide, full, and WIDTH_PRESETS is listed in that order, which is also the order a completion popup offers the values in. Pairing it with an alignment is the point: {width=fit align=right} hugs the content and sits right, because a box narrower than its container is what gives the alignment margins room to work. Both renderers pick up mk-width-fit from the shared preset list with no class map of their own to edit, and doc.css carries the one new rule.
  • Reworded the reserved align attribute's documentation (@markii/stdlib): Completion and hover now say that align places the block when it is narrower than the page, and that it should be paired with a width. The behavior is unchanged.
  • Inserting a container inside a container lengthens the enclosing fences (VS Code extension, Obsidian plugin): Nesting needs the outer fence pair to carry more colons than the inner one, which until now the author had to widen by hand. Both hosts now do it in two places only: the Insert Component command, and accepting a container from the completion popup. Never while typing. The rewrite lands in the same undoable edit as the insertion, and cascades outward only as far as it has to, leaving an outer pair alone once it is already long enough. It is quiet either way: a document whose fences do not pair cleanly from the top, or that has a ::: line inside a code block or a...
Read more

v0.9.0

Choose a tag to compare

@github-actions github-actions released this 31 Aug 03:50
v0.9.0
e56259c

Release Notes - Version 0.9.0

Release Date: August 31, 2026

Summary

This release introduces comprehensive directive completion and hover support across both the VS Code extension and Obsidian plugin, adds a versatile new divider standard component, and centralizes layout attributes as data within @markii/stdlib. It also fixes an issue where prose colons were incorrectly parsed as text directives, ensuring clean text handling for times, ratios, and key-value pairs.

Added

  • Directive completion and hover in both hosts: VS Code extension and Obsidian plugin; shared logic in the private host package. Typing an opener suggests component names in the forms the component's kind allows; inside the braces it suggests the component's attributes plus the reserved width and align, and enumerated values for attributes that have them. Accepting a name inserts the same skeleton the Insert command builds. VS Code also shows hover documentation for a directive name. Pack components complete by name and description; declaring kind in pack.json narrows which forms offer them.
  • A divider standard component (@markii/stdlib, @markii/react, @markii/html): a leaf directive for a section break that carries a label or a chosen look: ::divider, ::divider{label="Part 2" variant="dots"}. variant is one of line, dots, or ornament, defaulting to line when absent or unrecognized; label is optional and, when present, is centered in the break and also carried as the separator's aria-label. Both renderers emit the same mk-divider separator markup, so doc.css covers both, and the insert catalog, directive completion, and hover documentation pick it up from STANDARD_COMPONENTS automatically. A plain --- thematic break keeps its own CommonMark meaning and is untouched.
  • **@markii/stdlib: a neutral layout.ts**: exporting the docs/format.md layout system as data — LAYOUT_ATTRIBUTE_KEYS (width, align), WIDTH_PRESETS (normal, narrow, wide, full), ALIGN_PRESETS (left, center, right), and LAYOUT_ATTRIBUTES, the same two attributes expressed as AttributeSchemas so a tool that documents or completes attributes reads them exactly like a component's own. This is the one source both renderers' layout.ts now build their class maps from, replacing two independently hand-copied literals.

Changed

  • **@markii/react and @markii/html: the reserved layout-attribute keys and preset values now come from @markii/stdlib**: instead of a hand-copied literal in each renderer's own layout.ts. Each renderer's width/align class map is now derived mechanically from @markii/stdlib's preset lists (mk-width-<preset> for every width preset but normal, mk-align-<preset> for every align preset). No behavior change: the produced classes, the normal-is-classless rule, and the null-prototype defense against a hostile value are exactly as before.

Fixed

  • @markii/core: a prose colon no longer parses as a text directive: Previously any single colon could open a text directive, so a clock time (12:34), a Bible verse (John 3:16), a ratio (a:b), or a key:value pair was misread as a directive and every renderer showed an "unknown component" fallback box in the middle of an ordinary sentence. A text directive is now recognized only when its name starts with an ASCII letter and the colon sits at a word start (the start of the document, or preceded by anything other than an ASCII letter or digit). A colon that fails this rule is left as plain text, byte-identical to the source. Leaf (::) and container (:::) directives are unaffected, since they only ever occur at the start of a line.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.9.0

All eight packages, if you want them explicitly:

npm install @markii/core@0.9.0
npm install @markii/stdlib@0.9.0
npm install @markii/bundle@0.9.0
npm install @markii/pack@0.9.0
npm install @markii/runtime@0.9.0
npm install @markii/lua@0.9.0
npm install @markii/react@0.9.0
npm install @markii/html@0.9.0

Downloads

The attached tarballs are the packed npm packages. The names are stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz

v0.8.1

Choose a tag to compare

@github-actions github-actions released this 30 Aug 01:17
v0.8.1
3045f2a

Release Notes - Version 0.8.1

Release Date: August 30, 2026

Summary

This release resolves a component rendering issue in @markii/react where declared component kinds were ignored during compilation, ensuring that inline pack components now correctly map to their designated format.

Fixed

  • **@markii/react: loadPack now derives a registry entry's inline flag from the manifest's declared kind**: a kind: "inline" pack component previously rendered as the spec §4 rule 8 form-mismatch fallback when written in its own declared form, because the compiled registration script stamped every entry inline: false. The manifest's kind now overrides the module's flag (inline for kind: "inline", block for leaf and container); an entry whose manifest declares no kind keeps the module's own flag and renders unchanged, exactly as before. The generated registration script (@markii/host, private) also bakes the truthful per-component flag into the artifact.

Install

The renderer pulls the rest in as dependencies:

npm install @markii/react@0.8.1

All eight packages, if you want them explicitly:

npm install @markii/core@0.8.1
npm install @markii/stdlib@0.8.1
npm install @markii/bundle@0.8.1
npm install @markii/pack@0.8.1
npm install @markii/runtime@0.8.1
npm install @markii/lua@0.8.1
npm install @markii/react@0.8.1
npm install @markii/html@0.8.1

Downloads

The attached tarballs are the packed npm packages. The names are stable across releases, so the latest of each is always at a fixed URL:

https://github.com/markii-org/markii/releases/latest/download/markii-core.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-stdlib.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-bundle.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-pack.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-runtime.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-lua.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-react.tgz
https://github.com/markii-org/markii/releases/latest/download/markii-html.tgz