Releases: yerzhansa/enduragent
Release list
Enduragent Desktop 0.1.5
Patch Changes
-
fb370fb: User-facing: Saving a timezone now keeps the timezone and its pin together, so Enduragent cannot lose the saved choice between two separate writes.
-
10678ab: User-facing: Delete buttons in setup and settings now sit at the same weight as the buttons beside them and differ only in colour, the confirm button in a delete prompt is a filled red so it never reads as the same control as Cancel, and buttons, links and dropdowns across setup and settings show the hand cursor on hover.
Danger is a colour, not a button weight. The renderer now exports exactly two danger constants:
BUTTON_DANGER_QUIET_SMat the quiet weight (no border, transparent background) for every in-row destructive action, andBUTTON_DANGER_SOLID_SMat the solid weight for the confirm button inInlineConfirmation, where a fill keeps the destructive action distinguishable from Cancel without relying on colour alone.surface.module.css.dangerousmirrors the quiet variant so the Reset conversation button matches without migrating that file to Tailwind. -
85fd087: User-facing: Fixed Desktop startup when an existing Intervals refresh cannot be saved.
-
be36645: Log renderer and child-process crashes from the desktop main process and start Electron's crash reporter with local-only minidumps (
uploadToServer: false). Fields are collapsed to one stderr line, query strings and fragments are dropped from the crashed URL, and oversized values are truncated. -
63637ca: User-facing: The native window title bar now follows the appearance you pick in Preferences, so a dark app no longer sits under light window chrome.
-
7438087: User-facing: The first launch after installing no longer reports a fully-configured install as unconfigured — setup status now retries while the coach is still starting, shows a neutral "Checking setup…" state until it is known, and the Training page keeps reporting ride imports once setup is complete.
-
d7dc601: User-facing: Enduragent now uses this computer's timezone by default and refreshes it every time it starts, so a machine that moves zones no longer coaches on the old one. Save a timezone yourself in Settings → Conversation & time and Enduragent keeps that one from then on. COACH_TZ still owns the timezone when it is set.
-
73269ae: User-facing: Settings now shows the coach Provider row's title and its active-route detail on separate lines instead of running them together.
-
381ea8a: User-facing: Removing an additional Telegram user now asks for confirmation and explains that the user loses access until re-added by sender ID.
-
479180d: Ship the
en-USChromium locale pak in the Windows package.electronLanguages: [en]matched nothing under app-builder-lib's inverted prefix filter, so every locale pak was deleted fromwin-unpacked/locales/and Blink null-dereferenced inLocale::DefaultLocalethe first time a renderer wrote a value into a number input. The Windows package verifier now requires a present, non-emptylocales/en-US.pakand rejects any other locale entry. -
a0571e3: Verify the Windows installer envelope and retained application tree with native Node.js tooling, and emit immutable SHA-256 package evidence without relying on a machine-installed archive utility.
-
a0571e3: User-facing: Uninstalling Enduragent on Windows now removes both owned login-start registry values while preserving athlete data and desktop settings.
-
b4c0197: User-facing: The Windows app now enforces the update downgrade floor; previously it was silently inactive on Windows.
cycling-coach@2026.8.18
Patch Changes
-
df20eb1: User-facing: ChatGPT sign-in now keeps working on machines with a wrong clock, and sign-in problems show up as authentication errors instead of a generic failure.
Token validity no longer depends on the local wall clock: the ChatGPT-lane token readers return the stored access token as-is and treat a server 401 as the only invalid signal, with one bounded refresh-and-retry per generation (MAX_AUTH_REFRESH_ATTEMPTS = 1). HTTP 401/403 from the provider is classified as error_class "auth" in turn_outcome. Coaching dates and daily resets intentionally stay on the local clock.
-
d141441: User-facing: Enduragent now opens normally when Telegram setup is left in an uncertain state after a crash or forced quit; the Telegram section shows a repair prompt instead of the whole app refusing to start.
Startup no longer throws when the initial Telegram reconciliation returns a non-applied outcome. The channel is latched into its existing failed/repair status until a successful reconcile or a daemon rebind clears it, and unexpected startup failures are now written to log.jsonl as a classified startup_failed record before any dialog.
-
5eecfd8: User-facing: Enduragent now recovers Windows conversations after a crash interrupts reset-intent or transcript-boundary writes.
-
a0571e3: Internal: Add hosted Windows verification for the installed unsigned NSIS package and its cleanup contract.
-
8b8991a: User-facing: Exporting a ride and importing ride files now work on Windows. Both used to fail with "The export could not be saved to that location" because every Windows path was rejected before anything was read or written.
Export destinations and import paths now share one platform-absolute path validator that accepts POSIX, drive-letter and UNC paths; the preload and renderer import gates parse extensions across both separators; the export writer joins its temporary path with the platform separator and skips the post-rename directory fsync on Windows, where directory handles cannot be synced; and desktop export IPC now logs a fixed failure-stage classification before reporting a write failure.
-
40c9230: Internal: Stage generated sport-skill modules beside their destination so atomic replacement also works when Windows temp and workspace directories are on different drives.
Enduragent Desktop 0.1.4
Patch Changes
-
f59bf52: User-facing: Deleting the Telegram connection now completes while offline and cancels any pending pairing.
-
4555c74: User-facing: Connecting intervals.icu now repairs an outdated saved Athlete ID when the copied key verifies the current training account, instead of rejecting a valid key.
User-facing: Setup now tells you to copy the intervals.icu API key again when the clipboard is empty, instead of saying intervals.icu rejected it. -
4555c74: User-facing: Setup is now its own full-window screen that opens first and stays up until you answer all three required questions — what powers your coach, Intervals.icu, and your injury status. Telegram remains available there as an optional connection.
The desktop Shell renders the setup gate instead of the sidebar and views while setup is required, so the chat surface is unmounted rather than hosting an in-thread setup card. Credential repair stays reachable inside the gate through the shared credential feedback block.
-
4555c74: User-facing: Setup no longer asks whether a clinician has cleared you — an injury answer alone completes the injury question.
-
846b0d8: User-facing: Claude Code now starts only for Claude work and uses a private Enduragent folder with none of your files.
cycling-coach@2026.8.15
Patch Changes
- f59bf52: User-facing: Deleting the Telegram connection now completes while offline and cancels any pending pairing.
- bb3ccce: User-facing: Update alerts now link to the Enduragent desktop app for macOS.
- 846b0d8: User-facing: Claude Code now starts only for Claude work and uses a private Enduragent folder with none of your files.
- 8971c2e: User-facing: Connecting intervals.icu after pasting an API key is now faster while keeping account verification in place.
Enduragent Desktop 0.1.3
Patch Changes
-
00402f8: User-facing: Desktop update checks now recover from stalled network requests instead of remaining stuck indefinitely.
-
3e8fbe5: User-facing: Added optional Telegram bot setup directly to the desktop Chat setup screen.
User-facing: Moved required desktop setup into Chat and kept it available in Settings for recovery.Setup now stays in Chat until the coach is ready and remains available at the top of Settings for credential and training-data recovery.
Desktop setup readiness is rechecked from durable runtime state on every launch, and chat actions fail closed until the provider, training data, and saved safety intake are ready.
Chat setup can connect a Telegram bot from a copied BotFather token and safely delete its connection from this Mac, and always keeps pairing and access management in Settings.
-
a45d3bb: User-facing: Enduragent now exits safely instead of hanging indefinitely when background cleanup cannot finish.
-
d020f92: User-facing: Connect Intervals.icu by copying your API key - no typing it into the app.
-
9eadc87: User-facing: Delete your Intervals.icu connection from Chat or Settings, and reconnect any time with a copied API key.
-
e1c4786: User-facing: Desktop now checks for updates every six hours while running, in addition to checking at startup.
-
a6a2cf4: User-facing: Desktop now asks you to quit and reopen the app when an update check cannot safely continue, instead of offering a retry that cannot run.
Invalidate timed-out updater generations, fence late completions, and keep automated and manual checks disabled until process restart after timeouts or updater startup failures because the native macOS updater does not expose a supported instance reset.
-
da84213: User-facing: Desktop update actions now wait for in-progress Settings changes to finish before restarting the app.
-
41fe0aa: User-facing: Telegram bot management is now delete-and-reconnect - delete the connection, then connect a new bot with a copied token.
cycling-coach@2026.8.11
Patch Changes
-
3e8fbe5: User-facing: Added optional Telegram bot setup directly to the desktop Chat setup screen.
User-facing: Moved required desktop setup into Chat and kept it available in Settings for recovery.Setup now stays in Chat until the coach is ready and remains available at the top of Settings for credential and training-data recovery.
Desktop setup readiness is rechecked from durable runtime state on every launch, and chat actions fail closed until the provider, training data, and saved safety intake are ready.
Chat setup can connect a Telegram bot from a copied BotFather token and safely delete its connection from this Mac, and always keeps pairing and access management in Settings.
Enduragent Desktop 0.1.1
Patch Changes
-
0da7580: User-facing: Desktop now uses the Enduragent logo as its app icon and has a simpler sidebar with clearer training-data sync status.
Replace the default packaged application icon with the website mark, remove sidebar surfaces that duplicate Chat navigation or expose internal process state, and label successful refreshes as "Training data synced."
cycling-coach@2026.8.8
Patch Changes
-
d060028: User-facing: Desktop ride analysis now shows complete interval details and provider power-versus-heart-rate curve evidence with accessible chart tables.
Bound activity analysis and training exports across their full operation, and tighten activity-analysis result validation.
-
ddcf6d4: User-facing: Desktop releases now use an independent, easy-to-read version sequence starting at 0.1.0.
Keep the npm package on its existing calendar-version sequence while binding signed desktop builds, updater metadata, artifacts, and native update acceptance to
apps/desktop/package.jsonSemVer. -
1c059f4: Use the UTC calendar date as the npm package version and fail closed instead of generating a monthly release counter, same-day suffix, or future date.
cycling-coach@2026.8.0
Minor Changes
-
af0582c: User-facing: Added a Claude subscription provider that drives your locally installed Claude Code CLI (bring your own login, no API key).
The lane runs the user-installed CLI as a model transport under the existing coach loop: one query per generation, tools served over an in-process MCP server, sanitized child env, and a persisted session cursor that falls back to a rebuild from our canonical transcript whenever it drifts. A three-layer kill switch (
ENDURAGENT_CLAUDE_CLI_DISABLED,llm.claude_cli.enabled: false, desktop eligibility) is re-checked every turn, so disabling it takes effect on the next turn without a restart. macOS and Linux only this wave; Windows is unsupported for this lane. -
83b0275: User-facing: Experimental (off by default): a Codex provider that drives your locally installed, ChatGPT-signed-in codex CLI as the coaching agent. Enable it in config.yaml with llm.provider: codex-agent and llm.codex_agent.enabled: true.
Config-file only — deliberately absent from the setup wizard, the model catalogue and the desktop onboarding UI, so it can only be reached by editing
config.yaml. macOS and Linux only; win32 is refused before the enabled check so a Windows user gets the accurate message.Architecturally this is agent delegation rather than CLI-as-transport:
turn/startruns Codex's own agentic loop, the 18 coaching tools are injected over a loopback MCP endpoint, and the coach persona is applied as developer instructions rather than as a system prompt. One coaching turn is one billed call against the subscription regardless of how many model calls Codex makes internally, so every ledger row is stamped notional and excluded from the spending cap.Safety posture: the child environment is allowlist-built from an empty object rather than filtered from the parent,
account/readmust report a ChatGPT account on every turn-carrying child and not just the cached readiness census, the model provider and endpoint are pinned, and the user's own~/.codex/config.tomlMCP servers, plugins, hooks, shell execution, multi-agent, browser use and web search are all disabled for the duration of a coaching turn. Verification reads the effective config back from the spawned child and refuses rather than degrading. No CLI binary is bundled and no native module is added — the user installscodexand signs in themselves.
Patch Changes
-
8ac6eec: Record one store-level owner fingerprint from the resolved intervals.icu athlete identifier at sync time, compare it read-only before credential saves, allow saves when the comparison is unavailable, and keep credential rotation independent from account ownership.
-
c0cf65b: User-facing: Desktop activity analysis now uses a bounded local cache, preserves last-good results when refreshes fail, and keeps provider activity IDs out of the interface.
-
c01e27a: Apply timezone, daily reset, idle reset, history budget, and future archive-retention changes through one redacted runtime lifecycle.
-
4f99951: Add strict shared contracts for bounded activity analysis results.
-
e2ef5f7: User-facing: Cycling Coach now waits for you to ask before proposing a workout, while still creating workouts you explicitly request.
Add cycling's unauthored-envelope capability metadata and disabled autonomous-prescription posture.
-
ec24061: User-facing: Prevent ambiguous duplicate activity streams from producing misleading training analysis.
-
86a1697: Add Desktop in-app update checks and an explicit restart action when a new Desktop release is ready.
-
2109fbf: Read coaching activity details and streams directly from the canonical store, report import publication availability separately from durable ingestion, and bump the daemon protocol for the breaking import-result contract.
-
d22fb9a: User-facing: ChatGPT sign-in now finishes promptly after browser approval, shows clear progress, supports cancellation, and can retry coach activation without another login.
-
9c60b50: Feed verified current Power Progress snapshots into existing local metrics without making duplicate provider requests.
-
1788b65: Refresh Power Progress curve evidence in the normal desktop sync window without blocking base training-data updates.
-
68e2a75: Parameterize per-binary environment variable names (setup/update/managed-deploy
knobs derive from the binary name instead of hardcoding one binary's prefix),
ship the MIT NOTICE file inside the published npm tarball, and arm the
package-dependency lint family with empty kernel package scaffolds. -
760a670: Add the desktop chat-first surface and persisted-state training panels.
-
cf0cca5: Count cached input tokens in the Desktop ChatGPT subscription spend total and cap warnings.
-
381ad9f: Refuse Desktop ChatGPT sign-in instead of opening an unusable browser tab when another local sign-in flow holds the callback port.
-
61a8940: Added desktop PKCE sign-in, daemon-owned OAuth profile storage, and keyless runtime configuration for the ChatGPT subscription provider.
-
e4543b7: Render Desktop coach prose in the native system font, dropping the bundled Source Serif 4 webfont and its NOTICE entry.
-
0115dfe: Preserve closed configuration-readiness failures through app-supervised utility termination without retrying terminal configuration errors.
-
b4e5365: Let Desktop start from an existing configuration that omits
data_dir. -
0047eb8: Isolate local Desktop packages and packaged security checks from the production macOS application identity so development verification cannot alter production Keychain access state.
-
352bfa5: Add an authenticated packaged-app self-test with a Vitest-free runner, dual-location SHA-256 resource verification, and stable machine-readable exits.
-
78971cb: Adds boundary-scoped archived conversation reads (list plus a cursor-namespaced page reader) through the durable transcript store, daemon RPC registry, main-process IPC, and the validated preload bridge. Current-conversation hydration is untouched; the archived surface has no composer, retry, or resume path. Protocol version moves to 11 because the wire method set grew.
-
a42fb2c: Fetch bounded release metadata only after an explicit Desktop action, validate it across the preload boundary, and render remote note text without HTML or Markdown interpretation.
-
2e61329: Add curated and custom model selection, write-only endpoint overrides, explicit provider activation, and retry-safe non-secret Setup drafts.
-
1977c1b: Added provider-reported OpenRouter costs and aggregate authenticated spend methods for the desktop client.
-
6cf11bd: Report the latest successful sync time separately from when training data last changed in Desktop.
-
2e437f8: User-facing: Added an optional Desktop-hosted Telegram bot with private pairing, local-only availability, and separate Telegram chat history.
Added main-only clipboard capture, a strict redacted mutation contract, a coherent encrypted bot profile, visible replacement controls, background startup, transient sleep/resume handling, and generation-drained token replacement for Desktop Telegram setup.
-
01d652e: Expose credential and environment-ownership state without secrets, and return fixed account-guard refusals across the desktop runtime protocol.
-
810b29e: Add bounded, cursor-stable transcript pagination for the canonical Desktop conversation across the durable store, daemon RPC, main-process IPC, and validated preload bridge.
-
153f1c4: User-facing: Added the Cobalt palette to desktop appearance settings, with matching light and dark colors.
User-facing: Refreshed the desktop app's visual design — DM Sans typography, softer surfaces with a subtle paper grain, consistent button and input shapes, and quieter scrollbars.The desktop renderer now uses shared geometry, elevation and typography tokens in
theme/tokens.css, plus a CSS Modules primitive sheet (theme/surface.module.css) that every
view composes for cards, controls, fields, chips and list rows. Filled controls invert to--ink
rather than an accent hue, so the chrome stays monochrome across all thirteen palettes. -
e63b351: User-facing: Ride review now includes accessible power and heart-rate distribution charts with exact tables, plus a coverage-qualified server power and heart-rate response view.
-
153f1c4: User-facing: Setup no longer asks whether you have had a bone stress injury — the clinician-clearance question now appears only when you are managing or returning from an injury.
The flag was collected, validated and stored but never read: nothing fed it into the coach
prompt or any ride-volume logic, so its "affects how quickly we build volume" subtitle
described behaviour that did not exist. The cycling-only setup now asks only about an injury
the athlete is currently managing or returning from.The clearance question now keys off
injury_statusalone. It still requires an answer from
anyone managing or returning from an injury; it no longer appears for a historical injury with
no current return-to-training context. The pre-release store schema no longer carries the unused
field. Protocol 11 retains it only as an ignored compatibility value, with the new client always
sendingfalse. The footer note names the one question that is outstanding. -
cc259c7: Add the Electron launch surface, supervised local service connection, protocol-2 operational RPC, and renderer security boundary.
-
5d035ce: User-facing: The coach is now also published as enduragent — npm i -g enduragent installs the enduragent command, and container images additionally ship as ghcr.io/yerzhansa/enduragent; existing cycling-coach installs keep working unchanged.
-
0ab935f: Add a trusted canonical-activity resolver and revision key for bounded ride analysis.
-
2e437f8: User-facing: Desktop now starts with a fresh Enduragent profile and leaves old npm-library data untouched.
Removed the obsolete automatic home migrator fr...
cycling-coach@2026.7.28
Minor Changes
-
2a762ce: User-facing: Default and recommended LLM models upgraded to the newest generation — GPT-5.6 Sol (OpenAI and ChatGPT sign-in), Claude Sonnet 5, Gemini 3.6 Flash, Kimi K3, MiniMax M3, and Qwen3.7 Plus.
Refreshes the per-provider default model map, the setup wizard menus, and the context-window table for the July 2026 lineups (GPT-5.6 Sol/Terra/Luna, Claude Sonnet 5 / Opus 5 / Fable 5, Gemini 3.6 Flash + 3.5 Flash Lite, Kimi K3, MiniMax M3, Qwen3.7 Plus/Max). Extends the usage price table with the new models (including OpenRouter slugs), fills in the previously zero-priced GLM-5.x rows, and bumps the unknown-codex-model price fallback from gpt-5.4 to gpt-5.6-sol rates. Existing explicit model configs are unaffected — all previously catalogued IDs remain priced and resolvable.
Patch Changes
-
ea19abc: User-facing: Zone-based warmup ramps now render on the calendar power chart, and planned duration and Load for pushed workouts are derived by intervals.icu from the steps themselves.
-
371402c: User-facing: Workouts the coach adds to your intervals.icu calendar are now marked as coach-created, and the coach will only delete its own scheduled workouts — races, notes, and workouts you added yourself are always refused.
Calendar create tools in both sport packages stamp an
external_idandtagsprovenance marker on every event they push. The list projection surfacescategory,externalId,tags, and a derivedcoachCreatedflag, plus an opt-incoachCreatedOnlyfilter. The delete tool now refuses non-WORKOUT events (not_a_workout) and marker-less events (not_coach_created) before the destructive delete call, ahead of the existing past-date guard. -
f512ba3: Ship package license, notice, and graph-derived third-party legal artifacts.
-
8fe4c26: User-facing: Conversation summaries created during long sessions are now saved into the coach's dated memory notes, so they survive session resets and stay searchable later.
-
6340b6a: User-facing: Coaching replies and raw training snapshots now include Garmin attribution only when their data has a confirmed Garmin source.
-
55ac928: User-facing: Calendar changes and plan saves now ask for your confirmation first — the coach proposes, and you tap Confirm or Cancel (or answer y/N in the terminal) before anything is written.
-
4ccdf20: User-facing: Chat requests to intervals.icu now time out after 30 seconds instead of hanging a coach turn indefinitely.
Route every intervals.icu client built by the factory (sync and chat) through one process-wide request bucket (10 requests/second, burst 30) so multiple clients can no longer burst past the intended combined pacing. Chat clients now get the same abortable per-request timeout wrapper as sync clients; the timeout covers queue wait plus the HTTP call, queued waits abort promptly, and lib-level retries stay disabled (
maxAttempts: 1) on both paths. -
1e40c2e: User-facing: Saved memory no longer gets corrupted when a note contains markdown section headings.
Demote line-start
##headings to###inside the single section-write
choke point so heading-bearing content can no longer fragment the section map,
shadow a real section, or leave orphan fragments across reads and replaces.
Export a 4000-char per-section soft cap that emits one structured warn (never
truncates) when a stamped body exceeds it. -
bc1cd7c: User-facing: Long-term memory no longer crowds out conversation history — only your core profile is pinned into every reply, and the coach fetches the rest on demand.
Tier memory injection so only always-inject sections (person, goals, preferences, medical history, schedule, and the sport profile) render into the system prompt's athlete context; notes, equipment, and history stay on disk and remain reachable through the memory read tool. Add a prompt-layer section budget that nudges the flush pass to move dated detail into daily notes instead of growing a section, and hard-cap the rendered athlete context with a disclosed, warned truncation. Harden the athlete-data fence: a new reusable prompt-fence module neutralizes fence tokens and strips control/format characters, and every tool result is marked as untrusted data at a single choke point so stored or external text can never escape its fenced block.
-
ff98c56: User-facing: A corrupted or hand-edited plan file no longer breaks the chat — the coach simply continues without the plan summary.
[Engineering: loadPlan now goes through safeReadJson with a loose passthrough schema; plan summary omits missing fields instead of rendering "undefined"; orphan MEMORY.md sections emit a names-only structured warn at startup + post-flush; deprecated Memory.appendMemory deleted (zero callers, never on the interface); appendDailyNote skips exact-duplicate notes.]
-
ebfe55d: User-facing: Long chats that hit the model's context limit now compact and retry to produce a complete answer instead of returning a cut-off reply.
Harden context-overflow classification, token estimation, and effective-window caps. Context-overflow classification now recognizes structured provider signals (Codex-normalized
ContextOverflowError, and 400 responses whose body carries a known overflow code or message) on top of the existing message fallbacks, without treating every 400 as overflow. A successfullengthfinish whose prompt already filled the real provider window is routed through the existing compaction rescue rather than persisting the truncated text; plain output-length truncation keeps the earlier empty-reply recovery. Token estimation counts part-array/structured message content instead of dropping it to zero and can anchor budget math to the provider's reported token usage. History budget, preemptive compaction, and compaction chunk sizing use a 200,000-token effective estimator window (min(providerWindow, 200k)) so a million-token provider window no longer expands the planning target. -
13af149: User-facing: Coach can now schedule strength sessions on your intervals.icu calendar — free-text exercises, sets, reps, and RPE.
-
4da026b: User-facing: Rapid messages sent within about 1.5 seconds of each other are now combined into a single reply, so a thought split across several messages gets one coherent answer instead of several partial ones.
Buffers free-form Telegram text per chat behind a 1.5s debounce window (each fragment resets the window) and joins fragments with newlines into one turn. A slash command flushes the chat's pending text first, then runs immediately, so commands are never coalesced into free-form text. Turn dependencies are resolved at flush time, the flushed turn threads to the last fragment's message id, each fragment fires one best-effort typing action during the window, and shutdown/update drains flush pending buffers synchronously without waiting on the debounce timer. Debounce timers are unref'd so a pending buffer never holds the process open.
-
54f6f54: User-facing: Messages you send while the bot is offline are no longer dropped when it restarts, and when a new daily session starts the bot now tells you your earlier conversation is archived and your key details are still remembered.
Normal startup no longer drops pending updates; a durable, owner-only offset store (keyed by a short token fingerprint, never the raw token) dedupes anything a previous run already handled and stops
/updatefrom re-triggering itself after a self-update restart. Operator-capture startup still intentionally drops prior updates. A daily session reset is deferred for one turn when the last exchange is still recent (within 30 minutes), so a conversation that crosses the daily boundary isn't archived mid-thread; malformed timestamps and idle resets are never deferred. On an automatic reset the first reply is prefixed once with a plain-language notice and the model sees a one-turn archive marker so it discloses the fresh session. The athlete's message is now made durable before generation and a failed turn is recorded with a terminal marker, so a mid-turn crash no longer silently erases the message. Compaction now preserves surviving messages' original timestamps. -
e5d8e32: User-facing: Sketching a training plan no longer silently saves it — the coach saves a plan only after you approve it.
User-facing: The coach now refuses to schedule a workout on a past date instead of creating an event it can't remove.Tighten tool inputs for dates, activity IDs, streams, memory sections, and saved plans.
-
403fb5e: Trim serialized tool descriptions and add per-sport payload size regression ceilings.
-
03964f0: User-facing: Fixed a rare bug where an emoji sitting exactly at a length limit could be sliced in half, producing garbled text in long Telegram code blocks, compaction summaries, and memory query results.
All fixed-length string cuts now route through a shared
truncateUtf16Safehelper that backs the cut off by one UTF-16 unit when it would bisect a surrogate pair. Fixed sites:splitPreBlock's oversized-row fallback andhardSplit's pathological fallback in the Telegram chunker,capSummaryin compaction, and thememory_queryresult cap. (docs/issues #171)