Commit Graph
81 Commits
Author SHA1 Message Date
hyper 264038e27c fix(markdown): keep hyphenated block attribute keys
The key pattern \w+ could not cross a hyphen, so data-config=foo was parsed as config=foo and the data- prefix was lost. Allow hyphens in keys, matching parseDirectiveAttrs.
2026-09-12 23:44:43 +08:00
hyper e838f9a4b1 fix(journal): tokenize bare dice notation
The tokenizer only recognized dice when the pattern started with a count (3d6), so a bare d20 fell through to the identifier branch and failed as an unknown identifier. Add a dedicated branch for the bare d-form; DICE_RE already accepted it.
2026-09-12 23:44:24 +08:00
hyper 3532be2335 fix(journal): re-publish only changed declarations
topoSortAffected followed declared dependencies even when they were not in the affected set, so reevaluateDependents re-evaluated and re-published variables that had not changed. This could also overwrite a value just set via /set with the declaration's own expression.
2026-09-12 23:44:06 +08:00
hyper f17f09a8c4 refactor(components): remove md-commander widget
The journal now owns command history and tracking, so retire the md-commander widget. Its dice engine was extracted to src/components/dice in the previous commit.

Removes the custom element, tracker/command stores, completions, useCommander, Emmet parser, the doc entry, test fixtures, and the known-element catalog entry (reference docs regenerated).

BREAKING CHANGE: :md-commander is no longer a known element; content using it now fails tttk check with TTTK-D001.
2026-09-12 23:29:26 +08:00
hyper fadfd4cba6 feat(declare)!: parse role=declare blocks as YAML
Replace the tag/threshold/key/expr CSV body with YAML `vars:` and
`tags:` maps. `parseDeclare` validates the body with an exported Zod
schema and returns the same declaration and modifier shapes the
reactivity engine already consumes.

The breaking rename from `parseDeclareCsv` updates the registry, the
journal re-exports, and the `tttk check` role checks, where R003 now
reports schema errors with their path and R004 warns when a block
declares nothing.
2026-09-12 22:50:48 +08:00
hyper 16f2038fd8 fix(journal): unify $var lookup and error
EvalContext.lookup now receives the full $var name, matching getCombined,
setBase, and getMods, and parseFactor throws "Unknown variable" when the
lookup returns undefined. /set and /roll use the new resolveVariable() so a
typo errors instead of silently evaluating to 0.

Declarations and tag modifiers stay lenient (unknown -> 0): the documented
$hp = $con*5+$mod_hp pattern depends on external/undeclared variables
defaulting to 0.
2026-09-12 22:34:12 +08:00
hyper 02442a1100 fix(journal): re-init reactivity and drop var del
Make the reactivity engine re-initialize when the loaded declarations
change instead of only at import. ensureReactivity() reads the live
completions signal, compares a signature, and rebuilds from the store
(with exact bases) only when needed; dispatchCommand calls it before each
dispatch. Remove the unused DispatchContext.declarations/tagModifiers
fields, which were mount-time snapshots and could not be trusted.

Build initReactivity's maps into locals and commit only after the
circular check passes, so a failed re-init leaves the previous engine
intact; clear inFlight on commit.

Drop the unreachable var "del" action from the schema, render, and
reducer.
2026-09-12 22:29:25 +08:00
hyper 9f372fa2b0 fix(journal): surface variable eval errors
Collect and report failed declarations, failed tag modifier expressions, and
circular dependencies instead of swallowing them. Diagnostics are deduped,
logged with key/expression context, cleared on re-init, and exposed through
useJournalCompletions and the VariableView warning banner. A bad declaration
no longer aborts the rest of a cascade.

Reject malformed numeric literals in the tokenizer so inputs like "1.2.3"
throw instead of being truncated by parseFloat.
2026-09-12 22:22:18 +08:00
hyper a26d53cbeb fix(journal): keep variable bases in the stream
The stream only carried combined values, so hydrating a session lost the raw base and rebuildReactivityFromStore re-applied tag modifiers on top of already-combined values (e.g. $hp 70 became 90).

Publish the raw base alongside the combined value on var messages, persist it in variableBases, and rebuild engine state from exact bases. Derive tag activations from base tagmaps so tagmap-valued modifier targets are not re-triggered on every rebuild.

Seed declared variables only after hydration and only for keys absent from the store, so persisted values are no longer clobbered on load and reloads stop appending duplicate var messages.
2026-09-12 21:59:45 +08:00
hypercross d8ccaecade chore(skill): Own tttk-authoring in the repo
Move the skill to .agents/skills/tttk-authoring and point gen:skill-reference at it. Activate it by symlinking ~/.agents/skills/tttk-authoring to the in-repo copy.

