Commit Graph

23704 Commits

Author SHA1 Message Date
greyvito 7072fc4f87 fix(providers): resolve plugin-registered provider profiles in get_provider
Plugin-only providers (commandcode, tencent-tokenhub, ...) are absent from
models.dev and HERMES_OVERLAYS, so resolve_provider_full returned None and
/model switches failed with "Unknown provider ..." even though the picker
lists them (CANONICAL_PROVIDERS auto-extends from the same registry).

Fall back to providers.get_provider_profile() before giving up, mapping the
profile api_mode to the ProviderDef transport.
2026-08-18 14:27:36 -07:00
greyvito f5ea3fa9cb fix(commandcode): accept base_url kwarg in fetch_models overrides
The model picker's generic live-fetch path (hermes_cli/models.py
provider_model_ids) calls profile.fetch_models(api_key=..., base_url=...).
Both CommandCode overrides only accepted api_key/timeout, so every picker
open raised TypeError, which was silently swallowed, leaving the provider
with zero models.

Match the base ProviderProfile.fetch_models signature (base_url kwarg) and
add a regression test asserting both profiles accept it.
2026-08-18 14:27:36 -07:00
Teknium d354af5e12 feat(desktop): unified Sessions list shows every connected gateway's chats (#88880)
The global SESSIONS sidebar only aggregated local profiles and v1 per-profile
remote overrides. Sessions living on v2 registry connections (remote/cloud/ssh
gateways) never appeared — the remote API returned the rows, but the renderer's
Sessions component received an empty array (#88880).

- electron/profile-session-routing.ts: fetchRegistrySessionRows reads each
  CONNECTED registry gateway's session list (ssh backends natively, shared
  remote/cloud hosts via one cross-profile aggregate with a legacy flat-list
  fallback), tagging rows with connection_id + owning profile.
  spliceRegistrySessionRows dedupes them into the unified list and extends
  per-profile totals. Reads never pass include_hidden, so Bot Mode's hidden
  canonical chats stay OUT of the global list, same as local sessions.
- electron/main.ts: mergeRemoteProfileSessions splices registry rows; the
  /api/profiles/sessions[+/sidebar] intercepts also fire when registry
  gateways are pooled (previously only v1 remote overrides). Only
  already-pooled backends are read — a sidebar refresh never dials or spawns
  a backend (the roster-respawn trap), and a dead gateway contributes nothing.
- types/hermes.ts + use-session-actions: SessionInfo carries connection_id;
  resuming a registry-owned row activates its connection-scoped gateway
  (ensureGatewayAgent) instead of a same-named local profile.
- store/gateway.ts: ensureActiveGatewayOpen rides out an in-flight secondary
  activation (bounded 8s) instead of failing instantly — the Sessions "+"
  during remote wake no longer errors "Hermes gateway is not connected".

Tests: 5 new registry-source/splice unit tests (tagging, shared-host
aggregate + legacy fallback, dead-gateway isolation, hidden-flag contract,
dedupe/totals) and a sabotage-verified activation-wait regression test.
2026-08-18 14:27:15 -07:00
Teknium aae96913df fix(desktop): register plugin notify handlers only after guards pass; re-resolve activate at the IPC boundary
Two hardening follow-ups on the salvaged #84192 work:

- dispatchNativeNotification now reports whether the notification actually
  reached the OS bridge, and dispatchPluginNativeNotification registers its
  onActivate/onAction closures only on true. Previously a throttled,
  disabled, or baseline-suppressed notification registered handlers that no
  click could ever clear, leaking them for the window's lifetime.
- The renderer's onNotificationActivate handler re-resolves the activate
  payload through resolveHermesOpenPath instead of trusting the pre-IPC
  validation, keeping path validation in one funnel for any future
  hermesDesktop.notify caller.

