templates/plugin.js
templates/plugin.jsBrowse 22 files
857 tokens
3,141 bytes
Token encoding: o200k_base
Snapshot 24fd22b
← Back to SKILL.md
1/**2 * Hermes desktop plugin template. Save as:3 * <hermes home>/desktop-plugins/<id>/plugin.js (folder name == id)4 * where <hermes home> is ~/.hermes by default, or ~/.hermes/profiles/<name>5 * when running a named profile (`hermes -p <name>`). Run `hermes doctor` (or6 * check the app's Settings → Plugins folder path) if unsure which is active.7 * Then run "Reload desktop plugins" from ⌘K in the desktop app.8 *9 * Plain ESM, loaded uncompiled — UI is jsx() calls, not JSX syntax.10 * Only these imports resolve: @hermes/plugin-sdk, react, react/jsx-runtime.11 */12 13import { cn, haptic, host, Tip, usePluginI18n, useValue } from '@hermes/plugin-sdk'14import { jsx, jsxs } from 'react/jsx-runtime'15 16// Ship your OWN strings (never edit core en.ts). `usePluginI18n` resolves them17// against the app's active locale, falling back to `en`, then the raw key.18const ID = 'my-plugin'19 20function MyPane() {21 const t = usePluginI18n(ID)22 const gateway = useValue(host.state.gateway)23 24 return jsxs('div', {25 className: 'flex h-full flex-col gap-2 p-3 text-sm',26 children: [27 jsx('div', { className: 'font-medium', children: t('paneTitle') }),28 jsx('div', {29 className: 'text-(--ui-text-tertiary)',30 children: t('gateway', gateway)31 })32 ]33 })34}35 36function MyChip() {37 const t = usePluginI18n(ID)38 39 return jsx(Tip, {40 label: t('chipTip'),41 children: jsx('button', {42 className: cn(43 'inline-flex h-full items-center gap-1 px-1.5 text-[0.6875rem] transition-colors',44 'text-(--ui-text-tertiary) hover:bg-(--chrome-action-hover) hover:text-foreground'45 ),46 type: 'button',47 onClick: () => {48 haptic('tap')49 host.notify({ kind: 'info', message: t('hello') })50 },51 children: 'my-plugin'52 })53 })54}55 56export default {57 id: ID, // must match the folder name58 name: 'My Plugin',59 register(ctx) {60 // Register locale bundles — scoped to this plugin, torn down on reload.61 // Values are literals or interpolators (`arg => `…${arg}…``).62 ctx.i18n.register({63 en: {64 paneTitle: 'My Plugin Pane',65 gateway: state => `gateway: ${state}`,66 chipTip: 'My plugin — click me',67 hello: 'Hello from my plugin!'68 },69 ja: {70 paneTitle: 'マイプラグイン',71 gateway: state => `ゲートウェイ: ${state}`,72 chipTip: 'マイプラグイン — クリック',73 hello: 'マイプラグインからこんにちは!'74 }75 })76 77 // A layout pane — auto-placed by the placement hint; user can drag it.78 // To land on a specific edge instead of stacking, add a dock gesture,79 // e.g. below the conversation:80 // data: { placement: 'bottom', dock: { pane: 'workspace', pos: 'bottom' }, height: '200px' }81 ctx.register({82 id: 'pane',83 area: 'panes',84 title: 'my plugin',85 data: { placement: 'right', width: '237px' },86 render: () => jsx(MyPane, {})87 })88 89 // A statusbar chip.90 ctx.register({91 id: 'chip',92 area: 'statusBar.right',93 order: 130,94 render: () => jsx(MyChip, {})95 })96 }97}98