mellos-mapping 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Layer 4 (presentation) — pure rendering of a MellosMap to terminal lines.
3
+ *
4
+ * Shared by the MCP `mmap_view` tool (monochrome) and the split-pane watcher
5
+ * (colored, animated). Pure function of (map, options): no I/O, no clock —
6
+ * animation is driven by the caller passing a spinner frame index.
7
+ *
8
+ * Visual language — a dark circuit board:
9
+ * rank 0 renders at the BOTTOM of the picture ("primitives are the
10
+ * ground"). Wiring and band bars are FAINT; the glowing things are the
11
+ * nodes. Junctions where a wire enters a box inherit the box's color,
12
+ * like lit pins. Dependency lines only ever travel downward.
13
+ *
14
+ * planned dashed dim rounded box, '·' — a ghost: designed, not built
15
+ * in-progress amber rounded box, spinner — where attention currently is
16
+ * done heavy green box, '■' — built and verified
17
+ * regressed heavy red box, '✗' — was done, foundation cracked
18
+ *
19
+ * Routing preference, in order:
20
+ * 1. STRAIGHT — an adjacent-band edge whose box borders share a free
21
+ * column is one vertical line, no corners.
22
+ * 2. DOGLEG — descend, run horizontally on a track row in the gap above
23
+ * the target band, descend. Tracks are PACKED: segments that do not
24
+ * overlap share a row, keeping bands close together.
25
+ * 3. THREAD — a skip-level edge descends through the nearest column that
26
+ * is free of boxes in every intermediate band (threading the needle
27
+ * between boxes); only if no such column exists does it fall back to a
28
+ * private column on the right margin.
29
+ * Crossings merge into proper junction characters via a direction-bitmask
30
+ * union instead of any routing cleverness.
31
+ *
32
+ * Zoom — terminals cannot scale glyphs, so zooming out first COMPRESSES the
33
+ * geometry (gaps, breathing rows, padding shrink; labels truncate toward a
34
+ * scale-proportional budget) while boxes stay boxes. Only when a further
35
+ * step would leave labels too short to mean anything does the picture switch
36
+ * mode — to a borderless glyph constellation whose band bars carry
37
+ * done/total counts. Zooming in past 100% unfolds evidence and design notes
38
+ * inside the boxes; a second step widens the boxes and unfolds the notes
39
+ * further. The ladder, one wheel tick per step:
40
+ * +2 detail+ wider boxes, design notes unfold almost fully
41
+ * +1 detail evidence + design notes unfold inside boxes
42
+ * 0 100% the standard working view (default, unchanged)
43
+ * -1 85% labels truncated to 85%, geometry still roomy
44
+ * -2 70% padding and breathing rows collapse
45
+ * -3 55% tightest meaningful boxes; band bars gain done/total
46
+ * -4 overview MODE SWITCH: borderless status glyphs, pure topology
47
+ * The same layout/routing machinery runs at every step; only the per-node
48
+ * box spec (size, border, content) and the whitespace geometry change.
49
+ */
50
+ import type { MellosMap } from '../domain/types.js';
51
+ import { type ZoomStep } from '../semantics/semantics.js';
52
+ export { type ZoomStep, ZOOM_DEFAULT, ZOOM_MAX, ZOOM_MIN, clampZoom, isNeutralKind, zoomLabel } from '../semantics/semantics.js';
53
+ export interface RenderOptions {
54
+ /** Emit ANSI color codes. */
55
+ readonly color: boolean;
56
+ /** Use box-drawing characters; false falls back to pure ASCII. */
57
+ readonly unicode: boolean;
58
+ /** Spinner frame index for in-progress nodes; caller advances it over time. */
59
+ readonly spinnerFrame: number;
60
+ /**
61
+ * Node id to spotlight: its box border and every wire touching it render
62
+ * bright instead of faint. Color mode only — monochrome output ignores it.
63
+ */
64
+ readonly focus?: string | undefined;
65
+ /** Position on the zoom ladder; omitted means ZOOM_DEFAULT (100%). */
66
+ readonly zoom?: ZoomStep | undefined;
67
+ }
68
+ /** A window over the rendered picture, in cell coordinates (0-based). */
69
+ export interface Viewport {
70
+ readonly x: number;
71
+ readonly y: number;
72
+ readonly width: number;
73
+ readonly height: number;
74
+ }
75
+ /** Terminal column width of a string (CJK chars occupy two columns). */
76
+ export declare function displayWidth(text: string): number;
77
+ /** Truncate to a display width, ANSI-free input, appending … when cut. */
78
+ export declare function fitWidth(s: string, width: number): string;
79
+ /** Hard word-wrap by display width (CJK-aware, splits anywhere). */
80
+ export declare function wrapWidth(s: string, width: number): string[];
81
+ /** Glyph for a node kind, or undefined for unknown kinds. Shared with the watcher's panel. */
82
+ export declare function kindGlyph(kind: string, unicode: boolean): string | undefined;
83
+ /** Render the whole map as terminal lines. */
84
+ export declare function renderMap(map: MellosMap, opts: RenderOptions): string[];
85
+ /** Where a node's box sits on the full (unwindowed) picture, for hit testing. */
86
+ export interface BoxHit {
87
+ readonly id: string;
88
+ readonly x: number;
89
+ readonly y: number;
90
+ readonly w: number;
91
+ readonly h: number;
92
+ }
93
+ export interface WindowedRender {
94
+ readonly lines: string[];
95
+ /** Full extent of the picture, for viewport clamping. */
96
+ readonly contentWidth: number;
97
+ readonly contentHeight: number;
98
+ /** Node hit regions in full-picture coordinates, for mouse interaction. */
99
+ readonly hits: readonly BoxHit[];
100
+ }
101
+ /** Render only the given viewport of the map, plus the full content extent. */
102
+ export declare function renderMapWindow(map: MellosMap, opts: RenderOptions, viewport: Viewport): WindowedRender;