cdce56faf239eaeebbccf312ed4fa13ec72be256
261 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4efdfb6d84 |
Merge remote-tracking branch 'origin/onboarding/next' into feat/store-guest-onboarding
# Conflicts: # apps/desktop/electron/window-focus-policy.ts # apps/desktop/src/components/assistant-ui/inline-preview-directive.tsx # apps/desktop/src/lib/chat-messages/parts.ts # apps/desktop/src/plugins/hermes-bots/types.ts # apps/desktop/src/sdk/index.ts # hermes_cli/plugins_cmd_install.py # hermes_cli/profile_distribution.py # plugins/web/keyless_mcp.py # tui_gateway/methods_profiles.py # tui_gateway/server.py # website/docs/developer-guide/relay-shared-metrics.md # website/docs/user-guide/features/web-search.md |
||
|
|
d802c47238 |
docs: one complete plugin catalog submission guide, synced with the README rules
Submitters only saw a stale 5-point summary on the catalog page (it even listed a 'Released' requirement nothing enforces), while reviewers applied ten README rules plus criteria written nowhere public (credentials, approvals, disclosure, compatibility metadata, forks of bundled plugins). - plugin-catalog/README.md: rules 11-15 write down those review criteria; the rule list sits between admission-rules markers. - New developer-guide page 'Submitting to the plugin catalog': before you submit, the PR flow, the full rule block (verbatim mirror), pin updates, delisting vs removal, asking for a hook. - The /plugins 'Submit' links and the user-guide section point at it. - tests/website/test_catalog_rules_mirror.py fails when the two rule blocks differ; classify_changes makes a README-only edit run it. - AGENTS.md, plugins/AGENTS.md and CONTRIBUTING.md reference both files. |
||
|
|
ff4760bfbd |
The first task after setup connects the picks and finishes something small within minutes (#129646)
* feat(onboarding): the first task chat delivers a small result in minutes Live runs on an RTX Spark showed the task chat surveying the whole machine, asking a plan question, and installing the picked plugins 11.5 minutes after setup. Its suggestions ignored the picks and the scan, and the handoff text said "Call me Sid." and "Start from this; look at my computer again...". - New optional skill first-task. start_chat appends it to the task chat's first message, after the ask and the "What setup learned" block, with a JSON block of the connector and plugin ids picked in setup. No system prompt changes. The history projection cuts the message at its marker, so no surface shows the skill. Its rules: connect and install the picks first, work visible in 1 minute and a finished result in 5, big asks cut to a first slice, three options only for a vague ask, machine setup as a short card interview. - setup_choose records the picked ids and the fork pick. The fork card is filled when shown: two first tasks from the picks and the scan (a daily brief from the picked apps, "Install a few apps for this Spark", a small page), then "I have something in mind", "Help me set up this <machine>", "Let's figure it out together". The machine-first "Something else" step, "automate" and "skip" rows are gone; "figure" hands off at once. - The handoff template is the ask only; no "Call me", no install or plan paragraphs. start_chat drops the "Start from this" line. - initiate-setup SKILL.md keeps only the setup beats (20.5 KB -> 10 KB). - Desktop shows the "What setup learned" block folded under the first message; the model still gets the full text. * fix(setup): one unexpected shutdown reads as singular |
||
|
|
cdb957e336 |
fix(onboarding/next): skill docs, the metrics schema and a BOM-safe read catch up with the merged waves
The merged Wave A and skill PRs landed without CI: the generated skill docs did not list initiate-setup, the shared-metrics v3 schema lacked the start_chat toolset, and the setup-profile marker read was BOM-intolerant on Windows. |
||
|
|
9bcbe7b5df |
feat(i18n): pluggable, layered language packs across core, Desktop and TUI (#126296)
* feat(i18n): layered catalogs — plugin packs and user overlay over bundled locales
* feat(tui): i18n layer — en catalog, nanostore runtime, RPC pack loader, _keys.tui.json emitter
ui-tui/src/i18n/: en.ts (facade over topical siblings under en/), types.ts
(Translations + dotted TranslationKey derived from en), runtime.ts ($locale/
$catalog atoms, translateFrom active→en→key, pack merge with string→fn
wrapping for {0}/{1} placeholders), loader.ts (display.language →
i18n.catalog {lang, surface:'tui'}, English when the method is missing),
useT()/useLocale() hooks, t() for non-React code. useConfigSync feeds the
loader from the existing config.get full hydration. `npm run i18n:keys`
writes locales/_keys.tui.json (sorted flat key list) and runs before build.
* feat(plugins): provides_locales manifest field, ctx.register_locale/register_locale_dir, manifest-only language packs
* chore(tui): split en catalog siblings by lane (slash sibling)
* feat(plugins): validate language packs — parse, text-only, key-subset WARN against en / _keys exports
* feat(tui_gateway): i18n.languages / i18n.catalog RPC + regenerated contracts
* feat(config): display.language accepts any supported_languages() id, refuses unknown ids with the list
* docs(i18n): language packs user guide, pluggable display.language, plugin developer section, AGENTS notes
* feat(plugins): report language-pack layers in the mid-run activation summary
* feat(tui): wire status bar, composer placeholders, hotkey help and approval/clarify/confirm prompts through i18n
StatusRule maps compared state values (ready/running…/summoning) to catalog
text at render via displayStatus(); hotkeys()/placeholder() resolve lazily so
a pack that arrives after boot applies. Catalog grows to 81 keys.
* feat(desktop): pluggable app locales — registry, host.i18n.registerAppLocale, backend packs, keys emitter
- Locale widens to string (BundledLocale keeps the union); TRANSLATIONS stays
the bundled record and every consumer resolves through the registry.
- src/i18n/registry.ts: registerAppLocale(id, {endonym, rtl, translations})
layers partial packs (nested or flat dotted) over bundled/en via
mergeTranslations; a string over a function-valued en entry becomes a
positional {0}/{1} formatter; $appLocaleVersion bumps so translators
re-render; per-source disposers + replaceAppLocaleSource for atomic swaps.
- Backend packs: i18n.languages + i18n.catalog {surface:'desktop'} feed the
registry as source 'backend' (method-not-found is silent); re-synced on
socket open, display.language change and profile switch. A saved pack-only
language is promoted once its pack registers.
- SDK: host.i18n.registerAppLocale / languageOptions; ctx.i18n.registerAppLocale
tracked for unload. Docs in the desktop plugin SDK guide + skill reference.
- Language switcher lists bundled ∪ registered ∪ backend, endonym-only; RTL
from the registry (applyDocumentLocale takes rtl).
- npm run i18n:keys emits locales/_keys.desktop.json (wired into build).
* i18n(cli): route /topup + /subscription copy through t() (cli.billing.*, cli.subscription.*)
Module-level copy tables and modal choice tuples in cli_billing_mixin.py froze
English at import, before display.language was known. They are now key tables /
builder functions evaluated at call time; every user-facing line in the /usage
balance block, /subscription and the five /topup screens reads the catalog.
Choice VALUES stay English identifiers. Fragment-assembled status lines
(Plan: … → cancels · $x left · renews …) become full templates.
* i18n(gateway): exec-approval card contract + base/run/run_busy/run_inbound replies through t()
- base_exec_approval: EA_* English constants stay; add ea_header_text()/ea_reason_label_text()/
ea_smart_deny_line_text()/ea_default_reason_text()/ea_action_labels()/approval_timed_out_notice()
accessors; deadline + timed-out notice resolve via gateway.exec_approval.*
- BasePlatformAdapter._EA_HEADER/_EA_REASON_LABEL/_EA_SMART_DENY_LINE/_EA_ACTION_LABELS become
properties (adapters still shadow them with markup class attrs)
- run.py: provider error replies table holds catalog keys; _CONTEXT_OVERFLOW_REPLY -> _context_overflow_reply()
- run_busy/run_inbound: typed approval + slash-confirm matchers accept English ∪ approval.inputs.* (t())
- locales/en.yaml: gateway.exec_approval/busy/errors/... namespaces
* i18n(cli): wire modal, loops, agent-setup mixins through t() (cli.* keys)
* i18n(platforms): route Slack, Matrix and Feishu user-facing text through t()
Exec-approval markup overrides (_EA_HEADER/_EA_REASON_LABEL/_EA_SMART_DENY_LINE/
_EA_ACTION_LABELS) become per-call properties over the shared
gateway.exec_approval.* contract keys, so Slack's 3000-char section budget
measures the resolved template. Slack _APPROVAL_DECISIONS/_CONFIRM_DECISIONS,
Feishu _APPROVAL_LABEL_MAP and Matrix _EA_LEGEND/_EA_TYPED_HINT turn into
key tables resolved at click time; the Matrix typed hints become whole
sentences per offered tier instead of spliced fragments. Slack button labels
are cut to 75 chars and select placeholders to 150 after translation; the
model-facing clarify fallback answer ('choice N') stays English while the
card copy localizes.
locales/en.yaml gains the gateway.exec_approval.* contract keys plus the
platform.shared.* / platform.slack.* / platform.matrix.* / platform.feishu.*
namespaces (and the keys for the other adapters wired in follow-up commits).
* i18n(gateway): run_turn / run_turn_runner / approval-settle copy through t()
- status hints, proxy errors, background task notices, progress heartbeats, session info lines
- tool progress chrome (tool_head/tool_pending/tool_preview/tool_verbose) shared by base.format_tool_event
- run_turn_runner:1406 Chinese clarify placeholder -> gateway.clarify.native_stream_placeholder (zh text kept in zh.yaml)
- _UNEXPECTED_SILENCE_REPLY/_CLARIFY_EXPIRED_NOTICE -> accessor functions
* i18n(platforms): route Google Chat and Teams user-facing text through t()
Google Chat clarify card, typing placeholder, orphan-card labels and the whole
/setup-files reply set (module constants become platform.google_chat.setup_files.*
keys resolved at reply time). The attachment-fallback notice that shipped
hardcoded in Spanish is keyed with an English en value; es.yaml carries the
original Spanish text for those four keys.
Teams approval card header/reason use the gateway.exec_approval.* contract,
_APPROVAL_LABELS becomes a key table resolved at click time, and the meeting
summary writer resolves its section headings/fallbacks per render.
* i18n(platforms): route LINE, WeCom, email, DingTalk, IRC and Home Assistant text through t()
LINE default copy constants become catalog keys resolved in __init__ (the
LINE_*_TEXT / extra.* operator overrides still win); the busy-ack bypass
matcher keys on the leading emoji marker only, so it keeps firing once the
gateway busy heads are localized. WeCom media size/format notices that shipped
hardcoded in Chinese are keyed with English en values and zh.yaml carries the
original Chinese text. DingTalk emotion bubbles resolve per send.
* i18n(cli): route /model switch output and -q status lines through t() (cli.model.*, cli.single_query.*)
Switch-summary labels shared with the gateway reuse gateway.model.* keys
(provider/context/max-output/capabilities/prompt-caching); CLI-only variants
(glyph or no-backtick forms) live under cli.model.*. The hand-padded /model usage
block becomes a (form, description-key) table padded at render time so the
command syntax stays fixed while descriptions translate. -q 'Error:' reuses
gateway.model.error_prefix.
* i18n(cli): route TUI panel/hint/placeholder copy through t() (cli.tui.*)
_APPROVAL_CHOICE_LABELS and _TUI_MODAL_HINTS become key tables resolved at
render time; vault/sudo panel bodies are one catalog value per panel split on
newline; inline plurals use <key>_one/<key>_other. Adds the cli.* namespace
(shared/tui/voice/render/subagents/dock) to locales/en.yaml.
* i18n(cli): voice/wake-word CLI copy through t() (cli.voice.*)
RuntimeError texts raised in _voice_start_recording are human copy (callers
print {e}) and are keyed; the Termux requirement-check match stays English.
Wake state ids stay internal, only their labels localize.
* i18n(cli): live-work dock, subagent monitor and render copy through t()
cli.subagents.* / cli.dock.* / cli.render.*; count fragments pluralize via
_one/_other keys, verdict table holds keys resolved at paint time so width
clipping measures the translated text.
* i18n(gateway): unauthorized/pairing, voice, topics, shutdown, startup, notifications, kanban pings through t()
* i18n(cli): move tips + composer placeholders into the catalog (tips.tNNN / tips.placeholder.pNN)
get_random_tip()/get_random_composer_placeholder() pick a key from the English catalog
(the parity baseline, probed once per process) and resolve it through t() for the active
language, so language packs translate tips like any other string. Also lands the cli.*
en.yaml namespace consumed by the CLI info/help/error-copy wiring in the next commit.
* i18n(cli): wire chat-turn + session mixins through t(); kanban log trimmer matches t() output
* test(cli): assert TUI/dock/voice copy via t(key); prove labels resolve at render time
Pinned-English assertions in the approval-UI, live-work dock and voice tests now
go through the catalog. New test swaps the catalog after import and checks the
approval panel + hint row follow it (the reason _APPROVAL_CHOICE_LABELS and
_TUI_MODAL_HINTS became key tables).
* i18n(cli): route CLI info/help/error copy through t() (cli.* namespace)
cli_info_mixin: /help consumes CommandDef.describe() (added to commands.py: slash.<name>.description
with fallback to .description), section titles/skill/quick-command headers, /tools, /toolsets,
/usage labels, /context, /whoami, /insights, /gateway status, tool-progress labels, bang-shell
denials, MCP config-watch + /reload-mcp confirm/reload lines, /reload-skills, and the session-store
warning all read the catalog at call time (module-level label tables became functions so the
active language is honoured after startup). cli.py: worktree cleanup, tirith warning, show_config
(labels re-padded at print time), quick/plugin/skill slash-command errors, ambiguous-command hint,
stdin error, gateway start, profile warning. cli_chat_error_copy / cli_unknown_command /
cli_output / cli_init_mixin: chat error panel copy, did-you-mean lines, n-more / yes-no prompt
(localized affirmative initial alongside 'y'), unknown-toolsets warning.
* i18n(w1a): wire agent display/explainers/approval + slash registry/help through t()
- hermes_cli/commands.py: CommandDef.describe() resolves slash.<name>.description
at call time; category labels via slash.category.*; help/alias/usage suffixes
via slash.shared.*; gateway_help_lines and commands_platforms/slash_exec use them.
- agent/display.py: display.verb.* resolved at call time via get_tool_verb();
bridge/spinner/thinking-verb/cute-row/failure/preview/diff text via display.*.
- agent/turn_explainers.py: exit-reason / persistence-cause tables become call-time
lookups (explainer.exit.*, explainer.persistence.*, explainer.file_mutation.*).
- agent/background_review.py, session_activity.py, context_breakdown.py,
status_output.py: review summaries, iteration progress, context notices.
- tools/approval.py, approval_context.py: approval.summary.*, approval.noun.*,
approval.window.* pluralized keys.
- gateway/slash_commands*.py: remaining raw strings (busy, whoami, platform,
bundles, memory, skills, approvals, set_home, diff, update, debug, profile,
heartbeat, refine, review, subgoal, loop, retry, compress codex path, save,
sessions, model guard/errors, agents rows, topup, login). HISTORY_UNREADABLE
keeps its English constant; callers use history_unreadable() ->
gateway.shared.history_unreadable.
- locales/en.yaml: new approval/display/explainer/slash blocks + gateway leftovers.
* i18n(telegram): route adapter chat copy through t()
Approval card (header/reason/smart-deny as HTML-escaped properties), inline
button labels, callback toasts (cut at Telegram's 200-char cap), model/choice
pickers, clarify/update/slash-confirm prompts, gmail-triage labels and the
inbound-media failure notice now come from the catalog. _UNAUTHORIZED is a
lazy _unauthorized() so the import no longer binds a language. The command
menu carries a language+payload fingerprint (forum scopes re-register on
change) and BotCommand descriptions are cut at 256.
Adds gateway.exec_approval.* (WAVE2 contract), platform.telegram.*,
platform.discord.* and the slash.*.description keys the Discord table shares
with the CLI registry to locales/en.yaml.
* i18n(gateway/platforms): whatsapp_cloud, yuanbao, weixin, signal, api_server copy through t()
- whatsapp_cloud: clarify list/buttons, approve/deny + slash-confirm labels via platform.whatsapp.* (t()-then-truncate at 20/24/72 caps); _EA_HEADER becomes a property wrapping ea_header_text()
- yuanbao: SLOW_RESPONSE_MESSAGE -> slow_response_message() (platform.yuanbao.slow_response_notice; zh keeps the original text); cron-wrapper markers centralized as module constants for strip_cron_wrapper
- api_server: PROVIDER_AUTH_FAILED_LABEL/PROVIDER_RATE_LIMITED_LABEL stay English for run.py matchers; user_text() renders via t()
- signal/_format_wait, weixin voice caption, openai_routes transformed notice
- run_turn: second _UNEXPECTED_SILENCE_REPLY consumer -> accessor
* i18n(discord): route adapter chat copy through t()
Native slash-command table becomes _NATIVE_SLASH_COMMAND_SPECS holding catalog
keys; _native_slash_commands() resolves descriptions, parameter descriptions
and Choice names for the active language, each cut at Discord's 100-char cap,
and the app-command sync fingerprint now includes get_language() so a
display.language change re-syncs. Exec-approval card (gateway.exec_approval.*
contract), slash-confirm / clarify / update views, model+choice pickers,
thread creation, forum titles, voice acks, the response-truncation notice,
the unauthorized-slash security alert and the media upload-size notices all
read from platform.discord.*. Decorator-declared button labels are relabelled
in __init__ (80-char cap); embed titles cut at 256, select placeholders at
150, option label/description at 100. _UNAUTHORIZED is a lazy _unauthorized().
* i18n(cli): wire status-bar, stream, terminal mixins + terminal_input through t(); rename kwargs that shadow t(key)
* i18n: wire hermes_cli/cli_commands_mixin.py slash-command copy through t()
- 431 new leaves under cli.commands.<cmd>.* in locales/en.yaml; 12 rows reuse
existing gateway.* keys (rollback, diff, resume, branch, btw, model, reasoning)
via a _gt() helper so CLI and gateway replies stay identical.
- Module-level English tables (_BUSY_MODE_*, _REASONING_TOGGLES, _HATCH_PROGRESS,
_DIFF_LABELS, _LOCAL_ENGINE_LINES) become call-time catalog lookups keyed by id.
- Verb tables (Enabling/Disabling, Paused/Resumed/Triggered, planned/done,
Updating/Generating) are one full template per variant; plurals use
<key>_one/<key>_other via _tn(); hand-padded column labels (/snapshot list)
translate the value and re-pad at the call site.
- Multi-line usage blocks are single catalog values split with _lines().
- Model-facing system notes and DB-stored reasons stay English (EXCLUDED).
* tests: assert /handoff, /worktree, /login CLI copy via t(key) instead of pinned English
* test(i18n): pin Telegram/Discord adapter catalog wiring
Lazy unauthorized notice, exec-approval contract keys, HTML escaping before
Telegram <b> wrapping, 200-char toast / 256-char BotCommand caps, Discord
100-char app-command text and 80-char button caps, and language-bearing
command-menu fingerprints on both platforms.
* i18n: reconcile cli.shared on/off vs enabled/disabled after lane merge
* i18n: describe() in TUI-gateway slash listings; localize TUI exit resume hint
* i18n(tr): translate bundled catalog + tui pack
* i18n(ja): translate bundled catalog + tui pack
* i18n(ko): translate bundled catalog + tui pack
* i18n(zh): translate bundled catalog + tui pack
* i18n(fr): translate bundled catalog + tui pack
* i18n(af): translate bundled catalog + tui pack
* i18n(uk): translate bundled catalog + tui pack
* i18n(ar): translate bundled catalog + tui pack
* i18n(pt): translate bundled catalog + tui pack
* i18n(it): translate bundled catalog + tui pack
* i18n(es): translate bundled catalog + tui pack
* i18n(zh-hant): translate bundled catalog + tui pack
* i18n(ru): translate bundled catalog + tui pack
* i18n(hu): translate bundled catalog + tui pack
* i18n(hu): translate pre-existing English-valued leftovers (kanban wake, /context, /status, fast labels)
* i18n(de): translate bundled catalog + tui pack
* i18n(ga): translate bundled catalog + tui pack
* test(i18n): fixture matches _normalize_lang(lang, home) signature
* i18n(tui): scaffold userMessages/slashCmd en siblings
* i18n(tui): wire secure prompts + content tables
* feat(tui): i18n — wire billing, subscription, connection-setup and journey overlays
Adds en siblings billing.ts / subscription.ts / connection.ts (namespaces
billing, subscription, connection, journey) and routes every user-facing
literal in billingOverlay, subscriptionOverlay, connectionSetupOverlay and
journey through useT()/messages(). Module-level label tables became lazy
(scopeStillDeniedResult(), verbOf(T, action)); auto-reload rows dispatch on
stable ids instead of label text. Regenerates locales/_keys.tui.json.
* i18n(tui): wire slash ops/wake replies
* i18n(tui): wire pickers (modelPicker, activeSessionSwitcher, petPicker)
* i18n(tui): wire slash core/debug/setup replies
* i18n(tui): wire hubs (agents overlay/panel/controls, skills, plugins)
* i18n(tui): wire slash session/topup/subscription replies
* i18n(tui): wire chat bits (branding, thinking, messageLine, loaders, todo, queued, banner, entry)
* i18n(tui): register t3 siblings (pickers, hubs, secure, content, chatBits) and regenerate keys
* i18n(tui): wire userMessages copy through the userMessages namespace
* i18n(tui): lazy-copy test for userMessages, regenerate _keys.tui.json
* i18n(tui): wire session/gateway/lib text through the TUI catalog (lane t2)
Adds en siblings session.ts, gatewayMsg.ts, libText.ts (namespaces session,
gatewayMsg, libText) and routes user-facing literals in app/{useMainApp,
useSessionLifecycle,useInputHandlers,turnController,createServerRequestHandler,
setupHandoff,createGatewayEventHandler}.ts, gatewayClient displayed reasons,
lib/*, domain/*, hooks/* through t()/messages(). Status-bar state values that
code compares against, backend-matched strings, log lines, model-bound text,
and machine 'error:' prefixes stay literal. Regenerates locales/_keys.tui.json
(232 keys).
* i18n: serve bundled locales/<lang>.tui.yaml under overlay/packs; TUI pack parity test; regen _keys.tui.json (1250)
* i18n: translate pre-existing English stubs in bundled locales (424 leaves, 14 locales)
* tui: i18n-export-en script (English templates for pack translators)
* docs(i18n): bundled TUI packs are the bottom layer of the tui surface
* i18n(ru): translate TUI pack
* i18n(ar): translate TUI pack
* i18n(es): translate TUI pack
* i18n(pt): translate TUI pack
* i18n(ko): translate TUI pack
* i18n(de): translate TUI pack
* i18n(ja): translate TUI pack
* i18n(fr): translate TUI pack
* i18n(tr): translate TUI pack
* i18n(it): translate TUI pack
* i18n(zh): translate TUI pack
* i18n(zh-hant): translate TUI pack
* i18n(hu): translate TUI pack
* i18n(uk): translate TUI pack
1,169 missing keys translated; 81 pre-existing kept byte-identical. Parity OK missing=0 extra=0 placeholder_mismatch=0 empty=0.
Deliberately identical to en: chatBits.branding.mcpSummary ({0} MCP), chatBits.thinking.agentsHint ((/agents)), session.main.voiceStt (◉ STT), session.main.voiceTtsSuffix ( [tts]), slashCmd.core.help.tuiSection (TUI), slashCmd.core.history.hermesTag (Hermes #{0}), slashCmd.debug.heapdump.heapPath (heapdump: {0}), slashCmd.debug.mem.rss (rss), subscription.stepUp.title (Remote Spending — product feature name, as in core catalog), content.faces.* (glyph-only kaomoji).
* i18n(ga): translate TUI pack
* i18n(af): translate TUI pack
* plugin_guard: locale catalogs in language packs step down the agent-config family
A translated status line such as "Updating AGENTS.md" in locales/<lang>.yaml is UI text the loader
reads as a string leaf; it cannot edit a file. The bundled en.yaml itself tripped agent_config_mod
at critical, making any faithful language pack uninstallable. Injection shapes keep full severity.
* plugin_validate_locales: read key exports with utf-8-sig (Windows footgun lint)
* i18n(relay): route relay adapter prompt copy through t(); drop dead import-bound approval header
Adds platform.relay.* (5 keys) to en and all 16 bundled locales, reusing the sibling platform
translations for the confirm buttons and the Other option.
* ci: fix TUI import order, MDX table pipe, main's overflow-warning wording in all locales; fresh-install fixture carries the i18n kernel
- ui-tui/src/i18n/en.ts: perfectionist/sort-imports (slash before slashCmd)
- docs plugins/index.md: escape the | inside the provides_locales table cell (MDX parsed <id> as JSX)
- display.notice.uncompressed_context_overflow: adopt main's wording (names compression.enabled: false
and /compact) in en + 16 locales; the guardrail test pins that phrase
- tests/scripts/test_fresh_source_install.py: the installer tail now resolves CLI text through
agent.i18n, so the fixture tree carries the i18n kernel + en.yaml (not the agent runtime)
* docs(desktop-plugin-sdk): double-backtick the template-literal example (MDX evaluated ${n})
* test(e2e): display.language is validated against the live language set; exclude it from the arbitrary-string set property
* commands: keep the localized COMMANDS/COMMANDS_BY_CATEGORY module __getattr__ after the compat block removal
* build: never write locales/_keys.*.json from the desktop/TUI builds; regenerate the committed desktop key export
The desktop build regenerated locales/_keys.desktop.json in the checkout, so a
hermes update that rebuilt the app left the tree dirty (Desktop update E2E:
'M locales/_keys.desktop.json'). The key exports are committed artifacts pinned
to en.ts by apps/desktop/scripts/i18n-keys.test.mjs and ui-tui i18n:keys:check;
builds read them, never write them. Regenerated after main's new desktop strings.
* test: unbreak two main-red timing tests the PR merge-ref inherits
- test_local_runtime racing fake publishes the modern state record (legacy pid-only
records are rejected since 65ff3ad353; main has been red on this test since)
- test_run_progress_topics ManyProgressLinesAgent waits for the first bubble instead of
a fixed 0.35s, which a loaded CI runner does not always meet
* chore(i18n): regenerate desktop key catalog for main's new strings (model pricing, copy changelog)
* test(e2e): torture-chamber fd monitor confirms a deleted sidecar is still held before calling it a leak
SQLite's WAL last-close unlinks -shm before closing its descriptor (unixShmUnmap, then
unixShmPurge), so a healthy close shows a (deleted) -shm for microseconds; the 20ms poll
occasionally caught that window on the short-lived opener and failed the episode.
* chore(i18n): regenerate desktop key catalog for main's telemetry/consent strings
* chore(i18n): regenerate desktop key catalog after main sync
---------
Co-authored-by: Teknium <teknium@nousresearch.com>
|
||
|
|
a7c080ca66 |
feat(skills): brag and brag-slim join the optional-skills catalog as upstream stubs
latent-spaces/brag (MIT) turns the project you just built into a short launch video with music, motion and share copy. It ships two skills: /brag, the Hyperframes workflow with a bundled music and SFX library, and /brag-slim, a single SKILL.md where the model builds the whole video with local tools. /brag hands off to its bundled copy of brag-slim on Claude Opus 5.5. Both follow the impeccable/archify pattern: catalog stubs whose metadata.hermes.upstream pointer makes `hermes skills install official/creative/<name>` pull the live tree through OptionalSkillSource._fetch_from_upstream. Nothing is vendored. The brag stub documents that its Hyperframes path loads HeyGen's hyperframes-* domain skills by name, and that the skills guard blocks four of the five today (hyperframes-creative scores dangerous). brag-slim has no such dependency. Docs: two generated pages, two catalog rows, two sidebar lines. Credit: Shunit Haviv Hakimi (shunithaviv), upstream author. |
||
|
|
3f4b8840f1 |
Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts: # pyproject.toml # tests/fixtures/resolution_allowlist.json |
||
|
|
7ed6534c7e | Merge origin/main: browser fence composed with the dispatch/retry split (#115184); server registration, i18n, contracts | ||
|
|
207f8fedfd |
Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts: # hermes_cli/local_runtime/binaries.py # hermes_cli/plugins_cmd.py # hermes_constants.py # tests/test_hermes_constants.py # tests/tools/test_clipboard.py # tests/tools/test_voice_wsl_pipewire.py # tools/computer_use/cua_backend.py # tools/voice_mode.py |
||
|
|
4094ab610d |
hermes_platform.resolver: locate/inspect/probe tiers, AppResolver, gh lookup migrated (NS-921) (#118065)
* feat(platform): resolver core with locate/inspect/probe tiers and ordered candidates Every resource lookup needs one result shape and one cost contract. `locate` reads metadata only, `inspect` may open files and call OS APIs in-process, `probe` is fresh and the only tier that may spawn or connect. `Resolution.candidates` keeps probe order so fan-out consumers can try every present binary. Linear NS-921. * feat(platform): AppResolver over AppDef with plist, PE, registry, and server.json sources Desktop apps need presence, version, and liveness as separate observations. The runtime file's bearer token is parsed, used for one request, and discarded inside the probe; no public type carries it. Endpoints are accepted only when loopback with a numeric port. * refactor(copilot): gh candidates through locate_command and the Homebrew table First consumer of the resolver. The gh token probe still tries every present binary in order; the allowlist loses its two copilot_auth rows. * feat(platform): availability() over an application declaration locate() + inspect() only, never probes; the fail-closed _version in app.py treats a vendor's plist/PE/registry entry as untrusted input. Salvaged from PR #118122; reads any object with requires_app, min_version, app_for(os) — nothing here imports the MCP catalog. * feat(platform): application declarations parsed into AppDef per OS The parser slice of PR #118122's catalog manifest, re-homed as a catalog-free module: whoever owns an MCP server declares the app it fronts per OS and what it needs, and registers it here. Stdlib + hermes_platform.resolver only. register/lookup/clear are the one seam the MCP check_fn and the skill gate both read. * feat(mcp): check_fn honours a registered application declaration _make_check_fn ANDs the declared app's availability into the connection-alive check; with nothing registered for the server the behaviour is the pre-PR3 connection check. Provenance is explicit registration, not endpoint matching. Returns a plain bool: the registry caches bool(fn()). * feat(skills): requires_apps gate through registered declarations Offer-time filter beside environments:; names resolve through hermes_platform.declaration, an unknown name hides the skill (fail closed). The disk snapshot carries requires_apps and the fast path re-evaluates it (snapshot version bumped to 3): app presence is a host fact that changes without SKILL.md changing. * docs: application declarations page The plugin-facing schema reference: app: and requires: blocks, availability() states, and the two gates that read the registry. Registered under Extending > Plugins in the docs sidebar. * test(platform): declaration parser, availability, gates The PR3 app-block tests re-homed off the catalog: fixtures are dicts passed to parse_declaration, the check_fn gate keys on explicit registration (not endpoint matching), and the import-hygiene probe now covers hermes_platform.declaration and resolver.availability. |
||
|
|
1f38e868ea |
docs: register the pm/release developer pages in the sidebar
The five pages moved from docs/ into website/docs/developer-guide were never added to sidebars.ts, so the site did not link them, and they kept repo-relative links (../tests/..., ../scripts/..., ../website/docs/...) that only resolved from the old docs/ location. Register them under a Packaging & Releases category and point the repo-file links at GitHub; package-management.md now links the moved completion note in place. |
||
|
|
793605bc78 |
merge origin/main (7 commits) into ethie/pm-clean
Host-scoped update-restart obligation ( |
||
|
|
5bb314fa01 |
docs: link the Skills and Plugins hubs from the doc sidebar
The hubs are navbar-only. On a phone Docusaurus opens the drawer on the doc sidebar and puts the navbar behind 'Back to main menu', so mobile readers cannot find Skills or Plugins at all. Two top-level sidebar links make them one tap away on every doc page (desktop sidebar too). |
||
|
|
9f2ba1b74d |
merge origin/main (779 commits) into ethie/pm-clean
Branch semantics kept where main and PM disagree: update_cmd_deps.py, constraints-termux.txt, the Electron update-api-check module and the post-swap hand-off test stay deleted; the pending-fleet-restart catch-up and the local_runtime tag/download ladder stay retired (PM owns engines). Ported from main onto the branch's shape: profile_scoped_chore for the auto-archive and plugin-update housekeeping chores, the local-runtime cross-process boot lock and residency cap, the checkpoint tmp_pack sweep, the cua daemon-liveness status probe, the remote-served Desktop update flag (posix.sh / windows.ps1), sign-in for env-pinned remote gateways (urlDisabled on RemoteSetupFields), the uvloop extra split (uvicorn without [standard]), and the umask-scoping spawn test. uv.lock regenerated with pm.build_env --lock-only; new utf-8 reads from main switched to utf-8-sig (check-windows-footguns). |
||
|
|
6ba45b0e06 |
fix(sessions): storage maintenance refuses while a writer holds state.db; human-first retired-WAL guard text + recovery guide
`hermes sessions optimize`, `optimize-storage` and `prune` now run the same fail-closed holder scan doctor and repair use before rewriting the store. While a gateway, Desktop, dashboard or cron process holds state.db (or a WAL sidecar) they print each holder as `PID N (command)` with the stop remedy and exit 1; `--force` overrides with a warning, `--dry-run` previews are never gated. The Desktop console's `sessions optimize` gets the same refusal. Why: a user ran `optimize-storage` under a fleet of eight live gateways and every agent answered every turn with the retired-WAL refusal until all writers were stopped by hand (#110054, maintainer follow-up 09-20). The DeletedWalGenerationError text is now two layers: a first sentence for the person reading a chat bubble or banner (what happened, nothing is lost, quit every Hermes process on the profile, `hermes doctor` names the holders, never `doctor --fix` or delete files while they run, docs link), then the operator detail. The classifier fingerprint "deleted state.db-wal or state.db-shm" is unchanged. The cause table (`hermes_state_user_copy`, feeding the CLI banner, TUI/Desktop RPC error and the gateway home-channel notice) and the chat explainer carry the same first steps; the gateway notice no longer hardcodes `doctor --fix` + `gateway restart` for every non-corrupt cause, which for a held retired generation is the second-writer trap. New user-guide page `session-storage-recovery.md` (registered in sidebars, linked from the guard text, the developer state-db-recovery page and the sessions guide): the three steps, the do-nots, why maintenance refuses, and what the files beside state.db are (retired-wal captures + manifest.json, pre-update-emergency backups, corrupt backups, snapshots). |
||
|
|
2a1ec15a6f |
docs(website): regenerate the skill docs from the shipped skill tree
website/scripts/generate-skill-docs.py is the documented source of both catalogs and of the per-skill pages, but nothing compares its output with what is committed, so the committed copies drifted: - optional-skills-catalog.md was missing agent-merge-conflict-arbiter and listed pr-lens under blockchain (it lives in software-development); - skills-catalog.md still listed merge-reconciler, which #98539 moved out of the bundled set; - 196 pages and both catalogs carried Windows path separators — in the Path column and inside GitHub blob links, where a backslash is a broken URL. This commit is the generator's output (re-running it on this branch is a no-op), plus the orphan page #98539 left behind for merge-reconciler: no skill backs it, its catalog row is gone, and no page links to it. tests/skills/test_skill_docs_contract.py is the guard: the next skill that ships without a catalog row, or a page regenerated on Windows, fails there instead of on the published page. |
||
|
|
b4a294fff9 |
Merge origin/main; keep PM as plugin dependency owner
Reconcile plugin declarations and validation through PM's atomic generation publication; preserve external runtimes, target markers, and conflict refusal. Keep one source-update completion owner and port upstream lifecycle changes to the PM desktop/runtime paths. |
||
|
|
1a4d876176 |
Merge origin/main: profile-scoped browser env, sudo prompt copy, clone special files
Conflicts (all keep-both): tools/browser_tool.py takes main's scope-bound passthrough + loopback NO_PROXY and still routes the env through the Bot Desktop's desktop_env; i18n gains main's sudoDesc/sudoCommandUnavailable beside our sudoInstallDesc; test_profiles keeps both sides' new tests. |
||
|
|
1034215ae8 |
docs(free-tier): drop the rehearsal page and its references
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
51e39af967 |
feat(free-tier): ruled behaviour for every welcome-api failure, with friendly copy and a fault-injecting rehearsal server
The free tier depends on the account service (NAS) and the welcome inference host, and Hermes had no honest answer for most of the ways either can refuse or fail: the NAS codes it matched were never sent, the tier-dark 403 carried no message to match, a single boot-time blip disabled minting for the whole process, and a structured rate-limit refusal never reached the cross-session guard, so the "sign in for a bigger allowance" prompt was dead code. Backend - anon_auth: classify what NAS actually sends (404 not_found, 503 temporarily_disabled, 429 + Retry-After, 428 pow_*, 403 account_locked) into one ANON_* code each, carrying retry_after / retryable on AuthError. - Replace the process-lifetime mint memo with a per-profile cooldown that honours the server's wait, climbs a short ladder when the service is unreachable, never retries terminal codes, and yields to the user's own retry (force=True). - Bootstrap record carries error_code / retryable / retry_after; a bounded background loop retries transient failures and re-announces setup.ready. setup.status and free_tier.status expose the block; free_tier.provision is the forced retry. - Inference: a generic 403 from a welcome host is the tier refusing (keyed on the route); model_not_free moves onto the gateway's alternate once; anon_on_paid_host re-reads the route once; a long rate_limited refusal trips the cross-session guard; a locked account is retired but never replaced; terminal copy on the free route is one plain sentence. - Sign-in: Failed keeps the service's code and wait; account_busy is retryable; the OAuth poll reports retryable / retry_after. - All user-facing copy rewritten for first-time users: never "the free service is off" (what is unavailable is using Hermes without signing in, and signing in is free), no jargon, spoken waits. Desktop - A setup-failure notice above the provider picker: one sentence per code, a retry when the backend says one can work, the sign-in pointer only when the account service answered at all. The overlay re-checks readiness on setup.ready so a background success dismisses it. - Sign-in dialog gains busy / unreachable / unavailable screens. Rehearsal - scripts/free_tier_fault_server.py stands in for both services with the real wire contract and a CORS-open scenario switch; HERMES_EXTRA_WELCOME_HOSTS (dev-only, env-only) lets the route rules treat it as the welcome host. Walkthrough in website/docs/developer-guide/free-tier-fault-rehearsal.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
398279fd6a |
feat(skills): add ip-as-logo optional skill (minimal cute IP mascot marks)
Ports s1dashu/ip-as-logo-skill (MIT, 3.2k stars in 48h, snapshot of commit b1bf517c) into optional-skills/creative/. Generates extremely simplified, cute IP mascot characters readable at 32x32 — 3-color discipline, corner-emergence composition, complexity budget, and a copy-paste prompt skeleton. Hermes adaptations (blockquote header + inline edits, upstream body otherwise intact): - image path routed through the built-in image_generate tool (square aspect, main-prompt constraints mode — no negative_prompt parameter exists) - subagent parallelization mapped to delegate_task, optional - delivery per platform file conventions; no auto-QA (per upstream's own one-pass-draw rules) - live-test friction fixes folded in: reduced-batch labeling branch, proposal-round skip for pre-authorized batches, dimensions-reporting rule when the backend returns only a URL, limbless-subject note Validated via a cold subagent run (2 candidates for a real brief): both generations succeeded first-draw, verdict SHIP; its three friction findings are addressed in this commit. Docs: catalog row + sidebar line + generated skill page (scoped to this skill only; regen drift for unrelated pages reverted). Credit: s1dashu (https://github.com/s1dashu/ip-as-logo-skill) |
||
|
|
251ab05000 |
feat(skills): add auteur optional skill — cinematic web design with executable anti-slop gates
Port of agiwhitelist/auteur (MIT, ~1k stars), snapshot 9bca227d. Three registers (build / direct / system) on one taste core: commit-sheet-first art direction, asset generation via image_generate + local CLIs, and node-based quality gates (slopscan anti-slop linter, motionqa frame-drop check, systemscan cross-route drift) run through playwright. - optional-skills/creative/auteur: SKILL.md (de-Clauded, Hermes tool framing), LICENSE (upstream MIT), 11 references, 8 verbatim upstream .mjs scripts (all pass node --check; slopscan smoke-run verified), 6 templates. README gallery assets not vendored (size cap). - tests/skills/test_auteur_skill.py: frontmatter, path-annotation invariant, de-Claude residue, related_skills resolution. - Docs: catalog row, sidebar entry, generated skill page (scoped regen). |
||
|
|
788601358d |
refactor(skills): live-dashboard becomes an optional skill reconfigured for the Desktop app
Why: the web dashboard is being deprecated in favour of the Electron Desktop app, and a skill that ships a bespoke cron blueprint should not be bundled by default. Reconfigure instead of just rebasing: - Move skills/productivity/live-dashboard -> optional-skills/productivity/ live-dashboard (install with `hermes skills install official/productivity/live-dashboard`); register it like every other optional skill: per-skill docs page under user-guide/skills/optional/, optional-skills-catalog row, sidebars entry. - Desktop reality: add a "Show the dashboard" step — when `desktop_preview` is in the toolset (Desktop/GUI sessions) render index.html in the in-app preview pane after every build/tick and on request; otherwise report the absolute file path. Prerequisites section added (Enough1122 review). - Drop the hard-wired cron/blueprint_catalog.py entry: the curated catalog is for bundled skills and would preload a skill that may not be installed. Use the skills-pipeline blueprint instead — `metadata.hermes.blueprint` on the SKILL.md registers a daily all-dashboards sweep as a /suggestions entry at install time (opt-in, never auto-scheduled), which is exactly the mechanism main provides for optional skills. - Never hardcode ~/.hermes in prose the agent executes: refer to the Hermes home directory's dashboards/<slug>/ and write absolute paths into cron prompts (also answers the review's "tick prompt must name the state-file path" point). - Tests follow the skill to optional-skills/, the catalog-blueprint tests are replaced by one parse_blueprint/blueprint_to_job_spec invariant and one desktop_preview-with-path-fallback invariant. |
||
|
|
2154458685 |
Inspired by Energy: one-sentence live dashboards — bundled skill + automation blueprint
Energy (getenergy.com) ships natural-language persistent dashboards: describe what you want to see in one sentence and the agent builds a self-updating status page fed by email threads, signed-in websites, and files. This ports the concept onto Hermes's existing cron + connector architecture: - skills/productivity/live-dashboard: setup/tick split skill — pin the dashboard contract, verify one live read per source before scheduling, keep dashboard.json as source of truth with a self-contained HTML projection, stale-read discipline, deliver only on material change. - cron/blueprint_catalog.py: live-dashboard automation blueprint (purpose/sources/time/recurrence/deliver slots) rendering to the dashboard form, /blueprint command, and hermes:// deep-link. - tests/skills/test_live_dashboard_skill.py: skill standards + blueprint registration + real fill_blueprint E2E. - docs: per-skill page, skills catalog row, sidebar entry. |
||
|
|
e4f591d1b0 |
Merge origin/main: wire-contract registry + server→client requests + screenshot dedup
Main replaced every *.request/*.respond event pair with real JSON-RPC server→client requests and made Python the single source of the wire (tui_gateway/contracts → generated TS). Bot Screen now speaks that dialect: - tui_gateway/contracts/display.py declares the eight display.* methods, the display.install.sudo server request and the four display.* events; the generated TS/OpenRPC is regenerated. - The install sudo card is a `display.install.sudo` server request (app-level, empty session); the desktop answers it through respondToServerRequest, so the respondMethod/origin plumbing that pinned a reply to its socket is gone: a JSON-RPC response cannot land elsewhere. - screen-connection.ts consumes the generated DisplayStatus/DisplayLease instead of hand-typed copies (holder named by viewer_hash only; epoch always present). - computer_use: the lease fence and main's screenshot-dedup session key ride the same read handlers; the fence fires before a frame reaches the dedup cache. - server.py keeps the display module registration a naive --theirs would have dropped. |
||
|
|
612d542281 |
Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts: # .gitignore # Dockerfile # agent/onboarding.py # apps/desktop/electron/main.ts # apps/desktop/electron/pool-stop.ts # apps/desktop/src/components/model-picker.test.tsx # apps/desktop/src/store/updates.ts # apps/desktop/vite.config.ts # datagen-config-examples/run_browser_tasks.sh # docs/rca-ssl-cacert-post-git-pull.md # gateway/run.py # hermes_cli/backup.py # hermes_cli/credential_lifecycle.py # hermes_cli/dashboard_procs.py # hermes_cli/doctor_state.py # hermes_cli/env_loader.py # hermes_cli/gateway_windows.py # hermes_cli/local_runtime/endpoint.py # hermes_cli/psutil_android.py # hermes_cli/update_cmd.py # hermes_cli/update_cmd_windows.py # hermes_cli/web_routers/local_models.py # hermes_cli/web_server_config.py # hermes_cli/web_server_cron.py # plugins/memory/hindsight/__init__.py # plugins/memory/holographic/__init__.py # plugins/memory/honcho/cli.py # plugins/memory/mem0/__init__.py # plugins/platforms/google_chat/oauth.py # plugins/platforms/photon/adapter.py # scripts/ci/list_os_marked_tests.py # scripts/run_tests.sh # tests/agent/test_compression_stall_fallback.py # tests/agent/test_create_openai_client_ssl_verify.py # tests/gateway/test_google_chat_oauth_dependencies.py # tests/hermes_cli/conftest.py # tests/hermes_cli/test_cli_init.py # tests/hermes_cli/test_gateway_migrate_multiplex.py # tests/hermes_cli/test_psutil_android_extract.py # tests/hermes_cli/test_relaunch.py # tests/hermes_cli/test_update_check.py # tests/hermes_cli/test_update_handoff_desktop_rebuild.py # tests/hermes_cli/test_worktree_gc.py # tests/scripts/desktop_update/test_desktop_update_windows_python_handoff.py # tests/scripts/desktop_update/test_desktop_update_windows_retry_policy.py # tests/scripts/desktop_update/test_desktop_update_windows_timestamp.py # tests/scripts/install/test_install_autostash_conflict_recovery.py # tests/scripts/install/test_install_clone_throttle_fallback.py # tests/scripts/install/test_install_commit_pin_rollback.py # tests/scripts/install/test_install_diverged_update.py # tests/scripts/install/test_install_lockfile_churn.py # tests/scripts/install/test_install_macos_launcher.py # tests/scripts/install/test_install_no_initial_commit.py # tests/scripts/install/test_install_ps1_ascii_only.py # tests/scripts/install/test_install_ps1_browser_install.py # tests/scripts/install/test_install_ps1_managed_node_swap.py # tests/scripts/install/test_install_ps1_native_stderr_eap.py # tests/scripts/install/test_install_ps1_node_path_for_npm.py # tests/scripts/install/test_install_ps1_python_fallback_venv.py # tests/scripts/install/test_install_ps1_resolver_strictmode.py # tests/scripts/install/test_install_ps1_uv_install_fallback.py # tests/scripts/install/test_install_ps1_uv_powershell_host.py # tests/scripts/install/test_install_ps1_venv_process_tree.py # tests/scripts/install/test_install_ps1_venv_recreate_safety.py # tests/scripts/install/test_install_ps1_venv_rename_abort.py # tests/scripts/install/test_install_ps1_venv_transaction_boundary.py # tests/scripts/install/test_install_ps1_web_server_syntax_probe.py # tests/scripts/install/test_install_scripts_computer_use.py # tests/scripts/install/test_install_sh_acp_launcher.py # tests/scripts/install/test_install_sh_bootstrap_marker.py # tests/scripts/install/test_install_sh_browser_install.py # tests/scripts/install/test_install_sh_install_method_stamp.py # tests/scripts/install/test_install_sh_node_deps_failure.py # tests/scripts/install/test_install_sh_node_deps_workspaces.py # tests/scripts/install/test_install_sh_node_global_prefix.py # tests/scripts/install/test_install_sh_node_npm_check.py # tests/scripts/install/test_install_sh_node_prerelease.py # tests/scripts/install/test_install_sh_node_probe.py # tests/scripts/install/test_install_sh_node_tarball_without_xz.py # tests/scripts/install/test_install_sh_pythonpath_sanitization.py # tests/scripts/install/test_install_sh_reuse_supported_python.py # tests/scripts/install/test_install_sh_root_fhs_uv_python_path.py # tests/scripts/install/test_install_sh_setup_wizard_tty_probe.py # tests/scripts/install/test_install_sh_symlink_stomp.py # tests/scripts/install/test_install_sh_termux_network_prereqs.py # tests/scripts/install/test_install_sh_termux_python_bounds.py # tests/scripts/install/test_install_sh_uv_lock_config.py # tests/scripts/install/test_install_unmerged_index.py # tests/scripts/test_run_tests_parallel.py # tests/test_managed_runtime_resolution.py # tests/test_project_metadata.py # tests/tools/test_browser_use_cli.py # tests/tools/test_tts_pythonpath_fallback.py # tests/tui_gateway/test_hosted_room_driver_runtime.py # tests/tui_gateway/test_tui_gateway_server.py # tools/lazy_deps.py # tools/voice_mode.py # uv.lock # website/docs/developer-guide/macos-bundle-updates.md # website/docs/developer-guide/pm-audit-status.md # website/docs/developer-guide/shared-bundle-builds.md # website/docs/developer-guide/source-update-completion.md # website/docs/developer-guide/stable-releases.md |
||
|
|
a79ff58d65 |
feat(skills): ai-presenter-video optional skill (port of lanshu, 955★ MIT)
Ports cclank/lanshu-create-ai-presenter-video (MIT, 955 stars in 7 days) into optional-skills/creative/ai-presenter-video. Provider-neutral presenter-video production: locked narration as master clock, avatar generation with pilot-first cost discipline, lip-sync/identity QA, captions, deterministic ffmpeg finalization with loudness normalization and contact-sheet verification. Hermes adaptations in the hub SKILL.md: SKILL_DIR resolution (upstream hardcoded ~/.codex/skills), capability mapping to text_to_speech / FAL video families / vision_analyze / hyperframes, consent-flag JSON paths (input.* vs root), preflight error-vs-remote-blocker semantics. References kept substantively verbatim (all-English upstream). Scripts unmodified. LICENSE carried. Validated hands-on: init_job -> preflight gating (blocked until manual review booleans + input.remote_upload_approved) -> finalize_delivery on a synthetic 1080x1920 render (master+share decode-verified, delivery report, 9-frame contact sheet). Cold-subagent live test: SHIP; 3 friction fixes folded in (resolution guard, boolean-flip example, preflight-writes-job note). |
||
|
|
56cc2bd814 |
feat(skills): scrollcraft — premium scroll-driven landing pages (port of nateherkai/scroll-craft, 1.2k★ MIT)
Optional skill: scroll-as-timeline landing pages on a deterministic CSS/JS engine, with interview → page grammar → signature move workflow and screenshot-based scroll verification. Engine and scripts vendored verbatim; asset generation re-anchored on image_generate with the upstream kie.ai flow kept as an optional path. |
||
|
|
77123c0ef3 | Merge remote-tracking branch 'origin/main' into hermes/hermes-b802e898 | ||
|
|
0b40f5a790 |
docs: fold the root docs/ tree into the Docusaurus site and delete it
docs/ was not the documentation site; it was a grab bag of long-form design notes, wire contracts and observability guides that landed with feature PRs because their authors needed somewhere to put them. Root AGENTS.md already says long-form dev docs live in website/docs/developer-guide/; this moves the 14 living documents there (or to the matching user-guide section) so they are published, searchable and linked from the sidebar instead of being found by grep only. Developer guide: micro-compaction, gateway-session-lifecycle (was session-lifecycle), state-db-recovery, multiplexing-gateway, chronos-managed-cron-contract, relay-connector-contract, observer-hooks (was observability/README), gateway-monitoring (observability/monitoring), relay-shared-metrics, middleware, streaming-tts, billing-lifecycle. User guide: egress/network-isolation (was security/network-egress- isolation), features/kanban-multi-gateway (was kanban/multi-gateway). Each page got title/description frontmatter and a sidebar entry; repo- relative links became site links or GitHub blob URLs; two MDX brace hazards escaped. Every in-tree pointer (module docstrings, config comments, the relay conformance test's Path, the monitoring-doc test, gateway-internals, cron-internals, kanban docs, .dockerignore, AGENTS.md) now names the new location. `docusaurus build` passes with no unresolved links on the moved pages. |
||
|
|
47c029927f |
feat(skills): add dream-loop — concept-art visual fidelity build loop (port of achimala/dream-loop, MIT)
Port of https://github.com/achimala/dream-loop (MIT, 400+ stars in 48h). An autonomous loop for building visually impressive 3D scenes/games: generate photorealistic concept art, build (three.js/WebGL/Blender), screenshot the live build, judge screenshot-vs-concept on a 5-tier score ladder, iterate to convergence with explicit exit criteria. Prose-only port rebound to Hermes-native tools: image_generate for concept art, vision_analyze for judging (side-by-side composite workaround documented), browser_exec capture_screenshot for live builds, delegate_task for parallel asset work. Upstream ladder, failure modes, time-budget and exit rules preserved. optional-skills/ placement. |
||
|
|
f41b2c615d |
feat(skills): system-atlas — explorable isometric architecture atlases (port of inkboard/system-atlas, MIT)
Ports the system-atlas agent skill: one data.mjs file renders both an interactive isometric HTML map (progressive-disclosure chapters, moving data packets, question tracking by Q-ID) and a generated text twin (SYSTEM.md) for the repo. Why: architecture discussions that outgrow a single diagram — the skill encodes hard-earned rules (max 3 structures per chapter, shapes+labels, docs-policy ask before committing). Upstream 410 stars since Aug 20, VoltAgent-listed; complements architecture-diagram (static SVG) with an explorable, stateful artifact. - optional-skills/creative/system-atlas/: SKILL.md (89 lines), references/ (design language, process lessons), assets/ (build.mjs, template.html, data.example.mjs) vendored verbatim; LICENSE.txt (MIT, Harshyt Goel) - Live smoke: node --check both .mjs OK; node build.mjs produced atlas.html (41.5 KB) + SYSTEM.md from the example data, zero deps - docs: own catalog row + generated page + sidebar entry only |
||
|
|
b35c0284a1 |
feat(skills): add mono-color — one/two-ink editorial print images (port of yanliudesign/mono-color-skill, MIT)
Port of https://github.com/yanliudesign/mono-color-skill (MIT, 2.9k stars in 3 weeks). Generates original one-ink or controlled two-ink editorial print images (risograph/duotone/monochrome poster aesthetic) driven by machine-readable design-system catalogs: substrate/ink palettes, composition geometry, typography roles, rhythm, controlled imperfections — all vendored verbatim as the source of truth. Upstream 34 KB SKILL.md restructured into a hub (143-line core + three references). Image generation rebound to image_generate; hardcoded '~/Desktop/Claude skills' path replaced with a neutral output dir. Upstream examples/ are all-rights-reserved (ASSET-LICENSE.md) and are NOT vendored — MIT text + catalogs only, with a NOTICE. optional-skills/ placement. |
||
|
|
d7a56474fc |
feat(skills): pr-lens — animated architecture/data-flow diagrams for PRs (port of coldteadotai/pr-lens, 1.1k-star MIT)
Ports the pr-lens agent skill: represent a diff or subsystem as one graph.json document and render it as animated SVG diagrams via the MIT npx CLI (@coldtea/pr-lens-cli), with optional opt-in publishing to a shareable canvas link. Why: PR review and architecture explanation keep producing hand-drawn Mermaid; this gives validated, animated, drill-down diagrams with a deterministic document format. Upstream created Aug 20, 1.1k stars in 3 weeks, GitHub App + Action + CLI + skill. - optional-skills/software-development/pr-lens/: SKILL.md (145 lines), references/ (config, graph document format, valid example) vendored near-verbatim, LICENSE.txt (MIT, Coldtea AI) - gh --attach caveat handled: installed gh 2.97 lacks the flag; skill documents honest fallbacks (gist, canvas link, local path) - Live smoke: validate + render of the vendored example graph passed (4 SVGs + manifest produced) - docs: own catalog row + generated page + sidebar entry only |
||
|
|
b41c8ddfc4 |
feat: Bot Screen — per-bot Xfce desktop streamed into Hermes Desktop with human take-over
A bot running on a headless Linux gateway now gets its own desktop (TigerVNC Xvnc + a minimal Xfce session, one per profile) that Hermes Desktop streams live. The user can watch the bot work, take over to type a login / 2FA code / CAPTCHA, and hand control back; the bot refuses every computer_use action (screenshots included) while a human holds the screen, then resumes with the session cookies the human just created. Why this shape: - The screen lives on the machine Hermes runs on, not in a vendor cloud browser, so it works for any app the bot drives and keeps the session on the user's host. - Xfce components are launched individually (xfwm4, xfce4-panel, xfdesktop, xfsettingsd) under a private dbus session rather than xfce4-session/the metapackage: no screensaver, power manager or polkit agent to lock or prompt a headless desktop. - Transport is raw RFB over a WebSocket beside /api/ws, authenticated with a one-shot ticket minted through the already-authenticated RPC channel; noVNC runs in the Electron renderer. The bridge parses the RFB client stream and drops keyboard/pointer/clipboard (incl. QEMU Extended KeyEvent, which noVNC switches to once Xvnc advertises it) from any viewer that does not hold the lease, so viewOnly is enforced server-side, not by the client. - One lease per profile (agent | human viewer) is the single truth for the RFB bridge, the computer_use tool and the Desktop UI; taking control evicts other viewers' input with close code 4000 control-taken. - Auto-start happens only at the computer_use tool boundary (headless host, packages present, bot_desktop.auto_start=true); env builders stay pure so status probes and tests never spawn X servers. tests/tools/conftest.py pins the binaries to "missing" for the same reason the browser-use fixture does. Surfaces: Desktop (Bots → right-click → Open Screen; Take over / Hand back), CLI (`hermes computer-use screen status|start|stop|install-deps`), tool (`computer_use` actions request_handoff / wait_for_human), gateway RPCs (display.status/start/stop/observe/lease.acquire/lease.release + display.lease event), docs page user-guide/features/bot-screen. |
||
|
|
38dfe6df50 | merge: current main into consolidated PM and onboarding | ||
|
|
f364c19775 |
feat(plugins): touchdesigner ships as a catalog plugin (MCP server + skill), optional skill retired
The twozero TouchDesigner integration now lives in one installable unit: plugin-catalog/touchdesigner.yaml points at NousResearch/hermes-plugin-touchdesigner (portable Agent Plugins v1: mcp.json registers the twozero Streamable HTTP hub, skills/ carries touchdesigner-mcp). `hermes plugins install touchdesigner` + `hermes plugins enable td` replaces the optional skill whose setup.sh hand-wrote an mcp_servers block. The manifest name is `td` because Hermes names portable MCP tools mcp__agent_plugin_<name>_<hash>__<server>__<tool>; twozero's longest tool under a `touchdesigner` namespace is 71 chars, past the 64-char provider function-name cap. optional-skills/creative/touchdesigner-mcp and its generated docs (bundled, optional, zh-Hans) are removed; catalog tables, sidebar and kanban-video-orchestrator references are updated to point at the plugin. Supersedes #68607 (MCP-catalog-only approach). |
||
|
|
b7b35a84b7 | docs: remove the Nous guest free-tier guide (#108991) | ||
|
|
bf867d3c74 |
chore(skills): ship dynamic-workflow as an optional skill
Install with hermes skills install official/autonomous-ai-agents/dynamic-workflow. Orchestration-campaign guidance is niche enough not to sit in every default prompt index. |
||
|
|
fb4ed7b284 |
docs(skills): dynamic-workflow v2 — background-first delegation, campaign lessons from #102117
Main moved under take-1: top-level delegate_task is background-forced (results
re-enter as messages; synthesizing on the same turn reads files that do not
exist yet), per-task `toolsets` is gone (children inherit the parent's set),
DELEGATE_BLOCKED_TOOLS is {delegate_task, clarify, memory, send_message,
cronjob_manage} (execute_code is NOT stripped), and the 457-char description
was truncated by the 60-char routing budget. All four bbopen review items fixed.
Adds the campaign shape learned running the 1,863-session / 19-hour
whole-codebase simplification fan-out (#102117): shared brief + exclusive
file ownership, commit-per-step as the only handoff, fleet ceiling before the
OAuth refresh stampede, per-round integration with a frozen base and a full
suite on the combined tree, `rev-list --count` per branch before declaring a
round done (168 late-slice commits were once left behind), one serialized
test runner, forward-port last, live QA as its own wave, refuting the parent's
own heuristics with the same attempt/refuter mechanic, HANDOFF.md on restart.
Frontmatter now meets the hardline standard (platforms, ≤60-char description,
modern section order); `/tmp` replaced by the terminal temp dir so the skill is
correct on Termux and Windows. Catalog + sidebar + generated page added.
|
||
|
|
cc01ae9d44 |
merge: connector UI e2e v2 into bundled onboarding (rebuilt)
# Conflicts: # apps/desktop/electron/main.ts # apps/desktop/src/app/settings/local-models-settings.test.tsx # hermes_wisdom/agent_led/share_flow.py # plugins/memory/hindsight/__init__.py # scripts/lib/wisdom-demo-env.sh # scripts/release.py # tests/skills/test_collective_wisdom_install_skill.py # tools/checkpoint_manager.py |
||
|
|
0dcadf6f41 |
revert: remove Collective Wisdom V1 (#94266)
Reverts the in-tree org skill-marketplace: hermes_wisdom package, three model tools, CLI/gateway/desktop/dashboard/Telegram/Slack surfaces. Later non-Wisdom work on shared files (guest onboarding i18n, dashboard startup schema, Slack adapter, tui_gateway) is kept; Wisdom-only call sites and config were stripped from those files. |
||
|
|
b3bfc3afe5 |
Merge remote-tracking branch 'origin/main' into ethie/pm-clean
# Conflicts: # apps/desktop/electron/backend-connection-state.test.ts # apps/desktop/electron/backend-connection-state.ts # apps/desktop/electron/backend-exit.test.ts # apps/desktop/electron/main.ts # apps/desktop/electron/pool-spawn-coordinator.test.ts # apps/desktop/electron/pool-stop.ts # apps/desktop/electron/preload.ts # apps/desktop/src/app/settings/about-settings.tsx # apps/desktop/src/app/updates-overlay.tsx # apps/desktop/src/global.d.ts # apps/desktop/src/store/notifications.ts # apps/desktop/src/store/updates.ts # gateway/config_loader.py # hermes_cli/banner.py # plugins/platforms/dingtalk/adapter.py # tests/hermes_cli/test_plugins_cmd.py # tests/test_live_system_guard.py # tui_gateway/server.py # website/docs/user-guide/desktop.md |
||
|
|
a6ee31f55a |
feat(wisdom): add Hermes Collective Wisdom Agent V1 (#94266)
* feat(wisdom): add trusted publish and install foundation
* feat(wisdom): add private contribution loop
* feat(wisdom): add managed consumption workflows
* fix(wisdom): close cross-repository safety gaps
* fix(wisdom): align local package and lifecycle policy
* fix(wisdom): require explicit profile setup
* docs(wisdom): repin reconciled gateway head
* fix(wisdom): fence content downloads and approval receipts
* docs(wisdom): record generation-fenced downloads
* docs(wisdom): record unified delivery PR
* fix(ci): stop passing invalid classifier inputs
* docs(wisdom): remove internal requirements ledger
* feat(wisdom): localize dashboard and desktop copy
* feat(wisdom): complete local contribution and consumption UX
* style(wisdom): satisfy desktop lint
* chore(wisdom): refresh requirements pin
* test(dashboard): allow formatted profile copy
* test(wisdom): stabilize desktop interaction coverage
* fix(wisdom): surface dashboard action failures
* fix(wisdom): add repeatable Portal demo login
* feat(wisdom): add actionable skill notifications
* feat(wisdom): add notification install and update actions
* fix(wisdom): make Telegram skill alerts actionable
* fix(wisdom): always refresh demo Agent login
* feat(wisdom): embed Telegram notification actions
* fix(wisdom): preserve Telegram notifications after actions
* fix(wisdom): keep Telegram notification cards readable
* feat(wisdom): add Telegram candidate approval flow
* feat(wisdom): explain Telegram qualification reasons
* fix(wisdom): reconcile cross-surface candidate actions
* feat(telegram): add Collective Wisdom management command
* chore(wisdom): refresh Gateway contract pin
* chore(wisdom): advance Gateway contract pin
* feat(wisdom): align command UX across clients
* feat(slack): add Collective Wisdom management parity
* feat(wisdom): add security and professionalism reviews
* feat(wisdom): add first-time qualification guidance
* feat(wisdom): simplify qualification sharing choices
* feat(skills): add optional editorial metadata
* feat(wisdom): enrich legacy skill presentation
* fix(wisdom): harden review and update boundaries
* fix(wisdom): emit canonical review timestamps
* fix(wisdom): align with merged gateway and main
* wisdom: add agent-led sharing core (policy, evidence, schemas, templates, delivery, weekly job, share/install flows)
- hermes_wisdom/agent_led/: policy resolution (server > local > defaults),
7-day evidence builder that excludes bundled/hub/managed skills and
dismissed/handled/recently-suggested content hashes, strict pydantic
schemas for agent output with repair-or-reject, fixed copy templates
(Share / Teammate / Published / Update / Mute), idempotent retried
delivery ledger with stale-action resolution, weekly review job,
resumable Share and Install flows.
- prompts/: candidate review, recipient recommendation, share packaging.
- tests/wisdom/test_agent_led.py: 30 tests.
* wisdom: agent-led renderers and button action dispatcher
- render.py: Telegram HTML, Slack blocks, Desktop payload; editorial name
is the emphasized line, product label stays separate.
- actions.py: resolve opaque wa:<action>:<dedup> targets via the delivery
ledger; Not now -> dismissal, Mute -> fixed options, Share -> resumable
packaging flow, Install/Update -> plan command. Never publishes/installs.
* wisdom: CLI verbs, agent_led config default, conversational catalog skill
- hermes wisdom browse/review-week/act/share/dismiss/mute (all --json).
- wisdom.agent_led config block, default enabled.
- SKILL.md rewritten so natural-language catalog questions map to the CLI
verbs, share/install flows and fixed notification templates.
* wisdom: wire agent-led weekly review into gateway tick and Telegram buttons
- gateway housekeeping tick calls maybe_run_weekly_review with a home
channel sender when a Telegram adapter is available.
- Telegram: wa: callbacks resolved through the ledger (stale-safe), mute
duration keyboard, send_wisdom_agent_recommendation rich card + fallback.
* fix(wisdom): integrate local mediation and harden model and setup boundaries
* fix(wisdom): honor authoritative recommendation policy and defer on failure
* fix(wisdom): synchronize opaque suppression and recheck delivery preferences
* feat(wisdom): route weekly selection through the session-owned assessment queue
* fix(wisdom): prepare and submit the reviewed generated share package
* feat(wisdom): separate native Share preparation from publication consent
* feat(wisdom): sync native mute choices through a leased preference outbox
* feat(wisdom): bind native mute controls to durable preference choices
* feat(wisdom): add scoped desktop and dashboard notification settings
* fix(wisdom): revalidate feed recommendations before assessment and delivery
* fix(wisdom): persist validated delivery receipts before completing notices
* feat(wisdom): add private notification claim and receipt client
* Persist Wisdom send reservations and recover delivery acknowledgements
* Route legacy Wisdom controls through current native review
* Add typed private Wisdom operation outcome client
* fix(wisdom): make agent-led advice usable in the local demo
* fix(wisdom): keep requested consent outside proactive limits
* fix(wisdom): distinguish unavailable assessments and preserve digest text
* fix(wisdom): assess ongoing usefulness beyond the current task
* fix(wisdom): restore immediate qualification sharing controls
* fix(wisdom): separate qualification review from installation advice
* fix(wisdom): collapse review checklists and simplify sharing copy
* fix(wisdom): show compact sharing progress and publication receipts
* fix(wisdom): require credential prefixes rather than matching skill names
* fix(wisdom): finish package checks before presenting sharing consent
* fix(wisdom): scan local skills before qualification cards
* fix(wisdom): update moderation results on existing sharing cards
* fix(wisdom): keep sharing review accessible from receipt cards
* fix(wisdom): align mediated review cards and collapsible checks
* fix(wisdom): clarify clean security summary wording
* fix(wisdom): normalize consent plans and add explicit recheck
* fix(wisdom): keep install and update receipts concise
* fix(wisdom): collapse assessments and deduplicate operation cards
* fix(wisdom): restore private Portal review from native cards
* fix(wisdom): sync Portal publication to original consent card
* fix(wisdom): show local skill version on sharing cards
* fix(wisdom): skip agent recommendations for self-published versions
* fix(wisdom): simplify candidate notices and local-edit recovery copy
* feat(wisdom): submit locally reviewed packages with one confirmation
* feat(wisdom): expose safe receipt and outcome sync recovery
* wisdom: onboarding notice says detect and share, names the user's own skill
Copy review from the product owner on the first and returning
qualification notices (fixed delivery mode):
- the feature blurb now says the org enabled detection *and sharing*
- both notices say the detected skill is one the user created
- both close with an exclamation mark
Applied identically to hermes_wisdom.notice, the desktop and web i18n
strings, and the tests that assert the sentences.
* wisdom: one opener, no approval line, ask to share after the skill is shown
Product owner review of the candidate card.
- The Hermes written card now opens with the same sentence as the fixed card
("Your organisation has enabled Collective Wisdom, a feature designed to
automatically detect and share useful skills across all team members.")
instead of its own blurb, so there is one first time message.
- "Nothing is shared without your approval." removed from Telegram, Slack
and Desktop. The buttons already make the permission explicit.
- "Would you like to share?" no longer appears before the skill is named.
It is now the last line, after the skill name, description, why suggested
and the checks, and reads "Would you like to share it?" (matching the
agent led template wording).
Tests updated for the new order; proposalNotice removed from all desktop locales.
* wisdom: American spelling, organization
Product owner decision: user facing copy uses American spelling.
Changes "Your organisation" to "Your organization" in the chat notice,
the Hermes written card opener, the desktop and web strings, and the
tests that assert them. Identifiers such as nas_organisation:* and the
German and French locales are untouched.
* wisdom: candidate card copy round 4 (owner review)
Apply the product owner's round 4 copy decisions to the Hermes Collective
Wisdom candidate card on Telegram, Slack, Desktop and the shared views:
1. Hermes-written cards are titled "Hermes Collective Wisdom" instead of
the bare "Collective Wisdom".
2. The "Reusable skill ready to review" line is gone from the candidate
card (Telegram rich card and plain fallback, legacy agent-led share
template).
3. The skill name and description are labelled: "Skill name: <name>" and
"What it does: <description>" (Telegram, Slack, Desktop).
4. "Why suggested:" is now "Why others might benefit:".
5. A passing professionalism review reads "Safe to share at work ✓ (no
inappropriate content found)" with no per-check bullets and no "Pass";
a failed review reads "Needs a look before sharing at work (possible
inappropriate content)" and lists only the checks that flagged
something. Pending/unavailable wording is unchanged.
6. Telegram button toasts: "Will ask later...", "Preparing more
details...", "Sharing...".
7. Qualification reasons: "You used this skill consistently across many
days." and "You've really refined this skill."
8. prompts/wisdom_candidate_review.md asks for a compelling
editorial_name, a simple one_line_description and a compelling
why_coworkers_benefit under 300 characters; "Be concise and
convincing." becomes "Be concise and compelling: the goal is that the
user wants to share it."
Tests updated for the new strings; review_text() gains direct coverage.
* wisdom: re-apply owner copy after rebase
- Native share cards (advice_view/interaction_view): drop the approval line, ask "Would you like to share it?" as the last line after the checks
- Hermes-written completion card titled "Hermes Collective Wisdom"
- Qualification reasons use the owner wording (consistently across many days / really refined)
- American spelling (organization) in remaining English copy
- Desktop test asserts the current Share button; web test matches the returning notice
* fix(wisdom): pin reconciled Gateway and verify Unicode hash vectors
Pin Gateway 60cd2d6b613ae3cd4a6e65155d1142006d907e78 and byte-identical producer artifacts. Verify every content-order case and package-manifest binding. Validation: 186 focused Python tests, Ruff and contract verifier.
* fix(wisdom): reconcile optional SDK tests and frontend lint
* fix(wisdom): default to agent-written notification summaries
* fix(wisdom): restore deferred install review and browse controls
* feat(wisdom): inspect installed setup with exact package provenance
* feat(wisdom): run native-approved installed setup steps with durable evidence
* fix(wisdom): recover interrupted setup with explicit native consent
* feat(wisdom): hand native installs into guided setup review
* fix(wisdom): continue requested setup with fixed notification copy
* fix(wisdom): preserve setup while waiting for a session model
* fix(wisdom): expose canonical setup review controls on desktop
* fix(wisdom): resume setup after recorded automatic updates
* fix(wisdom): make missing setup prerequisites recheckable
* chore(wisdom): align Agent with verified Gateway contract
* fix(wisdom): stop guessing team slugs in portal links
* fix(wisdom): retire pending advice on account sign-out
* fix(wisdom): cancel advice after terminal account revocation
* fix(wisdom): fence feed responses across account sign-out
* fix(wisdom): checkpoint signed-out feed before reactivation
* fix(wisdom): link proactive advice to scoped notification settings
* fix(wisdom): coalesce queued publication recommendations by version
* fix(wisdom): keep package review navigation local and deferable
* fix(wisdom): reflect installed state in discovery controls
* fix(wisdom): show exact checks before command confirmation
* chore(wisdom): pin bounded analytics privacy contract
* chore(wisdom): pin retired legacy notification contract
* feat(wisdom): review publisher usage with exact sharing copy
* fix(wisdom): align discovery and review check summaries
* fix(wisdom): show expired consent before confirmation
* fix(wisdom): require fresh review for legacy install controls
* fix(wisdom): preserve review expiry across check toggles
* fix(wisdom): retain update policy in native install reviews
* fix(wisdom): surface failed native card edits
* fix(wisdom): persist local command approval reviews
* fix(wisdom): use saved approvals for messaging commands
* test(wisdom): provide scan result in setup handoff fixture
* test(wisdom): exercise Telegram approvals with saved review state
* fix(wisdom): retain suppression policy for offline deferral
* fix(wisdom): reconsider candidates after deferred suppression expires
* fix(wisdom): bind review checks and report verified readiness separately
* fix(wisdom): persist accepted publication intent and recover exact outcomes
* fix(sync): pin UTF-8 tree ordering across writers
* chore(wisdom): pin organisation-scoped Gateway authorization
* fix(wisdom): restrict consent delivery to user-facing sessions
* chore(wisdom): refresh reviewed Gateway contract pin
* fix(wisdom): preserve kept tools in Blank Slate exclusions
* test(auth): reset anonymous fixture with a profile-scoped cache
* fix(wisdom): gate local surfaces and work on current profile entitlement
* fix(wisdom): invalidate quiet tool cache on entitlement changes
* test(wisdom): authorize local consent gateway fixtures
* fix(wisdom): keep entitlement decoding free of native crypto imports
* test(wisdom): provide local entitlement to demo CLI subprocess
* ci: leave upstream workflow unchanged in Wisdom PR
* fix(wisdom): ship package and contracts in Nix wheels
---------
Co-authored-by: hbizi <36184542+hbizi@users.noreply.github.com>
|
||
|
|
a2db110ccc |
feat(auth): Nous free tier: free inference and connectors out of the box, one command to sign in (#105258)
* feat(auth): Nous free tier core: anonymous identity minted on first use, welcome inference, shared-store scoping A fresh install with no provider sets up a free Nous identity (anonymous auth method of the nous provider) instead of forcing the setup wizard. The identity is persisted through the same path a real login uses, so the resolver ladder is unchanged. Two seams differ: token acquisition re-exchanges the anon credential (no refresh token), and routing pins the welcome host's single model nous/welcome. One identity per shared store; nous.guest: false turns the free tier off. * test(auth): free tier core contracts: lifecycle, resolver precedence, exchange seam, model pin * docs(user-guide): free tier and signing in New page explaining what a fresh install gets before any key or sign-in (free inference on nous/welcome plus connectors), how the free tier coexists with a user's own API key, how to sign in with hermes auth upgrade and keep connectors, how to turn the free tier off with nous.guest, what hermes logout does in each state, a troubleshooting table, and a plain privacy note. Wired into the Using Hermes sidebar. * fix(auth): logout leaves the free tier alone and clears the shared store for a real Nous account Logging out of the free tier is a no-op: it is not a login, so nothing is cleared and the user is told they were never signed in. Logging out of a real Nous account now also clears the cross-profile store, so a profile logout is not silently re-adopted on the next boot. * fix(model): switching off the free tier points at signing in, never hops providers * Name the free tier in the gateway startup notice and tell explicit-provider installs about it once * Render the Nous free tier as free tier on auth status, auth list, hermes status and portal info, short-circuit billing copy for it, and skip the keepalive when there is no refresh token * fix(auth): free tier is set up where nothing is configured: resolver last rung and first-run check Both the provider resolver's terminal rung and the CLI first-run check now try to set up the free tier before declaring nothing configured. On a fresh install the first command lands in chat on nous/welcome; a failed setup still falls through to the existing guidance. * Add hermes auth upgrade: sign the free tier into a Nous account while keeping its connectors The device-code flow runs as usual, with a promotion intent registered on the portal between the code request and the token poll so the account that approves the code inherits the free tier's connectors. The promotion status decides the outcome: only a completed one is followed by the token grant, which is persisted over the free-tier singleton and the shared store. Declined, superseded, retired and busy outcomes each print their own plain copy, and a retired identity is cleared so the next use sets up a fresh one. User-facing text never names the free tier's internals. * Show the Nous free tier as one picker row with nous/welcome and hide it when nous.guest is off * fix(auth): upgrade opens the consent page for this sign-in; one mint attempt per process; forced free tier wins the first-run check The browser leg of hermes auth upgrade now prints and opens the promotion claim URL with the claim code, not the generic device page. A failed mint is attempted once per process so several bootstrap sites cannot hit a closed gate or a 429 twice; a retired credential resets that so re-minting still happens. HERMES_FORCE_GUEST is honoured ahead of the first-run provider check. * fix(auth): pin the welcome model on the selected route, not on profile state; background setup retries after a failure A credential-pool entry can select a paid Nous key while the profile singleton is still the free tier. The model pin now keys on the resolved endpoint (welcome host) in agent init and /model, and the pin in model normalization is removed since it had no route to look at. A failed background identity setup releases its latch so a later attempt in the same process can try again. * fix(auth): decide the Nous model together with the route on every credential-pool swap The credential pool can move a Nous agent between the welcome host and the portal host after init. One helper, pin_model_for_route, now runs at init and inside every pool swap, so the welcome host always carries nous/welcome and a paid endpoint always keeps the caller's model. * fix(auth): apply the route model policy on every wire mode during a pool swap; release the setup latch if the thread cannot start * fix(auth): free-tier lifecycle takes profile then shared lock, reconciles with the shared store, persists the mint before exchanging, and clears only the identity that died The shared store is the identity of record for a Hermes root: a profile holding a stale free-tier identity adopts a sibling's newer sign-in instead of keeping the guest, and never overwrites the shared account. Locks are taken in the documented order (profile, then shared). A minted credential is stored as soon as create succeeds, so a rate-limited or timed-out exchange does not lose it and trigger a second mint. Retiring a dead credential removes only that credential from both stores. Guest exchange uses the resolver's canonical portal URL. * fix(auth): a credential rotation never rewrites the conversation model; connectors honour the off switch and replace a retired free-tier credential The welcome host serves one model, so a rotation onto it is refused for any conversation on another model instead of silently switching that conversation to nous/welcome (the model pin applies only when a route is first chosen). The connector token path now treats the free tier as absent when nous.guest is false, including cached tokens, and shares the one dead-credential rule with inference: a retired identity is replaced once rather than returning its stale token. * fix(auth): plain login never imports the free tier as OAuth credentials; the gateway startup line reads persisted state only A free-tier identity in the shared store is not an OAuth credential to offer for import; a real sign-in replaces it. The gateway's startup notice now answers provider precedence from persisted state (no token refresh at boot), so an expired free-tier token cannot stall the online message. |
||
|
|
cde0ad0edd |
feat: agent signs into sites from an encrypted local vault (CLI, browser fill, Desktop Settings)
Consolidated re-apply of #96988 onto current main. Ported from Merit-Systems/OpenInstinct (MIT) opaque-handle autofill design: the model sees vault handles + login metadata, the password is resolved and filled server-side over the supervised CDP socket, and filled values are scrubbed from every browser tool result by an unconditional redaction registry. Rebase adaptations to the Sep-2026 facade/sibling layout: - toolsets: one _HERMES_CORE_TOOLS entry (the browser toolset derives from it) - hermes_cli/main.py: vault parser registered via the subcommand owner table - file_safety: vault/ joins the _READ_DENIED_DIRS credential-dir table - redact: registry scrub runs before the redact_secrets early-return - browser_vault_tool: _run_browser_command now lives in browser_tool_session |
||
|
|
2feb546828 |
feat(skills): archify joins the optional-skills catalog as an upstream-maintained stub
tt-a1i/archify (MIT, 57k stars) turns a typed JSON spec into validated, self-contained interactive HTML diagrams (architecture / workflow / sequence / dataflow / lifecycle) with a 9-check validate/deliver receipt, Mermaid import and PNG/SVG/WebM export. The upstream repo already ships a complete skill directory (archify/), so this follows the impeccable pattern: a catalog stub whose metadata.hermes.upstream pointer makes `hermes skills install official/creative/archify` pull the live tree through OptionalSkillSource._fetch_from_upstream. Nothing executable is vendored and the copy can never go stale. Docs: generated page, one catalog row, one sidebar line. Credit: tt-a1i (upstream author). Supersedes the vendored-references port in #106442. |
||
|
|
e4cc7f09d9 |
merge: integrate upstream catalog with PM publication
Keep upstream's reviewed catalog as the only plugin name index. Catalog pins and custom update sources share staged PM validation. Publish code and dependencies with recovery after process death. Reject a concurrent enablement change before publishing disabled code. Use the manifest loader's supported version in the installer. Keep probe cooldowns for timeouts, not TLS failures that a CA change fixes. Preserve the backup, uninstall, browser and memory-provider repairs. Verified with the canonical runner on native Windows ARM64, real Git repositories, local TLS endpoints and UV dependency generations. Desktop catalog tests and both TypeScript checks pass. The full suite and native release builds were not run. No remote push. |
||
|
|
d47adec28f |
Merge origin/main into feat/plugin-catalog
Python plugin CLI/loader/web/tui files taken from main wholesale; the catalog layer is re-ported onto main's decomposed shapes in the following commits. plugin_index.py removed (catalog is the sole discovery system). |
||
|
|
7d2b3b767d |
merge: integrate upstream/main into ethie/pm-clean
Merge upstream
|