Extend the reference drift guard to cover the skill copy now that it is versioned, and document activation in docs/development.md.
2026-09-12 17:19:38 +08:00
hypercross 6d94a99b42 docs(skill): Generate the tttk reference catalog
Enrich known.ts with element/role details, inline specs, and dice notation, and render them from reference.ts. Add gen:skill-reference and ~ expansion in --out so the skill copy can be regenerated.

The skill's reference.md is now generated; its extra authoring content moved to layout.md, yaml-tag.md, csv.md, and markdown.md.
2026-09-12 17:13:42 +08:00
hypercross 71542e7453 feat(cli): Complete the check rule catalog
Add D002 (malformed attribute blocks), R004 (skipped declare rows), and V001-V005 (CSV data files). CSV checks run once per referenced file and also cover inline spark-table bodies.

Generate docs/reference.md from the known.ts catalog via npm run gen:reference, and add drift guards asserting the catalog matches the customElement call sites and the committed reference.
2026-09-12 17:01:49 +08:00
hypercross ca6d8d1d14 docs(cli): Remove duplicated doc comment 2026-09-12 16:42:39 +08:00
hypercross 9def4d17aa feat(cli): Add tttk check validator
Statically validate a directory of tttk documents and report structured diagnostics with file/line positions, exit codes, and --json output. Checks cover code-block roles, unresolved content references, tag blocks, element names, links, anchors, and assets. Runs over the same content registry as the app.
2026-09-12 16:38:21 +08:00
hypercross d1384c2ccc refactor(cli): Share the content-index walk
Extract readContentIndex from buildRegistry so the validator can read raw files while the server keeps the scanned registry, both from one walk.
2026-09-12 16:38:05 +08:00
hypercross d6ea385a26 fix(cli): Mark compile as an unimplemented stub 2026-09-12 16:22:22 +08:00
hypercross 9b83123b6e fix: heading scan skips code fences; unify content resolution
- deriveLinks strips fenced code blocks so markdown examples don't
  produce phantom link completions
- Add resolveContentEntry returning body + path + inline flag;
  scanDocDirectives uses it instead of re-deriving resolution, and
  parseDirectiveAttrs is replaced by the shared parseBlockAttrs
- Fix relative file refs with ./ prefix never resolving through
  resolveContent (pathIndex lookup joined the ./ verbatim)
2026-09-08 22:30:14 +08:00
hypercross b7a804f1cf refactor: remove as= override and render data-spark at runtime
- Drop resolveBlockAs and the as= attribute; scanDoc now switches
  directly on role and warns on unknown roles instead of silently
  stripping
- md-table derives data-spark from its loaded CSV via
  parseSparkTableCsv; delete injectSparkDirectives and the second
  registry pass so pathIndex is exactly scanDoc output
- Align spark-table dice header regex with isSparkTableHeader
2026-09-08 22:18:12 +08:00
hypercross 256c685f6c refactor: remove implicit content sniffing and table conversion
- Split loadCSV into parseCSVString (content) and loadCSVFromPath
  (path); drop isCSV/looksLikeCsv heuristics
- Delete coerceSparkTables and markedTable label-header magic;
  plain markdown tables now render as plain tables
- Add explicit markdown role=spark-table fence syntax that converts
  pipe tables to CSV at scan time, with dice-header validation
- Map ESM-only github-slugger and csv-parse browser build to CJS in
  jest config; add content-registry tests
