Bring in the 65 upstream commits since 0.11.1, with ^K lock and the self chip.
Both sides kept their features. React gives way to Lock in two places. On the
PicoCalc lane, Lock keeps the Shift half of F2 and React is ^E only. In the
hint, ^E react is the first atom to go when ^K lock has no room.
The long-message code now refills the compose line with MentionEditor, which
replaced LineEditor upstream.
Typing narrows the outbox again, and its footer says so. With the scroll
atom, the footer of an entry row is wider than 72 cells, which JP
accepted. The footer line no longer cuts a hint that is too wide at the
edge, which took Esc with it: it drops atoms instead, as the splash
already did. The outbox drops "Del delete" first.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each row now carries a third column, MESSAGE, after TARGET and TRIGGER
(or OUTCOME). Nothing is shortened to fit: the rows and their headers pan
together with ←→, and the footer says so while the table runs past the
edge. The outbox no longer filters as you type, which keeps the footer
within 72 cells.
A column header that pans now pins with its section heading, as a
header that does not pan always did.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each section of the outbox now has column headers: TARGET and TRIGGER for
waiting entries, TARGET and OUTCOME for finished ones. The rows no longer
show the message. Enter on a waiting entry opens it to edit (the courier
holds the entry while the prompt is open, so the old text cannot go out
meanwhile), and Enter on a finished one shows it. Del deletes an entry
after a red confirm, and ^R sends a waiting entry now; on the PicoCalc
they ride F3 as Send, with Delete behind it. On a narrow screen a long
name gives cells to the trigger and breaks off on its crack.
The message field has the colours of the chat's compose line: a white
prompt mark and white text.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When a row was a chip followed by text (a Courier entry: the recipient,
then what it waits for) and the text ran past the screen, the cut looked
back for a chip fill, found the chip far to the left, and drew a half
block in its colour at the right edge. The crack now forms only inside
the path that the row stamps, so a cut in plain text gets the ellipsis.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The author chip of the selected message's group now turns its label white,
as the message's text does, and goes back when the selection leaves the
group. A mention of an unknown node turns white too: its grey fill already
says the node is unknown, and white reads better on it than black.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
In a channel, a DM, or a room, the selected message's text is white, and
now its mention chips follow: the label turns white and the fill stays, so
the chips still tell one node from the next. Arrow mode whitens the label
the same way. A mention that no key can place keeps its grey, as on every
selected row.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
In a channel, a DM, or a room, the chip of a sender that is a locked
contact reads 🔒 Name (⚿ on the PicoCalc), in the place of the ★ on our
own chip. The transcript cache now compares the locks, so a ^K or a lock
from the node page redraws the chips on the next paint.
The padlock is one constant, marks.LOCK_ICON, shared with the Contacts list.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
The same key as in a conversation. The row gains or loses its padlock in
place, with no confirm, and the next ^K reverses it. On the handhelds, Lock
(or Unlock) rides Shift+F2, as in a channel and a DM.
The hint names ^K only where it fits without dropping another atom. That
rule now lives in one helper, menus.splice_if_room, which the archive
preview uses too.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
In a channel, a DM, or a room, ^K toggles the lock of the contact that wrote
the selected message, so the archive sweep never takes it. The hint says
^K lock or ^K unlock, but only where it fits without dropping another atom,
and the status line confirms what the key did.
On the handhelds, Lock (or Unlock) rides Shift+F2 in a channel and a DM. A
room keeps Log in there, so the Author page that a conversation opens now
carries the lock row, and no other management verb.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Delete keeps a contact out of this sweep only. Shift+Delete removes the row
the same way and stages a lock, so no later sweep takes the contact. The
locks are written on Apply with the archive; Esc and Back ask before they
discard them. A preview left with only locks applies them without the amber
confirm.
The footer names ⇧Del lock only when the hint still fits 72 cells, and a
contact row now says Enter open, since Enter opens its node page. On the
handhelds, Lock rides Shift+F3 behind the Delete chip.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
When a laptop wakes from sleep, the kernel can reset the USB device and hang
up the open port, but keep the same device file. The next write fails with
EIO, and the serial transport closes itself. The serial liveness check read
only the OS port list, so it said the link was up: no reconnect dialog
opened, and each command failed with no_event_received (issue #32).
The serial check now also reads the meshcore client's is_connected flag,
which the client clears when its transport is lost, as the BLE and TCP
checks already did.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Off by default. Each masked value keeps a tidbit (j*********u, DA:xx:xx:xx:7C:7C,
192.xxx.x.180, m******e.local), so two radios stay two radios. The log masks each
line as it is written; diagnostics take --anonymize/--no-anonymize, and the page
toggles with `a` (Shift+F3 on the PicoCalc). Refs #31.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
meshterm --demo runs the simulator in a synthetic Montréal mesh: 14
repeaters on the high points (Mont-Royal to Mont-St-Hilaire), rooms,
sensors, and about twenty companions, all invented. A log-distance
link model decides who hears whom, so floods arrive on several real
paths and traces walk real routes.
At each start the demo writes its own directory (<config>/demo) again:
300 days of adverts and a dense week of traffic, bilingual channel,
direct, and room conversations whose packets decrypt, traces with
their trophy-case records, neighbour tables, a joined room, admin
passwords, regions, and Watchtower alerts. Every value comes from a
fixed seed and an age before now, so each run gives the same data.
The device plays the live traffic from the same seeds.
The repository writers that stamp now take an optional time, and
record_observations stores a batch in one commit. The test world of
--mock is unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Chat's Channels, Rooms, and Direct headings and the trophy case's
discipline headings drop their emoji, for a cleaner look. The trophy
marks stay on the delete list's rows and the record page's header.
section_heading no longer strips icons, since no heading has one.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
"Section spacing" (section_spacing_min_rows, in the Display group)
replaces "Author spacing" and "Spacing from". It is the smallest
terminal that gets the line: any height, 20, 24, 30, or 40 rows, or
never (default 24). Each section heading of a list gets the line, and
the chat keeps it between authors and before a new day.
The frame records the terminal rows on the screen before the body
renders (note_terminal_rows), and Screen.section_spacing is the one
test. section_heading marks its row as spaced, and the select list
adds the line, never at the top, after a blank line, or under a
heading. The hand spacers before headings are gone, except the seam
between the region table and its actions, which is two lists.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
A message that is too long for one packet now goes out as up to
message_parts_max parts (default 3, 1 turns it off), each ending with
its part number: [1/3], [2/3], [3/3]. Each part, with its part number,
fits in the byte limit of the conversation (130 for a channel, 150 for
a direct message). A cut goes at a space, and a word with no space to
cut at is cut between characters, never inside an emoji sequence or
after a combining accent.
Channel parts wait the transmit cooldown between them, so that the
floods do not go out as a burst. A direct part waits for the
acknowledgement of the part before it, or the end of its wait. An
unacknowledged part still lets the rest go out, and ^R retries each
one. A hard failure stops the rest and puts their text back in the
compose line. The byte gauge shows the number of parts and the bytes
of the last part. Rooms are not changed.
Co-Authored-By: Claude <noreply@anthropic.com>
^E still lists the reaction_emoji preference first, under "Your reactions". Under
"All emoji" it now lists each other emoji with its Unicode name, and the list
filters as you type: "fire" finds 🔥, "heart" finds the hearts. The catalog comes
from the Unicode database of the Python that runs MeshTerm and from Rich's table of
text-default emoji, so it needs no data file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Select a message in a channel or a DM and press ^E (Shift+F2 on the handhelds) to
react with an emoji. A reaction is a usual message on the wire: MeshTerm writes the
format of MeshCore One and reads it and the two formats of meshcore-open. The
transcript folds each reaction under the message that it names, with a count, or
the names of the nodes while that message is selected. A reaction does not raise
the unread badge, and the Messages list previews it as "reacted 👍".
A reaction names its target by the sender's timestamp. Thus MeshTerm now gives the
device the timestamp of each message it sends and stores exactly that second. A
retry of a DM keeps the timestamp and counts the try number, as the protocol
specifies. The emoji that ^E offers are the reaction_emoji preference. Rooms have
no reactions.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
So they pop a bit more: #f5e5a8, pale and low in chroma, which keeps it
well clear of warn's amber (0.12 apart in OKLab) and title.warn's (0.085).
The PicoCalc draws its nearest slot, the bright yellow that warn uses.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A section heading, in a grouped list or as a chat's day divider, was the
dark grey of faint. It now wears title.border, the colour of the title
in the frame around it: bold #d4d4d4, and white on the PicoCalc. It is
still never the border's own grey.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
#7c7c7c went too far. The border now sits halfway in lightness between
that and the old #a2a2a2, and on the PicoCalc it is back on the light
grey slot, the nearest one.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every node-type mark is white now: ● ▲ ■ ◉ were pink, violet, white,
and orange, and the shape already says the type. Each keeps its own
type.* style, so one can take a colour back in one place; the unknown ○
keeps its grey. On the map a crowd in one cell used to glow toward
white, which a white marker cannot do, so that signal is gone.
The border grey goes down to #7c7c7c, which JP picked on a ladder. That
sits almost on faint, so the title bar's live clip arrow is now lit like
the title instead of taking the border's grey. On the PicoCalc the
border is the dark grey slot.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A plain border, the one with no caution tier, was the indigo accent: one
more colour on every screen, and it meant nothing. It is now its own
theme style, border, in the grey of muted, with title.border and
hint.border beside it; the amber and red tiers keep their colours. That
covers the base frame, every dialog, the handhelds' title bar, the tab
strip, and the CLI's panels. The title bar's clip arrow for a direction
with nothing more now dims to faint, since the border and muted are the
same grey. On the PicoCalc the border takes the light grey slot.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Tailwind slate greys were cold. Each one is now r=g=b at its own
OKLab lightness, so every contrast stays where it was: the theme's
chrome, the path chips, the map's roads, labels and buildings, the heat
tail, and the emulator window. test_neutral_greys fails any #rrggbb
literal that reads as a grey and has a tint.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
The part of a route that the user does not compose (a mirrored return
leg, the return home) drew every hop as the same dark slate chip. Each
faded chip now has the colours of its own node at FADE_CHROMA of their
chroma, at the same lightness, so it still says which node it is. The
PicoCalc has no colour of less chroma: there a faded hop keeps its label
colour and drops its fill. Arrows keep faint.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The star of our node had the hue of our key, set from the self-info at run
time. It is now the white of "you" on each surface: the map, the routes,
the lists, the legends, and the chat. The run-time colour, the device-state
hook, and the style generation of the render cache are removed. A faded
star keeps its grey.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Our chip had our hue as a light fill under dark text. It now has the fill
that each known sender gets, with a white label, and the PicoCalc can draw
that too: white on the dim twin of the hue. The hop flag is white_ink now.
A chat chip with no key keeps its grey fill, and its label is black. On the
PicoCalc it is black on the light grey of the keyless chip.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The star of our node was the yellow of the map. SELF_MARK now names a
theme style, you.mark, and the theme writes our key's hue into it when the
device-state cache reads the self-info. The context makes that connection,
so the services still do not import the UI. The map, the routes, the lists,
the legends, and the chat all draw it, and the render cache keys on a style
generation so no old bytes stay. A faded star keeps its grey.
In a chat, a sender or a mention with no key had the light blue keyless
chip. It is now quiet: the grey of plain text on that grey darkened by the
chip rule. Routes keep the keyless chip, arrow mode keeps node.unknown, and
the PicoCalc keeps the keyless pair.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The point of our chip did not read well. The mark at the left of the time
is now the star, in the hue of our key: the colour of the mention chip in
the body. It is the same on each platform, with chips or without them. The
Messages list uses the same star at the left of the age.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The notch and the point together were too heavy. The mark is now one cell,
the point of our chip in its fill, then a space before the time. Without
chips, it is ">" in our hue.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The star at the left of the time becomes two cells in the fill of our
chip: the notch, then the point, with no label between them. Thus the mark
has the colour of the mention chip in the body. Without chips, it is ">>"
in our hue. The Messages list puts the same mark at the left of the age.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Our messages go under "★ Name" on the turned-over chip, as before the last
change. A mention of us keeps its chip without a star, and its message
keeps the star at the left of the time.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Our sender chip is our name, turned over, with the star on the page to its
right. A mention of us has the turned-over chip and no star: the message
that names us gets the star at the left of its time, so every time moves
two cells right, and the Messages list puts it at the left of the row's
age. A mention chip drops its @ where chips are drawn.
The compose line draws each complete @[Name] as its chip and treats it as
one atom: the arrows step over it, and Backspace or Delete removes all of
it. A reply inserts its mention at the cursor, so one message can name
several nodes. The prompt and the typed text are white.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Two preferences in the Display group: "Author spacing" (auto, on, off;
default auto) and "Spacing from" (the smallest terminal, in rows, that gets
the blank line with auto; default 24). The test reads the real rows of the
terminal before each paint, so a small desktop window drops the line as the
Cardputer Zero does, and a change applies at the next paint. The transcript
cache stores the spacing, so a change draws the lines again. The CLI
manual's sample of `preferences show` is the real output again.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The transcript asked for a gap between sender groups, but an empty Text
renders as no line at all, so the gap never showed. A blank line now
closes each author's messages, also before a new day's divider, where
the platform has 20 rows or more. The 14 rows of the Cardputer Zero keep
the transcript dense. A cached slice that starts with the gap pins its
day divider one line down.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A channel, a direct chat, a room, and the Messages list show our messages
under "★ Name" instead of the bare star. The chip has our key's hue turned
over: dark ink on a light fill, where each other sender is light on dark.
A mention of our name takes the same chip, as "★ @Name". The PicoCalc
cannot draw a light background, so there the chip keeps the normal
colours and the star marks it. Path lines keep the bare star.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Show private key drew its warning and no key in the menu since 0.10.0.
On the uConsole and the Cardputer Zero, MeshTerm now writes an imported
key into the node's identity.key and restarts the node. An import also
reads a file (hex text or raw bytes), expands a 32-byte seed, refuses a
key of the wrong length before the confirmation, and names a firmware
that has its import turned off. The run log no longer stores the key of
config import-key (a migration removes the stored ones), and an exported
key file is written with mode 0600. Refer to #26.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Greying every name that two keys ever used was too strict: a reflash with an
erase makes a new key, and 34 names on this mesh have one, JP's own among
them. Smog went grey this morning because of two keys silent since September.
The newest key now gets the name, and the name is grey only when another key
used it within name_overlap_days (a new Display preference, "Shared names",
default 7) of it: two live claimants. A contact that was never heard never
wins. On this machine's real data, LOG.IC 3R goes to its active key 47368a7c,
Smog to fa331c83, and 8 of 883 names stay grey.
The stored names come with their times from the one scan node_names() already
ran (node_names_with_times), so opening a chat costs no second scan.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A contact's page has enough action rows that, on a 24-row terminal, they left
the preview under its five-row floor, and it stepped aside everywhere. It now
keeps its floor and the page scrolls. Only a short frame (the Cardputer's
11-row viewport) leaves it out.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
In a channel, a DM, or a room, ^O on a selected message opens the node page
of its author, the same page the Contacts list opens: our own for a message
of ours, the contact the author's key finds otherwise (ContactPages, the twin
of the map's Locator). It opens to look, without the management verbs, which
belong to the list a contact is in. The hint names ^O only where it acts; the
handheld chip is Author, on Shift+F3 behind Map, since F1-F3 are full.
The room's login moves from ^O to ^G.
The Unreleased changelog now also says where the Map chip went, and covers
the shared lane and the route-end chips.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
F1-F3 hold what the three conversations share, in the hint's order: Paths,
QR, Map. The Shift bank holds each screen's own verbs: ^R on Shift+F1 (Retry
in a DM and a room, Resend in a channel) and the room's Log in on Shift+F2.
F4/F5 stay the pager with Latest/Oldest behind Shift.
Day ↑ and Day ↓ are gone from the lane; the desktop keeps the day jump on
^PgUp/^PgDn.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Messages list's preview draws its author as an origin chip (no colon: the
point says it) and its mentions as destination chips, as the transcript does.
The packet viewer's from rows close on the point and its to row opens on the
notch, around the via chain that already opens and closes on both. The live
feed's addressed subject is an origin chip and a destination chip facing each
other across one cell of page (widgets.route_ends): a seam would claim the two
are neighbours. A pair too wide for the lane cracks instead of eliding. The
courier's recipient is a destination chip, in the hue of its key while it
waits and muted once finished.
Arrow mode reads exactly as before everywhere. A lone hop there carries no
PATH_INK stamp, so a highlighted list row whitens it like any other name.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A message goes from its author toward the nodes it names, so the two chips are
the two ends of one route that is not drawn. name_chip takes a role (ORIGIN or
DESTINATION); arrow mode ignores it, so a degraded terminal draws exactly what it
did before. A chip in a message body never breaks across lines: render_hanging
holds each whole run together, spaces included. _sender_style lost its last
caller and is gone; its tests now read the rendered chips.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
locate moves from ^Y to ^L, and the room's login from ^L to ^O, under the
chord rule of 3675226. On the map and in the mesh walk, ^L still goes to
our node. In a chat and on a room's board, ^L opens the map on the author
of the selected message (our own message: our node); on Contacts, on the
highlighted node. map_screen.Locator holds the markers that
gather_markers returns when the screen opens and answers find() at each
paint, so the "^L map" hint atom and the Shift+F1 Map chip show only
where the key acts. A room keeps Log in on Shift+F1, so ^L has no chip
on a room's board yet.
The chat's hints for a selected message go through _fit_hint, which
drops ↑↓ and then ^P only when the line passes 72 cells; the room now
reuses them. LaneDeck.action_for returns None for a slot that has only
a Shift companion.
Right Ctrl with a letter chord still does nothing on the Canadian
Multilingual layout: JP chose not to repair that.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The viewer now opens on the stop the feed has. On the pin (^), the card
follows the stream and the feed stays pinned; on a selected packet, the
viewer holds that packet as before. Enter no longer drops the pin.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>