StoreStorage (Durable's storage on Chord v2's store, @earendil-works/pi-durable/storage/store) passes
Durable's storage conformance suite and runs Durable's harness tests (npm run test:store). The store
gets owner names and claims, one id allocator, Durable's Storage semantics for refused steps, history
none/latest/rewindable with reads at a point, archive revisions and applyBatch. self.follow follows
Durable's synchronous observers as Chord sources. Persisted jobs: records and state in the owner's
store, restarts as Durable's tasks, abort stored, deferred state. Chord's ./next export returns for
the adapter surface.
stripAnsi treated <, = and > after ESC [ as final bytes, so ESC[<35;59;1M
(SGR mouse report) left 35;59;1M in tool output. Accept one private prefix
byte only directly after a CSI introducer (ESC [ or 0x9B). After a bare ESC
these bytes stay final bytes, so ESC= and ESC> (keypad modes) keep the
digits of the text that follows.
closes#11377
tui.select.pageUp/pageDown were configurable but ignored by SelectList,
SettingsList, editor autocomplete, and most coding-agent selectors. In
fullscreen mode, the default PageUp/PageDown also scrolled the transcript
instead of reaching the focused list.
- add getSelectPageIndex() and handle page keys in SelectList, SettingsList,
editor autocomplete, and the model, scoped models, auth, user message,
settings submenu, llama search, and /mcp selectors
- add Component.capturesViewportInput: a focused component that sets it
receives fullscreen viewport keys instead of the transcript, as a focused
overlay already does
- let page keys move an open autocomplete menu before app actions, so a
remapped Ctrl+V pages the menu instead of pasting an image
closes#7629
Co-authored-by: muyiyr <940955635@qq.com>
A database an earlier unreleased build wrote at pi.live version 2 has a run
without run.turns; a run in flight across the upgrade then counted NaN turns
and failed its next tool round with "Value contains a non-finite number and
is not strict JSON". Version 3's migrate adds turns: 0 wherever it is
missing.
GenerationHooks.afterRun asks, after a run answered, for durable tasks
(runEndTask(task, input)). The answer commits and the run's inputs settle
done first; the generation then creates the tasks as its children in a
finish phase and waits for them in drain, keeping pi.live.run (run.afterRun)
and the conversation busy, so idle waits include them, Stop aborts them and
a crash resumes them. Queued input is placed when they are terminal.
pi.live.run.first and runFailure.first name where a run's history starts,
also for a continue after a failure.
closes#11141
HookApi.entry() and entries(), and TaskRuntime.entries(): a hook or task
reads the conversation's raw history, which compaction never changes, so a
range bounded by entry IDs reads the same before and after a compaction and
in a rerun.
Conversation.submit(tx, draft) and ConversationHandle.submit(tx, draft) run
the same admission inside the caller's commit and return the submission ID,
so a host's own checks and writes and the admission are stored together or
not at all. Admission must come before the commit's first table write, once
per commit, and throws ReadAfterWrite otherwise on every path. A first
argument that is not a draft is taken as a transaction; one of another
Session, or a wrapped one, is refused. The handle form also rejects once its
invocation is aborted. The pi.durable.submit span covers the admission only.
closes#11149
An input with whenIdle: "reject" is refused with the new ConversationIdle
when the conversation has no run, before any write, so it never starts a
run. With whenBusy: "steer" it steers the current run or is refused.
Request-ID deduplication runs first.