Adds a regression test covering the throttled and suppressed cases.
2026-08-18 14:26:28 -07:00
seref 73ddf6665c feat(desktop): rich plugin OS notifications with deeplink activation
Extends ctx.os.notify (the curated plugin OS door from #78685) with icon,
action buttons, and a serializable `activate` target. Body/action clicks
focus the window and navigate to the plugin's screen; activation paths
share one resolver (hermes-open-target.ts) with hermes:// OS deep links,
so `hermes://index-network/intent/1`, `/index-network/intent/1`, and
{ path, params } all land on the same hash-router route. Approval
notifications keep their existing session-scoped channel.

Salvaged from PR #84192 by @serefyarar (net diff of the PR branch applied
onto current main; branch carried merge commits so a single authored
commit preserves attribution).
2026-08-18 14:26:28 -07:00
Teknium 72b7c6c8d1 fix(models): keep discovery sentinels out of the user-facing models mapping
PR #67934 marked auto-discovered catalogs by writing two sentinel keys
INSIDE the user-facing ``models`` mapping of custom provider entries:
``__discovered_model_catalog__`` (written by
_save_discovered_models_to_config) and ``__explicit_model_allowlist__``
(injected by _normalize_custom_provider_entry). Every consumer of that
mapping — pickers, selectors, gateway/agent readers, and the user's own
config.yaml — had to know to filter those keys, and any site that
didn't listed them as phantom model IDs (``__discovered_model_catalog__``
showing up as a selectable "model"). The v11→v12 config migration and
the ACP session-state test caught exactly that leak on main.

Replace the in-mapping sentinels with a single entry-level flag:

- ``models_discovered: true`` now sits next to ``models``/``base_url``
  on the provider entry; the models mapping stays a clean
  ``{model_id: metadata}`` dict with no reserved keys.
- _save_discovered_models_to_config writes the new shape and refreshes
  catalogs it previously discovered (entry-level flag or legacy
  sentinel) instead of treating them as user-curated metadata.
- _normalize_custom_provider_entry no longer injects
  ``__explicit_model_allowlist__``; a dict-shaped models mapping counts
  as an explicit allowlist exactly when the entry is NOT marked
  models_discovered.
- _models_config_is_allowlist takes the discovered flag as a parameter
  (new helper _entry_models_discovered resolves it, including the
  legacy in-mapping sentinel); all call sites updated
  (model_switch.py, model_setup_flows.py, acp_adapter/server.py).
- Backward compat, no config version bump: configs written by a
  pre-fix Hermes (sentinels inside models) still read correctly —
  ``__discovered_model_catalog__: true`` is treated as
  models_discovered, both sentinel keys are stripped from model
  listings, and the next discovery save migrates the entry to the
  clean shape. Covered by a new regression test.

Also restore ``except Exception:`` on the pre-existing guards this PR
had narrowed to specific exception tuples (the resolve_runtime_provider
fallback in switch_model, the picker discovery/cache guards in
list_authenticated_providers, _get_model_config_dict, and
_credential_fingerprint). Those guards were intentionally broad on
main — a failed resolution or probe must degrade to the fallback path,
never crash the model switch. Guards the PR introduced for its own new
probe code keep their authored tuples.

