Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
346 commits
Select commit Hold shift + click to select a range
ec614c7
fix(journal): show [esc] in the empty-journal footer so a new user ca…
pro-vi Jun 13, 2026
cd8aa3b
fix(input): scroll the text field horizontally to keep the cursor vis…
pro-vi Jun 13, 2026
2dd4bf3
test(input): lock the cursor-stays-visible invariant across all posit…
pro-vi Jun 13, 2026
6e33488
fix(journal): keep the selected reading on screen when the terminal s…
pro-vi Jun 13, 2026
fd53d19
fix(journal): stop the image preview from overrunning the scroll indi…
pro-vi Jun 13, 2026
745336f
test(journal): lock the cursor-clamp when a search shrinks the result…
pro-vi Jun 13, 2026
1a30ea8
test(journal): lock mode mutual-exclusivity (no two modes live at once)
pro-vi Jun 13, 2026
e8adb4f
fix(journal): record note-save failure per-note, not per-entry
pro-vi Jun 13, 2026
567cad1
test(journal): lock that failed notes are excluded from search
pro-vi Jun 13, 2026
bdb2a26
fix(patterns): make the derivation independent of input entry order
pro-vi Jun 13, 2026
1c58abd
test(patterns): pin five more cross-field invariants in the fuzz loop
pro-vi Jun 13, 2026
9169cc3
fix(journal): replay the exact selected reading, not a date-key lookup
pro-vi Jun 13, 2026
fa2f2f0
fix(journal): 'show <date>' surfaces the day's latest reading by time…
pro-vi Jun 13, 2026
17e1392
test(journal): lock the field's frequency gradient to rise in luminan…
pro-vi Jun 13, 2026
ce01c11
test(journal): extend the field luminance lock to bg < dimmed (unseen…
pro-vi Jun 13, 2026
2de2e6b
test(journal): lock the field tiers distinct after 256-colour quantis…
pro-vi Jun 13, 2026
6c6b4b4
fix(patterns): drop non-integer changing positions; make field.recent…
pro-vi Jun 13, 2026
eb4cd55
docs(storage): document latest()'s append-order assumption
pro-vi Jun 13, 2026
cd54a51
test(reading-flow): lock that replaying a reading does not re-append it
pro-vi Jun 13, 2026
ba89c28
test(reading-flow): lock that the journal and daily cache record the …
pro-vi Jun 13, 2026
5775e22
test(journal): lock that a note attaches to the cursor's reading, not…
pro-vi Jun 13, 2026
6dcaddd
fix(journal): no NaN scroll indicator on a sub-chrome terminal
pro-vi Jun 13, 2026
aaf2df8
test(journal): lock note-vs-indicator reservation against emoji/ZWJ/C…
pro-vi Jun 13, 2026
d7aa285
fix(storage): latest() and stream() agree on lone-CR line endings
pro-vi Jun 13, 2026
a809f0f
feat(journal): orient the empty journal with a quiet line
pro-vi Jun 13, 2026
9275525
test(journal): lock that replaying a reading opens settled, not re-an…
pro-vi Jun 13, 2026
ca80695
test(journal): lock that the dict detail hydrates cast history from t…
pro-vi Jun 13, 2026
68c47e5
test(journal): lock 'journal show today' — the CLI daily anchor
pro-vi Jun 13, 2026
0e485e0
test(journal): make the patterns 'resets when closed' test actually v…
pro-vi Jun 13, 2026
45a113c
fix(reading): persist a cast best-effort — never crash at the reveal
pro-vi Jun 13, 2026
16fff7c
fix(journal): opening an unreadable journal opens empty, never crashe…
pro-vi Jun 13, 2026
2edf1cf
fix(journal): calm CLI error when the journal file can't be read
pro-vi Jun 13, 2026
1bac292
fix(cache): an unreadable daily cache starts fresh, never crashes sta…
pro-vi Jun 13, 2026
5a4fd90
fix(config): an unreadable config starts with defaults, never crashes…
pro-vi Jun 13, 2026
199a5d7
fix(journal): an unreadable notes sidecar drops notes, never the read…
pro-vi Jun 13, 2026
e1478a6
fix(doctor): report an unreadable journal as a failed check, never cr…
pro-vi Jun 13, 2026
4aa098f
fix(hook): persist best-effort — a blocked data dir never crashes the…
pro-vi Jun 13, 2026
49c413e
fix(journal): CLI 'note' write failure is a calm error, not a raw EIS…
pro-vi Jun 13, 2026
0a20532
fix(intention): strip control chars from single-char input, not just …
pro-vi Jun 13, 2026
46e2040
fix(dict): strip control chars from browse-search single-char input
pro-vi Jun 13, 2026
0303f13
fix(journal): an unknown cast method shows its name, never 'undefined'
pro-vi Jun 13, 2026
79d094f
fix(storage): a non-string timestamp no longer crashes journal list
pro-vi Jun 13, 2026
383b17c
fix(storage): reject semantically-false casts, not just mis-shaped ones
pro-vi Jun 13, 2026
6bcc01c
fix(journal): plain digest says "1 active day", not "1 active days"
pro-vi Jun 13, 2026
02d4e87
fix(journal): strip terminal control sequences from stored text at ev…
pro-vi Jun 13, 2026
255ab8c
fix(cast): strip control sequences from a replayed reading's stored i…
pro-vi Jun 13, 2026
146c469
fix(journal): don't pair an all-readings count with a method-marked c…
pro-vi Jun 13, 2026
7753016
fix(language-gate): residue scan now covers the FULL rendered corpus,…
pro-vi Jun 13, 2026
3535eb9
fix(input): bound the incomplete-escape buffer, like the paste buffer
pro-vi Jun 13, 2026
1cb9736
test(yarrow): pin the simulation to the authentic 1:5:7:3 distribution
pro-vi Jun 13, 2026
651b6a8
test(coin): pin the coin method to its 1:3:3:1 distribution too
pro-vi Jun 13, 2026
9111b9c
fix(dict): restore the terminal if the interactive dict session crashes
pro-vi Jun 13, 2026
ca05c68
fix(doctor): validate config and cache, not just check they exist
pro-vi Jun 13, 2026
4b2bf60
fix(cast): singularize "line" when exactly one line moves
pro-vi Jun 13, 2026
cee7309
fix(cast): assembleCast rejects a non-six-line array instead of corru…
pro-vi Jun 13, 2026
fdd056c
fix(core): hexagramByBinary/hexagramByKW honor their Hexagram return …
pro-vi Jun 13, 2026
440d5e3
docs(yarrow): rightRemainder can be 0 on a manual boundary split, not…
pro-vi Jun 13, 2026
29fcd1b
fix(input): validate UTF-8 continuation bytes — a truncated lead no l…
pro-vi Jun 13, 2026
99ec026
fix(input): a malformed CSI/SS3 no longer swallows a following sequence
pro-vi Jun 13, 2026
312a3f6
fix(terminal): harden the diff renderer as the output boundary
pro-vi Jun 13, 2026
44aa452
fix(journal): align patterns-pane reflow gate with the render budget
pro-vi Jun 13, 2026
bea002e
test(journal): pin the occupancy chance law at journal scale
pro-vi Jun 13, 2026
f064e7c
fix(cli): journal show surfaces the moving lines, not just the becoming
pro-vi Jun 13, 2026
e3fea71
test(journal): guardrail the patterns-pane shared label column
pro-vi Jun 13, 2026
2e25511
fix(cli): journal list names which lines moved, matching the TUI list
pro-vi Jun 13, 2026
f5437b5
fix(cli): journal note --date annotates the day's reading, matching show
pro-vi Jun 14, 2026
3bebb06
fix(dict): show the Chinese glyph in the Derived section in English mode
pro-vi Jun 14, 2026
1a86ad4
fix(core): castsPerActiveDay rests on the date-parseable population
pro-vi Jun 14, 2026
58d14ac
fix(cli): journal show/note --date validate the date, matching list/p…
pro-vi Jun 14, 2026
562c561
fix(terminal): patterns echo row keeps the count, dropping the name w…
pro-vi Jun 14, 2026
dfb4bc6
fix(cast): reading hint says "the upper speaks", not "governs"
pro-vi Jun 15, 2026
c94e062
feat(toss): drop the casting-surface line for a more minimal toss
pro-vi Jun 15, 2026
3e4c40f
feat(cast): [r] toggles the changing-line reading in the result
pro-vi Jun 15, 2026
92b7df9
test(cli): pin runCli subprocess to UTC so daily-anchor tests don't f…
pro-vi Jun 15, 2026
58dd845
fix(cast): advertise [r] reading toggle in the result footer
pro-vi Jun 15, 2026
a81face
refactor(cast): drop the reading-method hint; read the lines top-down…
pro-vi Jun 15, 2026
8d3e461
feat(cast): hide the reading by default; [r] reveals it
pro-vi Jun 15, 2026
b08666d
feat(cast): canonical 啟蒙 reading for 3/4/5 + a per-case method hint
pro-vi Jun 15, 2026
826be38
feat(core): add Wilhelm-interpretive judgments; unify the reading pan…
pro-vi Jun 15, 2026
b36bbf3
fix(core): tighten 10 Wilhelm judgments after a dual faithfulness review
pro-vi Jun 15, 2026
67e5bd5
feat(cast): blank line between oracle blocks in the reading panel
pro-vi Jun 15, 2026
003d049
fix(core): tighten 7 more Wilhelm judgments (GPT-Pro passes on 27–64)
pro-vi Jun 15, 2026
64fc97f
fix(cast): gap before the footer (not between judgments); glyph-label…
pro-vi Jun 15, 2026
9c8148b
fix(terminal): own the mouse wheel so scrolling never navigates
pro-vi Jun 15, 2026
fd327ef
refactor(terminal): de-duplicate the cursor-key and 爻辭-line mappings
pro-vi Jun 15, 2026
cecadf1
fix(reading): one canonical 啟蒙 reading shared by TUI, plain, and JSON
pro-vi Jun 15, 2026
1eb1756
fix(cli): journal show reads the same 啟蒙 reading as the fresh cast
pro-vi Jun 15, 2026
d3370b8
fix(cli): the reading speaks Wilhelm, matching the TUI panel
pro-vi Jun 15, 2026
10782c0
fix(storage): isCastShaped reconstructs from lines — reject false rea…
pro-vi Jun 15, 2026
12433f9
fix: doctor --json exit code + lock gcEnW and extra in the language gate
pro-vi Jun 15, 2026
a2415ca
fix(hook): recover today's reading from the journal when the cache is…
pro-vi Jun 15, 2026
4860208
fix(journal): historical retrospectives read as of the window end + t…
pro-vi Jun 15, 2026
260724d
fix(journal): TUI notes pin to the exact reading via a content ref
pro-vi Jun 15, 2026
90cdab9
fix(yarrow): freeze the ritual below the field floor, not just the re…
pro-vi Jun 15, 2026
ce5de87
fix(doctor): a parseable-but-shapeless cache reads as a reset, not "v…
pro-vi Jun 15, 2026
1641bf3
chore(language): classify the new doctor cache-shape warning
pro-vi Jun 15, 2026
99b6b4d
fix(reading): journal show surfaces the static 卦辭, matching the fresh…
pro-vi Jun 15, 2026
0737f65
refactor(yarrow): consolidate the field-floor gate into one shared he…
pro-vi Jun 15, 2026
88d08ae
fix(storage): atomic write derives the temp name with basename(), not…
pro-vi Jun 15, 2026
cb1faf3
test: consolidate cast fixtures into the shared @iching/core/testing …
pro-vi Jun 15, 2026
154d399
test(cli): cover the paths and hexagram commands end-to-end
pro-vi Jun 15, 2026
c3ef180
test(storage): add a journal-read benchmark; integrity-check cost is …
pro-vi Jun 15, 2026
c611f78
refactor(core): extract the journal-patterns type contract into patte…
pro-vi Jun 15, 2026
239f64d
chore: remove advisory plans/ — all four findings implemented
pro-vi Jun 15, 2026
72085d6
fix(input): Option/Alt+Backspace deletes a word instead of ejecting t…
pro-vi Jun 16, 2026
d70757a
fix(terminal): disable autowrap so a selected row's highlight can't b…
pro-vi Jun 16, 2026
6f340c1
refactor(dict): drop the trigram-pair column from the browse list
pro-vi Jun 16, 2026
4a3ff25
fix(journal): one recency comparator across list, CLI, and patterns pane
pro-vi Jun 16, 2026
b7d716d
fix(hook): read entropy config quietly so a corrupt config can't spam…
pro-vi Jun 16, 2026
b19288f
refactor(core): decompose journal patterns into concern-based modules
pro-vi Jun 17, 2026
574236d
fix(cli): note --date writes a precise content ref, not the bare date
pro-vi Jun 17, 2026
bd4b780
fix(cli): today recovers from the journal when the cache misses
pro-vi Jun 17, 2026
579be15
refactor(cli): one durable-recovery resolver for "today's reading"
pro-vi Jun 17, 2026
a6d6d20
refactor(storage): rename getHexagramHistory → loadHexagramHistory (I…
pro-vi Jun 18, 2026
490d5e9
perf(dict): scan the journal once for the King Wen walk, not per keys…
pro-vi Jun 19, 2026
38efd1f
perf(tui): memoize per-frame & per-keystroke recompute in the reading…
pro-vi Jun 19, 2026
f0001dd
fix(storage): deepen cache structure validation; canonicalize time-ke…
pro-vi Jun 19, 2026
cdb74a2
fix(cli): re-warm the daily cache on journal recovery; reconcile dura…
pro-vi Jun 19, 2026
bf867ee
feat(core): honor config.timezone in the daily anchor and phase-of-da…
pro-vi Jun 19, 2026
2cd1542
fix(hook): quiet daily-cache reads on the per-prompt surfaces (Codex P2)
pro-vi Jun 20, 2026
564ca3c
fix(cli): quiet today's config read; validate cached becoming structu…
pro-vi Jun 20, 2026
6388ddd
fix(cli): thread the configured clock into the post-cast journal path…
pro-vi Jun 20, 2026
0bdfbe3
fix(cli): exact hexagram name resolves to its KW despite trigram-fami…
pro-vi Jun 20, 2026
7da1d12
fix(storage): strip control bytes from the journal date field at the …
pro-vi Jun 20, 2026
cb3ec1c
fix(tui): cast-scene reveal polish — settle skip, clamped clock, no t…
pro-vi Jun 20, 2026
3c6f288
fix(tui): bracketed paste flushes on absolute age, not the inter-chun…
pro-vi Jun 20, 2026
56c8e54
fix: journal P3 polish — --limit/--all guard, search caret keys, re-e…
pro-vi Jun 20, 2026
4e742c3
refactor(cli): extract hexagramSummary — one friendly-keyed identity …
pro-vi Jun 20, 2026
baa28bd
refactor(cli): extract hexagramTitleLine — one plain-text hexagram he…
pro-vi Jun 20, 2026
d9fb53f
refactor(cli): extract structureLines — one upper/lower trigram block…
pro-vi Jun 20, 2026
3e6296b
refactor(cli): extract becomingLine — unify the two plain becoming-he…
pro-vi Jun 20, 2026
3b2c5a4
refactor(storage): extract warnUnreadable in the daily-cache store
pro-vi Jun 20, 2026
da82174
refactor(storage): unify both JSON stores on warnUnreadable(message)
pro-vi Jun 20, 2026
b312aaa
refactor(cli): extract rngProvenanceFor — one seed/bound/crypto rule …
pro-vi Jun 20, 2026
92c55e7
refactor(storage): extract historyFromDates — one max-date HexagramHi…
pro-vi Jun 20, 2026
0513751
refactor(core): extract kwFromLines — the shared lines→King-Wen lookup
pro-vi Jun 20, 2026
e8a2d24
refactor(tui): extract isCtrlC — one definition of the interrupt key
pro-vi Jun 20, 2026
67e9aed
refactor(core): hoist formatTime to core — one HH:MM formatter for bo…
pro-vi Jun 20, 2026
392973e
refactor(tui): journal localToday reuses core dateInZone instead of h…
pro-vi Jun 20, 2026
2a2dfe6
refactor(storage): share isRecord — the plain-object guard the JSON p…
pro-vi Jun 20, 2026
4f10198
refactor(tui): inline ellipsis truncation reuses the CJK-aware trunca…
pro-vi Jun 20, 2026
427c505
refactor(tui): extract centerCol — the centered-column math every ren…
pro-vi Jun 20, 2026
431d33e
refactor(tui): share the pace-speed ladder across the cast and yarrow…
pro-vi Jun 20, 2026
af596ff
refactor(tui): share activePaceFooter; finish the centerCol sweep (re…
pro-vi Jun 20, 2026
4572d11
refactor(tui): extract sparkBlock — one bucketing for both 觀象 sparklines
pro-vi Jun 20, 2026
36245c3
refactor(core): centralize the line-value semantics in isYangValue/is…
pro-vi Jun 20, 2026
e15b89d
refactor(tui): toss-scene reuses assembleCast instead of re-deriving …
pro-vi Jun 20, 2026
117256c
refactor(core): extract shareOf — the zero-safe fraction every patter…
pro-vi Jun 20, 2026
4d5a683
refactor(core): extract liftOf — comparison and the trigram frequency…
pro-vi Jun 20, 2026
264f20f
refactor(core): extract clamp — the two-sided Math.max/min written 16…
pro-vi Jun 20, 2026
f6477a4
refactor(test): reuse core/testing's lineOf instead of re-defining ma…
pro-vi Jun 20, 2026
a476299
refactor(test): reuse castOf for the two makeCast defs that are exact…
pro-vi Jun 20, 2026
9b70ca3
refactor(test): extract sceneCtx — 8 scene suites shared one SceneCon…
pro-vi Jun 20, 2026
7a0e0bd
refactor(test): migrate dict-navigation's makeCtx to sceneCtx, droppi…
pro-vi Jun 20, 2026
355a042
refactor(test): move the 4 byte-identical bufferText defs into testin…
pro-vi Jun 20, 2026
eb6b4b0
refactor(test): extract changingCast — 3 render suites shared one fix…
pro-vi Jun 20, 2026
df66987
fix(test): restore Cast import in timeline-builder dropped by eb6b4b09
pro-vi Jun 20, 2026
18ab9b5
refactor(test): extract settingsValues — scene-language repeated the …
pro-vi Jun 20, 2026
c36e130
refactor(test): route settings-quit-key + settings-scene through sett…
pro-vi Jun 20, 2026
9a5b480
refactor(test): move the 4 byte-identical mockStdin defs into testing.ts
pro-vi Jun 20, 2026
23e6a10
refactor(test): unify mockStdout into one capturing factory, dropping…
pro-vi Jun 20, 2026
d0660b0
refactor(test): extract staticCast — the override-based hex-63 fixtur…
pro-vi Jun 20, 2026
ab158f3
refactor(test): add cli test-support module (runCli) — migrate progra…
pro-vi Jun 20, 2026
5499025
refactor(test): migrate hexagram + paths suites to shared runCli
pro-vi Jun 20, 2026
348c096
refactor(test): migrate today-command to shared runCli (dataDir + TZ …
pro-vi Jun 20, 2026
3ddf5b8
refactor(test): route journal-command's runCli through the shared spa…
pro-vi Jun 20, 2026
3503c76
refactor(test): route main-mode-routing's two spawn sites through the…
pro-vi Jun 20, 2026
2a09f1b
refactor(test): route cast's two spawn helpers through the shared spa…
pro-vi Jun 20, 2026
e107388
refactor(test): route config-command's three spawn sites through the …
pro-vi Jun 20, 2026
6e55ddf
refactor(test): route doctor's two spawn sites through the shared spa…
pro-vi Jun 20, 2026
9ce54b2
refactor(test): finish runCli consolidation — hook-adapter via a stdi…
pro-vi Jun 20, 2026
79a9a75
refactor(core): extract isOneOf — one config-value guard for both val…
pro-vi Jun 20, 2026
22a6783
refactor(terminal): extract glyph-anim braille primitives into braill…
pro-vi Jun 20, 2026
64a6bdc
refactor(core): extract foldForSearch — one text-fold for hexagram + …
pro-vi Jun 20, 2026
2283a05
refactor(terminal): share the dict FOOTER_ROWS constant across the th…
pro-vi Jun 20, 2026
a258237
refactor(storage): extract quarantineCorrupt — one corrupt-file backu…
pro-vi Jun 20, 2026
7a53c8b
refactor(storage): share corrupt-warn-once via a closure warner
pro-vi Jun 20, 2026
0e4f579
refactor(cli): extract resolvePathsFor — one home for the --data-dir …
pro-vi Jun 20, 2026
2b607c6
refactor(terminal): single-source the ANSI CSI prefix
pro-vi Jun 20, 2026
271b4a4
refactor(terminal): share CHAR_GAP between compose and auto-size
pro-vi Jun 20, 2026
4d60037
refactor(terminal): share APERTURE_WIDTH + SWEEP_INTERVAL_MS across y…
pro-vi Jun 20, 2026
de5dc9f
refactor(storage): centralize the errno cast behind errnoCode
pro-vi Jun 20, 2026
bff2d8e
refactor(terminal): make home-menu keys typecheck instead of assertin…
pro-vi Jun 20, 2026
a04798a
refactor(terminal): fold _glyphRow into ContentLine, dropping two casts
pro-vi Jun 20, 2026
220ea2d
refactor(terminal): narrow glyph entries with .every instead of asser…
pro-vi Jun 20, 2026
973f377
refactor(cli): one formatError for displaying a caught error
pro-vi Jun 20, 2026
0f832f9
refactor(cli): one die() for the fatal print-and-exit convention
pro-vi Jun 20, 2026
0d88ee6
refactor(cli): assertConfigKey for the repeated unknown-key guard
pro-vi Jun 20, 2026
fdf4a36
refactor(cli): assertValidDateWindow for the repeated --since/--until…
pro-vi Jun 20, 2026
b5bdb77
refactor(core): kwOf — the inverse of hexagramByKW
pro-vi Jun 20, 2026
c3e9960
docs(core): explain why topShare divides raw but normalizedEntropy us…
pro-vi Jun 20, 2026
e420c1e
refactor(cli): one guarded hexagramNames for the journal JSON name block
pro-vi Jun 20, 2026
20ae11c
refactor(terminal): route 7 missed inline clamps through clamp()
pro-vi Jun 20, 2026
0adc866
refactor(terminal): extract CellBuffer.inBounds for the shared point …
pro-vi Jun 20, 2026
d49689f
refactor(terminal): share hexToRgb between sgr quantization and lerp
pro-vi Jun 20, 2026
d32c3ea
refactor(storage): single-source storage filenames + flatLayout
pro-vi Jun 20, 2026
ad9661e
refactor(core): trigramIndices — split a hexagram into its two trigra…
pro-vi Jun 20, 2026
b088ed2
refactor(core): KwGua type + withGua for the hexagram-detail derivati…
pro-vi Jun 20, 2026
3a48bf2
refactor(cli): makeDetailOpener — share the memoized openDetail handler
pro-vi Jun 20, 2026
d57a8ca
refactor(core): home lineFromValue in line-value.ts; coins stops dupl…
pro-vi Jun 20, 2026
ee31ac2
refactor(cli): latestEntryOnDate — one finder for show + note's "day'…
pro-vi Jun 20, 2026
957562e
refactor(core): matchesEitherScript for trigram-token bilingual matching
pro-vi Jun 20, 2026
adef8d5
refactor(terminal): MIN_DURATION_SCALE — name the animators' shared 0…
pro-vi Jun 20, 2026
442e143
test(storage): freshTempDir helper for the repeated mkdtemp setup
pro-vi Jun 20, 2026
669ad2e
test(cli): freshTempDir helper for the repeated mkdtemp setup
pro-vi Jun 20, 2026
fcd4ffd
test(storage): seedConfig helper for config-store fixture writes
pro-vi Jun 20, 2026
a309b17
test(storage): hoist journal-store's per-test fs imports to the top
pro-vi Jun 20, 2026
dcb9b59
test: hoist remaining per-test fs imports to top-level (finishes R97 …
pro-vi Jun 20, 2026
c300956
test(core): hoist guaci's dynamic SEQUENCE import to top-level
pro-vi Jun 20, 2026
61acca6
test(storage): appendHistory + TORN_LINE for journal-store fixtures
pro-vi Jun 20, 2026
7e5beac
test(storage): seedCache helper, mirroring seedConfig
pro-vi Jun 20, 2026
eebfed9
refactor(core): rankByShare for the two frequency summaries
pro-vi Jun 20, 2026
75da1b2
refactor(core): byFrequencyThenLift for the two distribution rankings
pro-vi Jun 20, 2026
1bfc586
refactor(core): addHexagram accumulator for freq/knownFreq
pro-vi Jun 20, 2026
3ce07d0
refactor(terminal): maxOffset for the scroll ceiling
pro-vi Jun 20, 2026
b5bd53a
refactor(terminal): lastIndex for the list-cursor ceiling
pro-vi Jun 20, 2026
d15599b
refactor(terminal): viewportFor for journal's guarded viewport math
pro-vi Jun 20, 2026
ddb470b
refactor(terminal): share viewportHeight across scenes (R112 sweep)
pro-vi Jun 20, 2026
d9721dc
refactor(cli): loadTimezone helper for the date-window subcommands
pro-vi Jun 20, 2026
e12a848
refactor(terminal): GlyphAnimatorBase superclass for the 4 reveal ani…
pro-vi Jun 20, 2026
9eb5b08
refactor(cli): methodComparison for the journal JSON distribution blocks
pro-vi Jun 20, 2026
91a0eaa
refactor(core): invertLines (錯) line-op for polarity + diagonal
pro-vi Jun 20, 2026
88a6774
refactor(core): assertIntInRange for the hexagram lookup guards
pro-vi Jun 20, 2026
bf37cbf
refactor(core): localDate for dateInZone's machine-local fallback
pro-vi Jun 20, 2026
62eba4e
refactor(terminal): colorCode for the parallel fg/bg SGR quantization
pro-vi Jun 20, 2026
c58bf3a
refactor(terminal): clearRow for the diff-renderer's row-clear sequence
pro-vi Jun 20, 2026
640c41c
refactor(terminal): reuse centerCol for the two horizontal-centering …
pro-vi Jun 20, 2026
0e2090d
refactor(terminal): finish the centerCol sweep — 7 more horizontal re…
pro-vi Jun 20, 2026
7ea9ca0
refactor(terminal): sand reuses the shared easeOut
pro-vi Jun 20, 2026
62b2693
refactor(storage): openLineReader for the journal's two line readers
pro-vi Jun 20, 2026
eb18aca
refactor(terminal): single MENU table drives home display + handling
pro-vi Jun 20, 2026
6376a6f
test(terminal): rowText helper for the rendered-row assertion idiom
pro-vi Jun 20, 2026
3be55f0
test(terminal): route inline SceneContext objects through sceneCtx
pro-vi Jun 20, 2026
415d84f
test(terminal): finish the rowText/bufferText sweep R137 left partial
pro-vi Jun 20, 2026
92a95e1
test(cli): shared seedJournal helper (was duplicated in two suites)
pro-vi Jun 20, 2026
79c091f
test: dedup utcToday + mockOutput (R140 sibling sweep)
pro-vi Jun 20, 2026
f875d51
refactor(terminal): brailleFromMask primitive for the dot-mask → glyp…
pro-vi Jun 20, 2026
964e7e1
refactor(terminal): single-source the blank braille cell (EMPTY_BRAIL…
pro-vi Jun 20, 2026
78c3505
refactor(terminal): settings preview uses isEmpty too (R145 completen…
pro-vi Jun 20, 2026
7bbdee1
refactor(storage): applyLegacyCastMode for the duplicated legacy-mode…
pro-vi Jun 20, 2026
16ace24
refactor(storage): localeBase names the POSIX locale-suffix strip
pro-vi Jun 20, 2026
d33a68e
refactor(terminal): moveCursor reuses clamp instead of inline min/max
pro-vi Jun 20, 2026
1c721e5
refactor(terminal): rgbToHex pairs with hexToRgb; lerp stops hand-bui…
pro-vi Jun 20, 2026
3ab6366
refactor(terminal): padToWidth joins measure.ts; browse stops re-deri…
pro-vi Jun 20, 2026
371bc8c
fix(tui): floor the journal list viewport like its siblings
pro-vi Jun 20, 2026
608245a
refactor(storage): remove the never-wired legacy-discovery surface
pro-vi Jun 20, 2026
cf8bc4a
test: harden weak assertions surfaced by the test-quality audit
pro-vi Jun 20, 2026
71955ba
fix(terminal): floor detail-scene viewport height (completes the sweep)
pro-vi Jun 20, 2026
8addadc
docs(storage): flag endsMidLine's EACCES degradation asymmetry
pro-vi Jun 20, 2026
0afa007
chore(release): prepare v0.5.0
pro-vi Jun 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ jobs:
- name: Prepare publish manifest
run: |
set -euo pipefail
cp README.md LICENSE publish/
cp README.md LICENSE TEXT_SOURCES.md publish/
VERSION=$(node -p "require('./package.json').version")
cat > publish/package.json <<EOF
{
"name": "@pro-vi/iching",
"version": "$VERSION",
"description": "A contemplative I Ching TUI for the terminal.",
"bin": "./iching.js",
"files": ["iching.js", "README.md", "LICENSE"],
"files": ["iching.js", "README.md", "LICENSE", "TEXT_SOURCES.md"],
"type": "module",
"engines": { "node": ">=18", "bun": ">=1.0.0" },
"keywords": ["iching", "i-ching", "yijing", "tui", "terminal", "divination", "node", "bun"],
Expand Down
42 changes: 37 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Set an intention. Cast a hexagram. Sit with what shows up.
(大象傳, 彖傳), English image and judgment, and Wilhelm-inspired notes.
- **Journal** every cast (with timestamp and intention) in
append-only JSONL — your own divination history.
- **Observe** quiet patterns over that history (`p` in the journal, or
`iching journal patterns`) — a field of all 64 lit by what you've drawn,
where movement falls, the yin/yang balance, the phase of day each was cast.
Observation, never prediction.
- **Hook into LLMs** the assistant can read your cast for further interpretation.

Raw ANSI, five hand-tuned themes (ink, bone, cinnabar, jade, river),
Expand Down Expand Up @@ -57,16 +61,42 @@ bun run build # builds dist/iching for your platform
iching # interactive TUI
iching cast # one-shot cast (plain text)
iching cast "should I ship?" # with a question
iching cast --bound "ship it?" # bind the cast to the question and moment
iching cast --json # structured output
iching today # today's reading (cast in the TUI)
iching today --json # full reading payload for scripts/assistants
iching journal list # recent readings
iching journal list --hexagram 29 # readings where hexagram 29 appears
iching journal show today # today's reading
iching hexagram 1 # look up hexagram by number
iching journal note "..." # attach a reflection note to the latest reading
iching journal patterns # quiet observation over every past reading
iching journal patterns --since 2026-01-01 --until 2026-03-31 # bound it to one season
iching journal patterns --json # the same derivation, structured for scripts
iching hexagram 1 # look up hexagram by number or name
iching dict water # open the dictionary on a search
iching dict # browse all 64 in TUI
iching config theme cinnabar # set theme
```

Press `c` to cast, `j` for journal, `d` for dictionary, `s` for
settings, `q` to quit.
Press `c` to cast, `t` to return to today's reading, `j` for journal,
`d` for dictionary, `s` for settings, `q` to quit.

### JSON for scripts and assistants

`cast --json`, `today --json`, and `journal patterns --json` emit stable,
self-describing payloads. In `journal patterns --json`, mind one contract
(the output states it in a `basis` field): **descriptive counts tally every
reading; chance figures live in `comparison` blocks computed only over the
method-marked subset** (coin/yarrow casts, whose line probabilities are known —
legacy entries have none). Never divide an all-readings `count` by an `expected`
from a `comparison` block; use that block's own `count`/`expected`, which share
a basis. (Every chance figure — including `topTrigrams` — lives in a
`comparison` block over the method-marked subset; uniform trigram geometry
still needs P(yang)=½, a property of the method, so it rests on the same basis
as the rest.) One further basis: `timeOfDay` rests on the **timestamped**
subset — its phase
counts sum to `timeOfDay.timestamped`, not `total`, since readings without a
recorded local hour are omitted rather than guessed.

## Storage

Expand All @@ -76,6 +106,7 @@ Files follow the [XDG Base Directory](https://specifications.freedesktop.org/bas
|------|------|---------|
| Cache | `~/.cache/iching/daily-cache.json` | Most recent cast |
| Journal | `~/.local/state/iching/history.jsonl` | All casts |
| Notes | `~/.local/state/iching/notes.jsonl` | Reflection notes (sidecar to the journal) |
| Config | `~/.config/iching/config.json` | Theme, motion, glyph settings |

Override with `ICHING_HOME` env var or `--data-dir` flag.
Expand All @@ -94,9 +125,10 @@ Bun workspace monorepo. Four packages:
## Development

```bash
bun test # run tests (382 tests, ~100ms)
bun test # run the test suite
bun run typecheck # tsc --noEmit
bun run smoke # end-to-end smoke test
bun run build # compile the binary for your platform
bun run smoke # end-to-end smoke test of the built binary
```

Vision notes and the current scope spec are mapped in
Expand Down
29 changes: 25 additions & 4 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
英译象辞与卦辞、以及卫礼贤风格的注解。
- **日志** 自动记录每一次起卦(含时间戳与问意),
以追加式 JSONL 保存 —— 你自己的卜筮史。
- **观象** 对这段卜筮史作静观(日志中按 `p`,或 `iching journal patterns`)——
六十四卦之野依所占点亮、动爻所在、阴阳之衡。只是观照,从不预言。
- **接入大语言模型**:助手可读取你的卦象作进一步释义。

原始 ANSI 渲染、五种手调主题(ink、bone、cinnabar、jade、river)、
Expand Down Expand Up @@ -56,15 +58,32 @@ bun run build # 为当前平台构建 dist/iching
iching # 进入交互式 TUI
iching cast # 一次性起卦(纯文本)
iching cast "该不该上线?" # 带问意起卦
iching cast --bound "该不该上线?" # 将此卦与问意及当下时刻绑定
iching cast --json # 结构化输出
iching today # 今日卦象(在 TUI 中起卦)
iching today --json # 供脚本与助手读取的完整卦象数据
iching journal list # 近期记录
iching journal list --hexagram 29 # 筛选出现第 29 卦的记录
iching journal show today # 今日卦象
iching hexagram 1 # 按卦序查阅
iching journal note "……" # 给最近一卦附上注记
iching journal patterns # 观象:对历来卦记的静观
iching journal patterns --json # 同一推演,结构化输出供脚本读取
iching hexagram 1 # 按卦序或卦名查阅
iching dict water # 以检索词打开卦典
iching dict # 在 TUI 中浏览六十四卦
iching config theme cinnabar # 设置主题
```

按 `c` 起卦,`j` 查日志,`d` 查卦典,`s` 设置,`q` 退出。
按 `c` 起卦,`t` 回看今日,`j` 查日志,`d` 查卦典,`s` 设置,`q` 退出。

### 供脚本与助手的 JSON

`cast --json`、`today --json` 与 `journal patterns --json` 输出稳定且自描述的结构。
`journal patterns --json` 有一条约定(输出中以 `basis` 字段写明):**描述性计数统计所有卦记;
理数(chance)数值则置于 `comparison` 块内,只就已注法的子集计算**(铜钱/蓍草占法,其爻变概率已知——
旧占记没有)。切勿用全量的 `count` 去除以某个 `comparison` 块里的 `expected`;应取该块自带的
`count`/`expected`,二者同基。(`topTrigrams.expected` 是唯一在 `comparison` 块之外的 `expected`——
属无关占法的几何期望,与其 `count` 同为全量基准。)

## 数据存储

Expand All @@ -74,6 +93,7 @@ iching config theme cinnabar # 设置主题
|------|------|------|
| 缓存 | `~/.cache/iching/daily-cache.json` | 最近一卦 |
| 日志 | `~/.local/state/iching/history.jsonl` | 全部卦象 |
| 注记 | `~/.local/state/iching/notes.jsonl` | 回看注记(日志的伴生文件) |
| 配置 | `~/.config/iching/config.json` | 主题、动画、字符设置 |

可用 `ICHING_HOME` 环境变量或 `--data-dir` 参数覆盖。
Expand All @@ -92,9 +112,10 @@ Bun 工作区单仓多包。共四个包:
## 开发

```bash
bun test # 运行测试(382 项,约 100ms)
bun test # 运行测试
bun run typecheck # tsc --noEmit
bun run smoke # 端到端冒烟测试
bun run build # 构建当前平台的二进制
bun run smoke # 对构建产物做端到端冒烟测试
```

## 缘起
Expand Down
24 changes: 6 additions & 18 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ document in the repository.
`iching` is a local-first terminal I Ching application:

- one-shot CLI commands for casting, journal, config, paths, doctor, and lookup
- a daily-reading anchor: the day's cast is cached and recallable without
recasting (`iching today`, TUI `t`)
- fullscreen TUI for daily casting, journal review, settings, and dictionary
- pure domain package for casts, derivations, search, and hexagram data
- JSON/JSONL storage using XDG-compatible local paths
Expand All @@ -24,34 +26,20 @@ old checkbox.
|---|---|---|
| Workspace monorepo | Implemented | `apps/cli`, `packages/core`, `packages/storage`, `packages/terminal` |
| Core domain | Implemented | casting, derivation, lookup, detail, search, formatters, exhaustive tests |
| Storage | Implemented | paths, JSON/JSONL stores, config store, legacy discovery, atomic-write tests |
| CLI commands | Implemented | `cast`, `journal`, `hexagram`, `config`, `paths`, `doctor`, `dict` |
| Storage | Implemented | paths, JSON/JSONL stores, config store, atomic-write tests |
| CLI commands | Implemented | `cast`, `today`, `journal`, `hexagram`, `config`, `paths`, `doctor`, `dict` |
| Terminal primitives | Implemented | cell buffer, diff renderer, ANSI, key parser, raw input, session lifecycle |
| Animation engine | Implemented | timeline DSL, runner, easing, presets, scene loop |
| Casting scenes | Implemented | cast scene, coin/line/morph/reveal renderers, timeline builder |
| TUI dictionary | Implemented | browse model/scene, detail model/scene, dictionary command, scene routing |
| Large glyph support | Implemented | glyph data, glyph animation modes, cast/detail integration |
| Yarrow casting | Implemented (2026-05-30) | `core/casting/yarrow.ts`, `YarrowScene` auto, `YarrowManualScene` 18-cut full-manual, ritual-chrome parity with coin |
| Distribution | Infrastructure present | build script, smoke script, CI workflow, release workflow |
| Entropy source evolution | Planned | see `docs/vision/entropy-sources-vision.md` |
| Entropy binding (`bound`) | Implemented (2026-06-10) | `core/random.ts` `BoundRandomSource` (SHA-256 length-prefixed binding of fresh crypto bytes + intention + timestamp + process nonce, hash-counter DRBG); `entropy` config key (default `crypto`); `cast --bound`; `rng` provenance on journal/cache/`cast --json`; Settings row; `bound-random.test.ts` |
| Entropy source evolution | In progress | `bound` shipped (row above); `embodied` and `quantum-remote` remain planned — see `docs/vision/entropy-sources-vision.md` |

## Active Product Questions

### Entropy Binding

Next likely scope: add a `bound` entropy path that mixes local crypto entropy
with intention/session context.

Constraints:

- keep `crypto` as the default
- use intention as salt/context, never as the sole seed
- preserve explicit deterministic `--seed`
- record provenance in JSON and journal output if the source becomes user-visible
- do not add network entropy in this step

Source: [Entropy Sources Vision](docs/vision/entropy-sources-vision.md).

### Embodied Entropy

Future scope: collect local timing/jitter during an existing ritual window and
Expand Down
42 changes: 42 additions & 0 deletions TEXT_SOURCES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Text Sources & Attribution

`@pro-vi/iching` bundles several layers of I Ching text. This file records each
source, its rights status, and what the project's MIT license does and does not
cover.

## Classical Chinese (public domain)

The hexagram judgments (卦辭), line statements (爻辭), the 小象傳, and the
序卦傳 / 雜卦傳 belong to the ancient *Zhouyi* / *Yijing* corpus. The Chinese
source text is in the public domain.

## English — Legge (`gcEn`, public domain)

The `gcEn` judgment field is the English translation by **James Legge**,
*The Yî King* (Sacred Books of the East, Vol. XVI; Oxford, 1882, rev. 1899).
Legge's translation is in the public domain.

## English — Wilhelm register (`gcEnW`, `yaoEn`) — original interpretive text

The displayed English judgments (`gcEnW`) and line readings (`yaoEn`) are
**original interpretive renderings** written for this project in the
Wilhelm–Baynes *register* (cadence and vocabulary), **distilled from
public-domain sources** — the classical Chinese 卦辭 / 爻辭, Legge's translation,
and the 彖傳 / 小象傳 commentaries.

They are **not quotations of, and are not derived from, the copyrighted
Richard Wilhelm / Cary F. Baynes English translation** (*The I Ching or Book of
Changes*, Bollingen Series XIX; 1950, rev. 1967), which remains under copyright.
This is the project's standing **AC-010** policy: ship original wording from
public-domain sources, never licensed third-party translation text.

If you believe any specific string reproduces protected expression, please open
an issue and it will be revised.

## License scope

The project's [MIT LICENSE](./LICENSE) covers the project's **code** and its
**original textual material** (including the `gcEnW` / `yaoEn` renderings). It
does **not** purport to grant rights in any third-party text. The classical
Chinese source and Legge's translation are in the public domain; no third-party
copyrighted translation is included.
2 changes: 1 addition & 1 deletion apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@iching/cli",
"version": "0.2.0",
"version": "0.5.0",
"private": true,
"type": "module",
"exports": {
Expand Down
Loading
Loading