2026-09-08 21:33:12 +08:00
hypercross 638e8f6526 refactor(markdown): unify yaml tag block syntax on role=tag
Drop legacy yaml/tag info string; tag blocks now require
```yaml role=tag. Add fence-line tag=/id= attributes that
override YAML body values, and move parseBlockAttrs to
src/markdown/block-attrs.ts so scanner and render extensions
share one parser.
2026-09-08 20:56:14 +08:00
hypercross 80e2b5b209 fix(yaml/tag): prevent yaml role=tag from being stripped & generalize
data-config
2026-09-03 10:39:05 +08:00
hypercross 7c4865ba8c feat(journal): var stuff 2026-09-01 15:39:36 +08:00
hyper c03528a293 feat: Unify spark table detection and content resolution
Export isSparkTableHeader from content-registry and use it in both CLI
and frontend table parsing. Add resolveContentRef to resolve content
references consistently. Write processed registry content back to the
file index so browser mode renders identically to CLI mode.
2026-08-07 13:15:51 +08:00
hyper 0a68122efd refactor(cli): centralize content registry building
Extract buildRegistryFromIndex and normalizePathKey from the CLI serve
command and the browser completions module into the shared
content-registry module. This ensures both paths produce identical
pathIndex/docContent, including the spark-injection pass that was
previously only applied in the CLI.
2026-08-07 12:46:08 +08:00
hyper e8aa7165cb refactor(completions): centralize content scanning
Add a browser-safe ContentRegistry owning path and inline content
stores, then derive completions from it. Remove the old block-processor,
directive-scanner, and link-source modules in favor of scanDoc,
deriveCompletions, and injectSparkDirectives, and register an inline
resolver for the frontend file index.
2026-08-07 12:17:35 +08:00
hypercross 7cb28e631e feat: add threshold support and tagmap support to variable system
Introduce a `threshold` column to tag modifiers in CSV declarations,
allowing modifiers to activate only when a tag's count meets a minimum
requirement.

Implement support for "tagmap" variables (e.g., `#warrior:1;#druid:2`)
which allow for complex, multi-tag state tracking. These variables
can receive specialized tagmap modifications rather than simple
numeric additions.
2026-07-13 15:09:50 +08:00
hypercross d74ba69fdf refactor: merge /spark command into /roll
Consolidate the `/spark` command into `/roll` to simplify the CLI.
The `/roll` command now handles both dice notation and spark table
slugs.

- Update `parseInput` to treat `/roll` arguments as a generic string.
- Update `dispatchCommand` to check for spark table matches before
  evaluating dice notation or variable expressions.
- Update command completions to show both dice and spark table
  suggestions under `/roll`.
- Update documentation and UI placeholders to reflect the change.
2026-07-13 14:43:55 +08:00
hypercross ffa023b92a refactor: optimize reactive variable updates and parsing
- Replace `scanDeclareBlocks` with `parseDeclareCsv` in block processor
- Add error handling for declare block parsing
- Optimize `ReactiveVariableManager` by pre-computing variable keys
- Store template text and keys in data attributes for faster updates
- Adjust `VariableView` popup width via CSS class
2026-07-13 11:13:07 +08:00
hypercross c106b6f79c test: add variable system tests and jest config updates
- Add comprehensive tests for variable system, including parsing,
  expression evaluation, and reactivity.
- Add `moduleNameMapper` to `jest.config.js` to resolve `.js` imports
  to `.ts` source files.
- Add a mock for `csv-parse/browser/esm/sync` to support Node-based
  testing.
2026-07-13 11:08:48 +08:00
hypercross 2c762b0411 refactor: move block scanning logic to shared module
Import `FENCED_BLOCK_RE` and `parseBlockAttrs` from `block-scanner.js`
instead of defining them locally in `declare-parser.ts`.
2026-07-13 10:49:40 +08:00
hypercross f172da378a refactor: unify declare block scanning between CLI and client
Introduce `scanDeclareBlocks` in `declare-parser.ts` to provide a
single source of truth for parsing `role=declare` blocks. This
replaces redundant scanning logic in both the CLI and the journal
completions.

Also remove unused `dice.ts` and `spark-scanner.ts` files.
2026-07-13 10:43:44 +08:00
hypercross ae44191b28 refactor: use csv-parse for declare block parsing
Replace manual CSV splitting with `csv-parse` to allow for
order-agnostic columns and better handling of quoted values.
The `tag` column is now optional.
2026-07-13 09:38:09 +08:00
hypercross 981c829d0f refactor: replace stat-parser with declare-parser
Replace the old stat-parser logic with a new declare-parser to handle
variable declarations and tag modifiers. This includes moving the
declare-parser logic to a shared location in cli/completions to avoid
duplication between the CLI and the journal component.
2026-07-12 19:14:35 +08:00
hypercross 736bcf4bb2 feat: add ReactiveStatManager for markdown template support
Introduce ReactiveStatManager to allow dynamic stat replacement within
rendered markdown content. This component scans the article DOM for
`${key}` patterns and reactively updates them based on the journal
stream.

As part of this change, the SVG-based StatSheet system is removed in
favor of this more flexible text-based approach.
2026-07-12 13:32:49 +08:00
hypercross 2068ecad10 feat: add remix mode for spark table rolling
Introduces a `remix` option that allows each data column in a spark
table to be rolled independently. This is enabled via a `remix=true`
attribute in the directive's extra attributes.