The ACP new_session payload also goes back to
probe_current_custom_provider=False, matching the contract main's
test_new_session_returns_authenticated_cross_provider_model_state pins
(session opens must not block on live-probing the current custom
endpoint).
2026-08-18 14:26:16 -07:00
Vadelma 015f9990c6 fix(models): persist named custom catalog identity
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 4daaf1e619 fix(acp): preserve colon-bearing custom provider prefixes
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 7fb6b28ec8 fix(models): complete selector parity safeguards
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 81e813507f fix(models): preserve empty catalog and custom model semantics
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 9d2ba6c655 fix(acp): isolate custom catalog identities
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 7e61bd38c6 fix(models): preserve discovery provenance and endpoint identity
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma f70e9abce9 fix(models): close final provider discovery edge cases
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 17405de9c1 feat(acp): preserve native provider catalogs and identities
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma fa1bb88e3e feat(models): propagate native discovery across selectors
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
Vadelma 638b72f5ef feat(models): add native Ollama catalog semantics
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 14:26:16 -07:00
hermes-seaeye[bot] 6a1fb37c94 fmt(js): npm run fix on merge (#89485)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-18 21:26:10 +00:00
Teknium 38b7a40382 chore: map whisky0809 contributor email 2026-08-18 14:19:39 -07:00
whisky0809 edb9f96d6d fix(desktop): keep escaped dollars from ending a shielded math span
The inline branch of MATH_SPAN_SPLIT_RE excluded `$` from the body outright,
so a `\$` inside inline math — a literal dollar sign, valid TeX — broke the
span match and the shield silently didn't apply. `$\sqrt[3]{8} + \$5$` still
lost its index.

Step over escape pairs instead, matching the escaped-delimiter rule
findClosingSingleDollar already applies via isEscapedAt. The two body
alternatives are disjoint on their first character, so the added quantifier
can't backtrack ambiguously.

Reported by Copilot in review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SPGjEQ2yrS4nWiooUEdYti
2026-08-18 14:19:39 -07:00
whisky0809 21fc7c5a14 fix(desktop): shield math spans from the visible-prose rewrites
`$\sqrt[3]{8}$` renders as a plain square root — the index is gone. It is
not a KaTeX layout problem: the index never reaches KaTeX. CITATION_MARKER_RE
strips `[3]` as a citation marker, because its lookbehind accepts any letter
and the `t` of `\sqrt` qualifies. That runs inside normalizeVisibleProse,
which splits out inline code spans but not math, so TeX is fed to rewrites
written for prose.

Numeric-only, which is why `\sqrt[n]{8}` survives and made this look like a
layout edge case rather than a preprocessing one.

Shield math the same way inline code is already shielded: split each prose
part on math spans and rewrite only the segments between them. That also
takes math out of the reach of the other rewrites in that pass
(autoLinkRawUrls, LOCAL_PREVIEW_URL_RE, the ``` stripper, linkifySessionRefs),
any of which can corrupt TeX the same way with different input.

The split is capturing, and math segments are identified by index parity
rather than a leading `$`, so a prose run that merely opens with a stray
dollar cannot be mistaken for math. Escaped `\$` delimiters stay prose, which
is what keeps `$5 and $10` escaping intact.

Verified in the real renderer through the desktop mock-backend E2E harness:
`.katex .root` (the span KaTeX emits for a radical index) goes from 1 to 4 on
the same four-radical reply, and the MathML annotations show KaTeX receiving
`\sqrt[3]{8}` intact rather than `\sqrt{8}`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SPGjEQ2yrS4nWiooUEdYti
2026-08-18 14:19:39 -07:00
whisky0809 47066f5ea0 fix(desktop): normalize hugging multi-line display-math delimiters
Multi-line display math whose $$ delimiters hug the body
(e.g. $$\begin{aligned}...\end{aligned}$$) renders as raw error text.
remark-math's flow-math construct is fence-shaped: text after the
opening $$ on the same line is read as an info string and discarded,
and the closing $$ is only recognized alone on its own line. So the
block never closes and KaTeX paints the remains via its error fallback.

splitHuggingDisplayMath moves those delimiters onto their own lines. It
runs AFTER normalizeMathDelimiters because that rewrite is itself a
source of the hugging form: a multi-line \[...\] comes out of it as
$$\begin{aligned}...\end{aligned}$$, so the same bug reached users who
never typed a $$ at all.

Single-line $$...$$ is left alone (it routes through the inline
math-text construct and already renders), container prefixes are
replayed onto the delimiter lines, and both patterns anchor $$ to the
start of the line, which keeps them from firing inside an inline code
span.

Verified end to end: the repro emits katex-error through
remark-math + rehype-katex before this change and not after.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:19:39 -07:00
Teknium cc421cb697 fix: dashboard console skills commands no longer act on the wrong profile (#65828)
tools/skills_sync.py bound HERMES_HOME / SKILLS_DIR / MANIFEST_FILE at
import time — the third module in the same lineage as skills_tool
(f8723c478) and skill_manager_tool (c6a3d412d). In a long-lived
dashboard/TUI process, console skills commands (reset, diff,
list-modified, opt-in/out, repair-official) dispatched in-process under
_profile_scope's set_hermes_home_override(), but skills_sync's frozen
constants kept resolving against whichever profile was live at import.
Sharpest edge: reset_bundled_skill()'s #48200 rmtree strict-child guard
was computed against the WRONG skills root.

Fix: same call-time accessor pattern as the two prior fixes —
_hermes_home()/_skills_dir()/_manifest_file() honor an explicitly
patched module global (tests, retargeting) and otherwise re-resolve
from the live profile-scoped get_hermes_home() on every call. All 37
call sites migrated; module constants kept for compat.

Also documents in _profile_scope() that skills_sync needs no module
retargeting since the contextvar override now reaches it.

Regression tests (sabotage-verified: all 3 fail on the old binding):
- accessors follow set_hermes_home_override at call time
- explicit module patch still wins over the override
- rmtree guard anchors on the overridden profile's skills root

Fixes #65828
2026-08-18 14:14:42 -07:00
Teknium ae6578aff8 fix(desktop): route session RPCs to the profile that owns the session (#89206)
Bot Mode wake-ups died on a routing split-brain: session.resume /
session.activate / session.usage were dispatched on whatever socket was
active at request time, while the bot's own backend sat healthy and idle
(zero traffic until the idle reaper killed it). Two divergence sources,
both fixed:

1. Registry-owned route truth. applyActive() now publishes the active
   route's bare profile ($activeGatewayRoute + onActiveRouteChanged), and
   use-gateway-boot mirrors it into $activeGatewayProfile. Previously,
   eviction fallbacks (idle reap, connection removal, profile delete)
   moved the SOCKET back to the primary while the profile atom kept
   naming the evicted bot — ensureGatewayProfile's "already active" fast
   path then trusted the stale atom and skipped the re-swap forever.

2. Request-time routing for session-scoped RPCs. resumeSession's RPCs go
   through requestForSessionProfile (store/session-request-router.ts):
   when the active route serves the session's owning profile the ambient
   dispatcher is kept (reauth-aware reconnect); when it diverges — a
   concurrent switch won the mutex, a failed dial left the old socket
   active, an eviction re-pointed the route — the RPC is pinned to the
   owning profile's own socket via requestGatewayForProfile.

Diagnosed from zero trust's debug bundle (loki/hulk/teknium-kun backends
READY then idle-reaped, renderer stuck on "Waking up… → retries gave
up") and DanBennettUK's #89206 trace (profile socket accepts, closes
with messages=0, no resume RPC observed).

Both layers sabotage-proven: reverting the route publish fails the
lockstep/eviction tests; reverting the request-time routing fails the
wrong-socket dispatch test.
2026-08-18 14:09:08 -07:00
Teknium ced900a57d fix(desktop): file-path links in chat now open through the preview pane (#82140)
Assistant messages that link a file the agent wrote —
[report](/home/user/report.md), file://…, ~/…, C:\… — rendered as dead
anchors: file:// is blocked in the renderer, Streamdown's URL hardening
turns file:/~/ hrefs into "[blocked]" spans, and on a remote gateway the
path isn't on the viewer's disk at all. Issue #82140 proposed exposing
the Desktop connection mode to skills/MCP/plugins so EXTENSIONS could
emit different output per viewer; this fixes the symptom at the right
layer instead — the viewer surface resolves paths at VIEW time, so
extension output stays surface-agnostic and the same transcript works
from every machine that opens it.

- markdown-preprocess: routeFileLinksToPreview() rewrites filesystem-path
  links in prose to the renderer's existing hash-href doors —
  #preview/… (PreviewAttachment) for documents, #media:… for
  audio/video/image extensions. These pass URL hardening by design and
  resolve through normalizeOrLocalPreviewTarget / resolveMedia*Src:
  local connections read the file directly, remote connections fetch
  over the authenticated /api/fs bridge. Image syntax, fences, inline
  code, anchors, relative and http(s) links untouched.
- markdown-text: MarkdownLink routes any filesystem href that still
  reaches it (bypassing preprocess) to PreviewAttachment/MediaAttachment
  instead of a bare dead <a>.
- media.ts: export isFileMediaPath.

Live E2E (built app, CDP-driven, fixture session with links to a real
gateway-side file):
- BEFORE: [report.md] = dead <a href="/home/…"> (click: nothing),
  [notes](file://…) = "notes [blocked]" span, 0 preview affordances.
- AFTER: both render as attachment rows; Open preview shows the file's
  content in the preview pane; zero blocked spans; screenshots verified.

Closes #82140. Supersedes PR #82187 (connection-mode API): with view-time
resolution the extension layer no longer needs to know where the viewer
sits.
2026-08-18 14:09:01 -07:00
Teknium cb7dd6d2b8 fix(desktop): MEDIA-delivered .md opens in the preview rail, not as a download link
A `.md` delivered via MEDIA has no entry in MEDIA_BY_EXT, so mediaKind()
classified it as a generic 'file' and MarkdownLink rendered a download-style
anchor. Markdown is renderable content: route markdown document paths to
PreviewAttachment (source='tool-result'), which opens them in the right-rail
preview pane — where .md already renders with a rendered/source toggle and,
since #89381, full KaTeX math, tables, images, and links.

Resolves #84951 (the MEDIA delivery half; the rail-side rendering half landed
in #89381).
2026-08-18 14:08:52 -07:00
ethernet 1c4dc4cf5f fix(desktop): collapse the docked Bots tab with the sessions sidebar on narrow viewports
The Bots pane docks into the sessions zone but did not declare
collapsible. Below the sidebar-collapse breakpoint, the sessions pane
left the grid and the zone kept a stranded BOTS tab on screen.

The Bots pane now declares collapsible, so it leaves the grid with
its zone. The narrow edge overlay now mirrors the zone's tab strip
when the revealed pane has collapsed zone-mates. Without the strip,
only the first pane of the zone was reachable while collapsed. A
lone pane keeps the stripless overlay form.
2026-08-18 16:58:25 -04:00
hermes-seaeye[bot] f94cead337 fmt(js): npm run fix on merge (#89453)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-18 20:40:02 +00:00
ethernet 542e146b05 feat(desktop): show a hover close button on pane tabs
Each closeable horizontal tab now shows a close button when the
pointer is on the tab. A small gradient fades the button into the
tab surface, so long labels fade under it instead of a hard clip.
The gradient reads the tab's effective surface color. This color
tracks the hover and selection washes, so the fade is correct on
every theme.

Middle-click and Cmd-click still close the tab. Vertical rail tabs
keep those gestures and do not get the button.
2026-08-18 16:27:41 -04:00
Teknium 0093bc0fcc fix(skills): preserve manifest file mode across atomic rewrites
_write_manifest still used a hand-rolled mkstemp + atomic_replace,
so every sync reset .bundled_manifest to mkstemp's 0600, dropping a
group-readable or shared mode the operator had set. Replace the block
with utils.atomic_write_text(preserve_mode=True) — the same shared
writer and mode-preservation contract PR #86255 applied to the skill
manager's document writes.

This is the remaining half of PR #14410 by @sgaofen, who reported the
manifest mode reset first; the skill-manager half of that PR was
superseded by the atomic_write_text refactor and #86255.
2026-08-18 13:18:55 -07:00
Teknium 3701435306 test(desktop): align preview test comment with math-only normalizer 2026-08-18 13:18:41 -07:00
Peter 034589fa22 test(desktop): add behavior tests for .md preview math/table/img/link rendering
Export MarkdownPreview and cover the regression this PR fixes: KaTeX output present with no raw $$ delimiters left, GFM table structure, image alt/src, and external links opening with noopener noreferrer. Aligns the import order (perfectionist/sort-imports) and documents the mathPlugin module-scope setup to match the chat renderer.
2026-08-18 13:18:41 -07:00
Peter 6a3ef22346 fix(desktop): render math and missing markdown elements in .md file preview
The preview renderer for .md files was missing the math plugin, table/image/link components, and the markdown preprocessing pipeline that the chat transcript renderer has. Add KaTeX math rendering (inline $...$ and block $$...$$), table, image, and link support so file previews match the chat rendering.
2026-08-18 13:18:41 -07:00
Topher Ross c445cc4ebd test(desktop): fix lint in file-preview math render test 2026-08-18 13:18:41 -07:00
Topher Ross 0fa1212c97 test(desktop): prove file-preview math renders to KaTeX
DOM-level render test mounting the exact file-preview pipeline
(normalizeFilePreviewMath -> Streamdown + memoized math plugin) and asserting
`.katex` output for inline $.x.$, display $$..$$, and \(..\) delimiter math,
plus that a code-fence $.HOME.) stays code.
2026-08-18 13:18:41 -07:00
Topher Ross 93a2fae4e6 fix(desktop): render LaTeX math in file preview
The right-rail file preview rendered markdown through Streamdown with no
plugins and no math preprocessing, so $...$ and \(...\) stayed as raw
source text. Wire the memoized KaTeX plugin (same one the chat transcript
uses) into the preview and preprocess prose with a math-only normalizer that
skips chat-only transforms (reasoning-block stripping, session-ref linking,
preview-target stripping, URL autolinking, citation stripping) so a file's
prose, code fences, and inline code spans are never mangled.

- preview-file.tsx: import + module-scope createMemoizedMathPlugin, pass
  plugins={{ math }} to Streamdown, preprocess text with
  normalizeFilePreviewMath before render
- markdown-preprocess.ts: add exported normalizeFilePreviewMath
- markdown-preprocess.file-preview.test.ts: 8 tests (currency escaping,
  delimiter normalization, fence/inline-code preservation, verbatim
  citations/URLs/reasoning blocks)
2026-08-18 13:18:41 -07:00
Teknium c820a5d383 docs(teams-pipeline): document fetch --organizer-user-id
Follow-up to #89382: the operator runbook, bundled-skill docs page, and the
bundled SKILL.md now cover the organizer-scoped lookup flag and note that
/meet/ short URLs require it while webhook jobs derive the organizer
automatically.
2026-08-18 13:03:16 -07:00
vadelma-agent a34157c6ea test(gateway): fix background cleanup fixture
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 13:02:50 -07:00
kshitij e88d8831d2 refactor: consolidate owner extraction onto _owner_from_payload
_fetch_owner_handle and the browse catalog walk both inlined the
same owner-handle extraction logic that _owner_from_payload was
extracted to centralize. Replace both with calls to the helper.
2026-08-19 01:23:17 +05:30
xxxigm a6ddfa5769 test(skills): cover same-name inspect/install provenance mixup
Pin ClawHub to GitHub-style identifiers and keep catalog metadata
from being paired with a foreign same-named bundle.
2026-08-19 01:23:17 +05:30
xxxigm 696fef6214 fix(skills): keep inspect/install from mixing same-named hub skills
ClawHub treated the last path segment as a slug, so a GitHub-style
id like owner/repo/skills/skillopt fetched a different author's
skillopt. Pair metadata and files from the same source so inspect
cannot show one registry's header and another's SKILL.md.
2026-08-19 01:23:17 +05:30
Vadelma 6fccbdc54c test(skills): cover umask and explicit skill paths
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:52:53 -07:00
Vadelma 0b6e2bac2b test(skills): cover private supporting-file mode
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:52:53 -07:00
Vadelma 030687dcca test(skills): strengthen mode rollback coverage
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:52:53 -07:00
Vadelma 66fafebce0 test(skills): cover supporting-file patch rollback
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:52:53 -07:00
Vadelma f33831e4d9 test(skills): cover security-scan rollback modes
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:52:53 -07:00
Vadelma 968853c5b5 fix(skills): preserve document modes during atomic writes
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:52:53 -07:00
Vadelma 7d780ccb70 test(codex): cover retained fallback models
Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:51:36 -07:00
Vadelma 3a87f8767a fix(codex): drop unsupported pro defaults
Port the stale PR #61665 behavior to current main. The original two-file contribution is by yungchentang; this candidate preserves its scoped Codex OAuth fallback intent.

Co-authored-by: Taneli Mielikäinen <taneli.mielikainen@iki.fi>
2026-08-18 12:51:36 -07:00
Teknium de213b5210 chore: add contributor email mappings for vadelma-agent and tmielika
Maps vadelma@agenttiklubi.org and the bare noreply address to
vadelma-agent, and taneli.mielikainen@iki.fi to tmielika, so the
check-attribution gate passes on their open PRs (#70667, #72671,
#67934, #86255, #89194).
2026-08-18 12:38:10 -07:00
Teknium d03fe2adf4 fix: detect base64-encoded transcript markers in Graph ids
The getAllTranscripts resourceData.id from the field report is a base64url
blob whose DECODED payload ends in "-TranscriptV2" while the encoded form
contains no readable marker, so the substring heuristic in
looks_like_transcript_id missed it. Add a best-effort base64 decode hint so
degraded notifications (no @odata.id) are still refused with the clear
guidance error instead of a cryptic Graph 400.
2026-08-18 12:37:40 -07:00