Also refactors spark table scanning by moving markdown parsing logic
from the frontend to a new CLI-side `spark-scanner.ts` utility,
improving separation of concerns.
2026-07-11 11:58:01 +08:00
hypercross 719bb6ad8a refactor: use CSV path instead of markdown file for spark tables
Switch the spark table resolution logic to use the direct path to the
backing CSV file rather than attempting to parse the containing
markdown file. This simplifies the lookup process and improves
reliability.

Also refactor `SparkTableMeta` to store rows as objects keyed by
header instead of raw string arrays.
2026-07-11 11:45:38 +08:00
hypercross 841fbc7bae refactor: simplify spark table detection logic 2026-07-11 09:56:18 +08:00
hypercross d4ebca5fd0 refactor: move spark table parsing to directive scanner
Relocate spark table logic from the block processor to a dedicated
directive scanner. This allows spark tables to be treated as
`:md-table` directives and ensures they are processed in a second pass
after the content index is fully populated.
2026-07-10 15:55:45 +08:00
hyper a20063c624 refactor(cli): Extract shared deck and frontmatter utils
Create deck-utils.ts and frontmatter/shared.ts to consolidate
duplicated logic. Rename ensure-deck-preview.ts to preview-deck.ts.
2026-07-09 14:31:08 +08:00
hyper 06c3916a95 feat: rename project to TTTK
- Update package name and CLI binary to 'tttk'
- Revise documentation to reflect new name
- Add default serve behavior when no subcommand is given
- Add directory existence check in serve command
- Refactor inline comments to Chinese
2026-07-09 14:14:45 +08:00
hypercross 30d1c5dc1b feat: add support for stat sheet SVG rendering
Introduces the ability to discover and render `*.sheet.svg` files.
These files can contain `<text>` elements with `${key}` templates
that reactively update based on the current journal stats.

- Add `StatSheet` type and CLI scanning logic
- Implement `SheetView` for rendering SVGs with live bindings
- Add `parseSheet` utility to extract template patterns from SVG
- Update file indexer to include `.svg` files
2026-07-09 12:04:25 +08:00
hypercross 4f3b03d082 feat: support custom labels for stat modifiers
Allows passing an optional label to `parseStatModifiers` to override
the default ID-based label. This enables more descriptive names in
the UI and improves how modifier labels are derived in the journal
view.
2026-07-09 11:28:17 +08:00
hypercross ef71a43f0a feat: add stat-modifiers role for automatic stat generation
Introduces a new `stat-modifiers` CSV role that simplifies the
creation of template stats and their associated modifier stats.
A single CSV block now automatically generates:
- A template stat definition.
- Multiple modifier stat definitions (prefixed with the template ID).
- The corresponding template table.

This reduces the need for manual YAML definitions for every
modifier associated with a template.
2026-07-09 11:16:39 +08:00
hypercross a4cfcde613 refactor: consolidate block processing logic
Introduce a centralized `block-processor` and `block-scanner` to
handle markdown fenced code blocks. This replaces the previous
`inline-blocks.ts` and individual completion sources with a unified
approach that handles block stripping, directive replacement, and
metadata extraction (stats, templates, and spark tables) in a single
pass.
2026-07-09 10:56:54 +08:00
hypercross 1c69bf394c feat: add support for stat templates
Introduces a new `template` stat type that allows for table-based
lookups via CSV blocks in markdown files. When a template stat is
rolled, it uses a dice expression defined in the template to select
an entry, applies a label, and automatically updates associated
modifier stats using relative values.
2026-07-09 10:26:54 +08:00
hypercross 19c66640b5 refactor: extract stat parsing logic to shared module
Move YAML and CSV stat parsing logic from CLI and journal components
into a new shared `stat-parser.ts` module to enable reuse between
the CLI scanner and the client-side frontend.
2026-07-09 10:00:17 +08:00
hypercross ef8b56e5b6 feat: add stat completion source
Implement a new completion source that extracts stat definitions
from markdown files using `yaml` or `csv` code blocks with
`role=stat`.
2026-07-09 09:52:34 +08:00
hypercross ae3045f96b fix(cli): preserve inline blocks without file or as attributes 2026-07-08 16:49:01 +08:00
hypercross 749b1a6a4b feat: support multiple attributes and as directive in inline blocks
Update the inline block parser to support arbitrary key-value pairs.
If an `as` attribute is provided, the block is replaced with a
directive (e.g., `:directive[path]{attrs}`) instead of being
stripped. If no `as` attribute is present, the block is removed.
Additionally, filenames are now automatically generated using a
content hash if the `file` attribute is missing.
2026-07-08 16:02:19 +08:00
hypercross 2a9eee6410 feat: extract and index inline file blocks in markdown 2026-07-08 15:46:19 +08:00